stream.on('readable', function () { // extract stylesheet and javascripts urls var contents = stream.read() if (!contents) return styles = styles.concat(flatten( oust(contents, 'stylesheets'), oust(contents, 'preload') )) styles = styles.map(function (styleHref) { var u = url.parse(styleHref) if (!u.hostname) u = url.parse(inspectUrl.protocol + '//' + inspectUrl.host + styleHref) return u }).filter(function (styleUrl) { return styleUrl.hostname && styleUrl.hostname.endsWith(inspectUrl.hostname) }) // FIXME: also find <script> tags, this just looks for <script src=""> scripts = scripts.concat(oust(contents, 'scripts').map(function (scriptHref) { var u = url.parse(scriptHref) if (!u.hostname) u = url.parse(inspectUrl.protocol + '//' + inspectUrl.host + scriptHref) return u })).filter(function (scriptUrl) { return scriptUrl.hostname && scriptUrl.hostname.endsWith(inspectUrl.hostname) }) })
return file.getContentPromise(opts).then(function (html) { // consider opts.css and map to array if it's a string if (opts.css) { return typeof opts.css === 'string' ? [opts.css] : opts.css; } // Oust extracts a list of your stylesheets var stylesheets = [ oust(html.toString(), 'stylesheets'), oust(html.toString(), 'preload') ].reduce(function (a, b) { return a.concat(b); }, []).map(file.resourcePath(opts)); debug('Stylesheets: ' + stylesheets); return Promise.map(stylesheets, file.assertLocal(opts)); // read files }).map(function (fileName) {
fs.readFileAsync(url).then(function (html) { // consider opts.css and map to array if it's a string if (opts.css) { return (typeof opts.css === 'string') ? [opts.css] : opts.css; } else { // Oust extracts a list of your stylesheets return oust(html.toString('utf8'), 'stylesheets').map(function (href) { return path.join(opts.base, href); }); } // read files }).map(function(fileName){
return getContentPromise(opts).then(function (html) { // consider opts.css and map to array if it's a string if (opts.css) { return typeof opts.css === 'string' ? [opts.css] : opts.css; } // Oust extracts a list of your stylesheets (ignoring remote stylesheets) return oust(html.toString(), 'stylesheets').filter(function (href) { return !/(^\/\/)|(:\/\/)/.test(href); }).map(function (href) { return path.join(opts.base, href); }); // read files }).map(function (fileName) {
/** * Compute a source path which fits to the directory structure * so that relative links could be resolved * @param {object} opts Options passed to critical * @returns {string} */ function generateSourcePath(opts) { var html = opts.html; if (typeof opts.src !== 'undefined') { return path.dirname(opts.src); } if (typeof opts.folder !== 'undefined') { var folder = path.isAbsolute(opts.folder) ? opts.folder : path.join(opts.base, opts.folder); opts.pathPrefix = path.relative(opts.folder, opts.base); return folder; } if (!opts.pathPrefix) { var links = oust(html, 'stylesheets'); debug('generateSourcePath - links', links); // we can only determine a valid path by checking relative links var relative = _.chain(links).omitBy(function (link) { return /^data:/.test(link) || /(?:^\/)|(?::\/\/)/.test(link); }).toArray().value(); debug('generateSourcePath - relative', relative); if (relative.length === 0) { process.stderr.write([ chalk.red('Warning:'), 'Missing html source path. Consider \'folder\' option.', 'https://goo.gl/PwvFVb', os.EOL ].join(' ')); opts.pathPrefix = '/'; return opts.base; } var dots = _.map(relative, function (link) { var match = /^(\.\.\/)+/.exec(link); return _.first(match); }); opts.pathPrefix = _.chain(dots).sortBy('length').last().value() || ''; debug('generateSourcePath', opts.pathPrefix.replace(/\.\./g, '~')); } return path.join(opts.base, opts.pathPrefix.replace(/\.\./g, '~')); }
fs.readFile(url, function (err, html) { if (err) { cb(err); return; } // Oust extracts a list of your stylesheets var hrefs = oust(html, 'stylesheets'); // Penthouse then determines your critical // path CSS using these as input. penthouse({ url: url, css: path.join(opts.base, hrefs[0]), // What viewports do you care about? width: opts.width, // viewport width height: opts.height // viewport height }, function (err, criticalCSS) { if (err) { cb(err); return; } if (opts.minify === true) { criticalCSS = new CleanCSS().minify(criticalCSS); } if (opts.dest) { // Write critical-path CSS fs.writeFile(path.join(opts.base, opts.dest), criticalCSS, function (err) { if (err) { cb(err); return; } cb(null, criticalCSS.toString()); }); } else { cb(null, criticalCSS.toString()); } }); });
.then(html => { if (html.toLowerCase().indexOf('<html') === -1) { throw new Error('No HTML received'); } return oust(html, 'stylesheets'); })