src/index.js
async function generateCriticalCssWrapped (
  options,
  { forceTryRestartBrowser } = {}
) {
  const width = parseInt(options.width || DEFAULT_VIEWPORT_WIDTH, 10)
  const height = parseInt(options.height || DEFAULT_VIEWPORT_HEIGHT, 10)
  const timeoutWait = options.timeout || DEFAULT_TIMEOUT
  // Merge properties with default ones
  const propertiesToRemove =
    options.propertiesToRemove || DEFAULT_PROPERTIES_TO_REMOVE

  // always forceInclude '*', 'html', and 'body' selectors;
  // yields slight performance improvement
  const forceInclude = prepareForceIncludeForSerialization(
    ['*', '*:before', '*:after', 'html', 'body'].concat(
      options.forceInclude || []
    )
  )

  // promise so we can handle errors and reject,
  // instead of throwing what would otherwise be uncaught errors in node process
  return new Promise(async (resolve, reject) => {
    debuglog('call generateCriticalCssWrapped')
    let formattedCss
    let pagePromise
    try {
      pagePromise = getOpenBrowserPage()

      formattedCss = await generateCriticalCss({
        pagePromise,
        url: options.url,
        cssString: options.cssString,
        width,
        height,
        forceInclude,
        strict: options.strict,
        userAgent: options.userAgent || DEFAULT_USER_AGENT,
        renderWaitTime: options.renderWaitTime || DEFAULT_RENDER_WAIT_TIMEOUT,
        timeout: timeoutWait,
        pageLoadSkipTimeout: options.pageLoadSkipTimeout,
        blockJSRequests:
          typeof options.blockJSRequests !== 'undefined'
            ? options.blockJSRequests
            : DEFAULT_BLOCK_JS_REQUESTS,
        customPageHeaders: options.customPageHeaders,
        cookies: options.cookies,
        screenshots: options.screenshots,
        keepLargerMediaQueries: options.keepLargerMediaQueries,
        maxElementsToCheckPerSelector: options.maxElementsToCheckPerSelector,
        // postformatting
        propertiesToRemove,
        maxEmbeddedBase64Length:
          typeof options.maxEmbeddedBase64Length === 'number'
            ? options.maxEmbeddedBase64Length
            : DEFAULT_MAX_EMBEDDED_BASE64_LENGTH,
        debuglog,
        unstableKeepBrowserAlive: options.unstableKeepBrowserAlive,
        allowedResponseCode: options.allowedResponseCode,
        unstableKeepOpenPages:
          options.unstableKeepOpenPages ||
          _UNSTABLE_KEEP_ALIVE_MAX_KEPT_OPEN_PAGES
      })
    } catch (e) {
      const page = await pagePromise.then(({ page }) => page)
      await closeBrowserPage({
        page,
        error: e,
        unstableKeepBrowserAlive: options.unstableKeepBrowserAlive,
        unstableKeepOpenPages: options.unstableKeepOpenPages
      })

      const runningBrowswer = await browserIsRunning()
      if (!forceTryRestartBrowser && !runningBrowswer) {
        debuglog(
          'Browser unexpecedly not opened - crashed? ' +
            '\nurl: ' +
            options.url +
            '\ncss length: ' +
            options.cssString.length
        )
        try {
          await restartBrowser({
            width,
            height,
            getBrowser: options.puppeteer && options.puppeteer.getBrowser
          })
          // retry
          resolve(
            generateCriticalCssWrapped(options, {
              forceTryRestartBrowser: true
            })
          )
        } catch (e) {
          reject(e)
        }
        return
      }
      reject(e)
      return
    }

    const page = await pagePromise.then(({ page }) => page)
    await closeBrowserPage({
      page,
      unstableKeepBrowserAlive: options.unstableKeepBrowserAlive,
      unstableKeepOpenPages: options.unstableKeepOpenPages
    })

    debuglog('generateCriticalCss done')
    if (formattedCss.trim().length === 0) {
      // TODO: would be good to surface this to user, always
      debuglog('Note: Generated critical css was empty for URL: ' + options.url)
      resolve('')
      return
    }

    resolve(formattedCss)
  })
}
async function generateCriticalCssWrapped (
  options,
  { forceTryRestartBrowser } = {}
) {
  const width = parseInt(options.width || DEFAULT_VIEWPORT_WIDTH, 10)
  const height = parseInt(options.height || DEFAULT_VIEWPORT_HEIGHT, 10)
  const timeoutWait = options.timeout || DEFAULT_TIMEOUT
  // Merge properties with default ones
  const propertiesToRemove =
    options.propertiesToRemove || DEFAULT_PROPERTIES_TO_REMOVE

  // always forceInclude '*', 'html', and 'body' selectors;
  // yields slight performance improvement
  const forceInclude = prepareForceIncludeForSerialization(
    ['*', '*:before', '*:after', 'html', 'body'].concat(
      options.forceInclude || []
    )
  )

  // promise so we can handle errors and reject,
  // instead of throwing what would otherwise be uncaught errors in node process
  return new Promise(async (resolve, reject) => {
    debuglog('call generateCriticalCssWrapped')
    let formattedCss
    let pagePromise
    try {
      pagePromise = getOpenBrowserPage()

      formattedCss = await generateCriticalCss({
        pagePromise,
        url: options.url,
        cssString: options.cssString,
        width,
        height,
        forceInclude,
        strict: options.strict,
        userAgent: options.userAgent || DEFAULT_USER_AGENT,
        renderWaitTime: options.renderWaitTime || DEFAULT_RENDER_WAIT_TIMEOUT,
        timeout: timeoutWait,
        pageLoadSkipTimeout: options.pageLoadSkipTimeout,
        blockJSRequests:
          typeof options.blockJSRequests !== 'undefined'
            ? options.blockJSRequests
            : DEFAULT_BLOCK_JS_REQUESTS,
        customPageHeaders: options.customPageHeaders,
        cookies: options.cookies,
        screenshots: options.screenshots,
        keepLargerMediaQueries: options.keepLargerMediaQueries,
        maxElementsToCheckPerSelector: options.maxElementsToCheckPerSelector,
        // postformatting
        propertiesToRemove,
        maxEmbeddedBase64Length:
          typeof options.maxEmbeddedBase64Length === 'number'
            ? options.maxEmbeddedBase64Length
            : DEFAULT_MAX_EMBEDDED_BASE64_LENGTH,
        debuglog,
        unstableKeepBrowserAlive: options.unstableKeepBrowserAlive,
        allowedResponseCode: options.allowedResponseCode,
        unstableKeepOpenPages:
          options.unstableKeepOpenPages ||
          _UNSTABLE_KEEP_ALIVE_MAX_KEPT_OPEN_PAGES
      })
    } catch (e) {
      const page = await pagePromise.then(({ page }) => page)
      await closeBrowserPage({
        page,
        error: e,
        unstableKeepBrowserAlive: options.unstableKeepBrowserAlive,
        unstableKeepOpenPages: options.unstableKeepOpenPages
      })

      const runningBrowswer = await browserIsRunning()
      if (!forceTryRestartBrowser && !runningBrowswer) {
        debuglog(
          'Browser unexpecedly not opened - crashed? ' +
            '\nurl: ' +
            options.url +
            '\ncss length: ' +
            options.cssString.length
        )
        try {
          await restartBrowser({
            width,
            height,
            getBrowser: options.puppeteer && options.puppeteer.getBrowser
          })
          // retry
          resolve(
            generateCriticalCssWrapped(options, {
              forceTryRestartBrowser: true
            })
          )
        } catch (e) {
          reject(e)
        }
        return
      }
      reject(e)
      return
    }

    const page = await pagePromise.then(({ page }) => page)
    await closeBrowserPage({
      page,
      unstableKeepBrowserAlive: options.unstableKeepBrowserAlive,
      unstableKeepOpenPages: options.unstableKeepOpenPages
    })

    debuglog('generateCriticalCss done')
    if (formattedCss.trim().length === 0) {
      // TODO: would be good to surface this to user, always
      debuglog('Note: Generated critical css was empty for URL: ' + options.url)
      resolve('')
      return
    }

    resolve(formattedCss)
  })
}
async function generateCriticalCssWrapped ( options , { forceTryRestartBrowser } = { } ) { const width = parseInt ( options . width || DEFAULT_VIEWPORT_WIDTH , 10 ) const height = parseInt ( options . height || DEFAULT_VIEWPORT_HEIGHT , 10 ) const timeoutWait = options . timeout || DEFAULT_TIMEOUT // Merge properties with default ones const propertiesToRemove = options . propertiesToRemove || DEFAULT_PROPERTIES_TO_REMOVE // always forceInclude '*', 'html', and 'body' selectors; // yields slight performance improvement const forceInclude = prepareForceIncludeForSerialization ( [ '*' , '*:before' , '*:after' , 'html' , 'body' ] . concat ( options . forceInclude || [ ] ) ) // promise so we can handle errors and reject, // instead of throwing what would otherwise be uncaught errors in node process return new Promise ( async ( resolve , reject ) => { debuglog ( 'call generateCriticalCssWrapped' ) let formattedCss let pagePromise try { pagePromise = getOpenBrowserPage ( ) formattedCss = await generateCriticalCss ( { pagePromise , url : options . url , cssString : options . cssString , width , height , forceInclude , strict : options . strict , userAgent : options . userAgent || DEFAULT_USER_AGENT , renderWaitTime : options . renderWaitTime || DEFAULT_RENDER_WAIT_TIMEOUT , timeout : timeoutWait , pageLoadSkipTimeout : options . pageLoadSkipTimeout , blockJSRequests : typeof options . blockJSRequests !== 'undefined' ? options . blockJSRequests : DEFAULT_BLOCK_JS_REQUESTS , customPageHeaders : options . customPageHeaders , cookies : options . cookies , screenshots : options . screenshots , keepLargerMediaQueries : options . keepLargerMediaQueries , maxElementsToCheckPerSelector : options . maxElementsToCheckPerSelector , // postformatting propertiesToRemove , maxEmbeddedBase64Length : typeof options . maxEmbeddedBase64Length === 'number' ? options . maxEmbeddedBase64Length : DEFAULT_MAX_EMBEDDED_BASE64_LENGTH , debuglog , unstableKeepBrowserAlive : options . unstableKeepBrowserAlive , allowedResponseCode : options . allowedResponseCode , unstableKeepOpenPages : options . unstableKeepOpenPages || _UNSTABLE_KEEP_ALIVE_MAX_KEPT_OPEN_PAGES } ) } catch ( e ) { const page = await pagePromise . then ( ( { page } ) => page ) await closeBrowserPage ( { page , error : e , unstableKeepBrowserAlive : options . unstableKeepBrowserAlive , unstableKeepOpenPages : options . unstableKeepOpenPages } ) const runningBrowswer = await browserIsRunning ( ) if ( ! forceTryRestartBrowser && ! runningBrowswer ) { debuglog ( 'Browser unexpecedly not opened - crashed? ' + '\nurl: ' + options . url + '\ncss length: ' + options . cssString . length ) try { await restartBrowser ( { width , height , getBrowser : options . puppeteer && options . puppeteer . getBrowser } ) // retry resolve ( generateCriticalCssWrapped ( options , { forceTryRestartBrowser : true } ) ) } catch ( e ) { reject ( e ) } return } reject ( e ) return } const page = await pagePromise . then ( ( { page } ) => page ) await closeBrowserPage ( { page , unstableKeepBrowserAlive : options . unstableKeepBrowserAlive , unstableKeepOpenPages : options . unstableKeepOpenPages } ) debuglog ( 'generateCriticalCss done' ) if ( formattedCss . trim ( ) . length === 0 ) { // TODO: would be good to surface this to user, always debuglog ( 'Note: Generated critical css was empty for URL: ' + options . url ) resolve ( '' ) return } resolve ( formattedCss ) } ) }
const so not hoisted, so can get regeneratorRuntime inlined above, needed for Node 4
const so not hoisted so can get regeneratorRuntime inlined above needed for Node 4