description and source-codepenthouse = function (options, callback) { // jshint ignore: line
var stdOut = ''
var stdErr = ''
// debugging
var START_TIME = Date.now()
var debuglog = function (msg, isError) {
if (m.DEBUG) {
var errMsg = 'time: ' + (Date.now() - START_TIME) + ' | ' + (isError ? 'ERR: ' : '') + msg
stdErr += errMsg
console.error(errMsg)
}
}
normalizeCss.DEBUG = m.DEBUG
function generateCriticalCss (ast) {
var debuggingHelp = '',
cp,
killTimeout
var timeoutWait = options.timeout || DEFAULT_TIMEOUT
var astTmpobj = writeAstToFile(ast)
var scriptArgs = penthouseScriptArgs(options, astTmpobj.name)
var phantomJsArgs = [configString].concat(toPhantomJsOptions(options.phantomJsOptions))
phantomJsArgs.push(script)
phantomJsArgs = phantomJsArgs.concat(scriptArgs)
cp = spawn(phantomJsBinPath, phantomJsArgs)
// Errors arise before the process starts
cp.on('error', function (err) {
debuggingHelp += 'Error executing penthouse using ' + phantomJsBinPath
debuggingHelp += err.stack
err.debug = debuggingHelp
callback(err)
// remove the tmp file we created
// library would clean up after process ends, but this is better for long living proccesses
astTmpobj.removeCallback()
})
cp.stdout.on('data', function (data) {
stdOut += data
})
cp.stderr.on('data', function (data) {
stdErr += data
debuglog(String(data))
})
cp.on('close', function (code) {
if (code !== 0) {
debuggingHelp += 'PhantomJS process closed with code ' + code
}
})
// kill after timeout
killTimeout = setTimeout(function () {
var msg = 'Penthouse timed out after ' + timeoutWait / 1000 + 's. '
debuggingHelp += msg
stdErr += msg
cp.kill('SIGTERM')
}, timeoutWait)
cp.on('exit', function (code) {
if (code === 0) {
// promise purely for catching errors,
// that otherwise exit node
new Promise(function (resolve) {
var finalCss = postformatting(stdOut, {
maxEmbeddedBase64Length: typeof options.maxEmbeddedBase64Length === 'number' ? options.maxEmbeddedBase64Length : DEFAULT_MAX_EMBEDDED_BASE64_LENGTH
}, m.DEBUG, START_TIME)
if (finalCss.trim().length === 0) {
// TODO: this error should surface to user
debuglog('Note: Generated critical css was empty for URL: ' + options.url)
} else {
// remove irrelevant css properties
finalCss = apartment(finalCss, {
properties: [
'(.*)transition(.*)',
'cursor',
'pointer-events',
'(-webkit-)?tap-highlight-color',
'(.*)user-select'
],
// TODO: move into core phantomjs script
selectors: [
'::(-moz-)?selection'
]
})
}
callback(null, finalCss)
resolve()
return
})
.catch(function (err) {
callback(err)
})
} else {
debuggingHelp += 'PhantomJS process exited with code ' + code
var err = new Error(stdErr + stdOut)
err.code = code
err.debug = debuggingHelp
err.stdout = stdOut
err.stderr = stdErr
callback(err)
}
// we're done here - clean up
clearTimeout(killTimeout)
// can't rely on that the parent process will be terminated any time soon,
// need to rm listeners and kill child process manually
process.removeListener('exit', exitHandler)
process.removeListener('SIGTERM', sigtermHandler)
// remove the tmp file we created
// library would clean up after process ends, but this is better for long living proccesses
astTmpobj.removeCallback()
cp.kill('SIGTERM')
})
function exitHandler () {
cp.kill('SIGTERM')
}
function sigtermHandler () {
cp.kill('SIGTERM')
process.exit(0)
}
process.on('exit', exit ...