mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-12 08:47:31 +00:00
- Rename to critters-webpack-plugin
- Format output using pretty-bytes - Insert inlined style tags immediately after their source link tags - Add option to turn off external stylesheet processing - Add `async` option that converts critical'd external sheets to `<link rel="preload" as="style" onload="this.rel='stylesheet'">`
This commit is contained in:
@@ -3,10 +3,11 @@ const path = require('path');
|
||||
const parse5 = require('parse5');
|
||||
const nwmatcher = require('nwmatcher');
|
||||
const css = require('css');
|
||||
const prettyBytes = require('pretty-bytes');
|
||||
|
||||
const treeUtils = parse5.treeAdapters.htmlparser2;
|
||||
|
||||
const PLUGIN_NAME = 'html-webpack-inline-critical-css-plugin';
|
||||
const PLUGIN_NAME = 'critters-webpack-plugin';
|
||||
|
||||
const PARSE5_OPTS = {
|
||||
treeAdapter: treeUtils
|
||||
@@ -25,6 +26,11 @@ const ElementExtensions = {
|
||||
return this.tagName;
|
||||
}
|
||||
},
|
||||
insertBefore: function (child, referenceNode) {
|
||||
if (!referenceNode) return this.appendChild(child);
|
||||
treeUtils.insertBefore(this, child, referenceNode);
|
||||
return child;
|
||||
},
|
||||
appendChild: function (child) {
|
||||
treeUtils.appendChild(this, child);
|
||||
return child;
|
||||
@@ -82,7 +88,13 @@ const DocumentExtensions = {
|
||||
addEventListener: Object
|
||||
};
|
||||
|
||||
module.exports = class HtmlWebpackInlineCriticalCssPlugin {
|
||||
/** Critters: Webpack Plugin Edition!
|
||||
* @class
|
||||
* @param {Object} options
|
||||
* @param {Boolean} [options.external=true] Fetch and inline critical styles from external stylesheets
|
||||
* @param {Boolean} [options.async=true] If `false`, only already-inline stylesheets will be reduced to critical rules.
|
||||
*/
|
||||
module.exports = class CrittersWebpackPlugin {
|
||||
constructor(options) {
|
||||
this.options = options || {};
|
||||
}
|
||||
@@ -112,6 +124,7 @@ module.exports = class HtmlWebpackInlineCriticalCssPlugin {
|
||||
const externalSheets = document.querySelectorAll('link[rel="stylesheet"]');
|
||||
|
||||
Promise.all(externalSheets.map(function(link) {
|
||||
if (self.options.external===false) return;
|
||||
const href = link.getAttribute('href');
|
||||
if (href.match(/^(https?:)?\/\//)) return Promise.resolve();
|
||||
const filename = path.resolve(outputPath, href.replace(/^\//, ''));
|
||||
@@ -121,7 +134,12 @@ module.exports = class HtmlWebpackInlineCriticalCssPlugin {
|
||||
const style = document.createElement('style');
|
||||
style.$$name = href;
|
||||
style.appendChild(document.createTextNode(sheet));
|
||||
link.parentNode.appendChild(style); // @TODO insertBefore
|
||||
link.parentNode.insertBefore(style, link.nextSibling);
|
||||
if (self.options.async) {
|
||||
link.setAttribute('rel', 'preload');
|
||||
link.setAttribute('as', 'style');
|
||||
link.setAttribute('onload', "this.rel='stylesheet'");
|
||||
}
|
||||
});
|
||||
}))
|
||||
.then(function() {
|
||||
@@ -199,8 +217,9 @@ module.exports = class HtmlWebpackInlineCriticalCssPlugin {
|
||||
}
|
||||
style.appendChild(document.createTextNode(sheet));
|
||||
}
|
||||
const name = style.$$name;
|
||||
console.log('\u001b[32mInlined CSS Size' + (name ? (' ('+name+')') : '') + ': ' + (sheet.length / 1000).toPrecision(2) + 'kb (' + ((before.length - sheet.length) / before.length * 100 | 0) + '% of original ' + (before.length / 1000).toPrecision(2) + 'kb)\u001b[39m');
|
||||
const name = style.$$name ? style.$$name.replace(/^\//, '') : 'inline CSS';
|
||||
const percent = (before.length - sheet.length) / before.length * 100 | 0;
|
||||
console.log('\u001b[32mCritters: inlined ' + prettyBytes(sheet.length) + ' (' + percent + '% of original ' + prettyBytes(before.length) + ') of ' + name + '.\u001b[39m');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -9,7 +9,7 @@ const PreloadWebpackPlugin = require('preload-webpack-plugin');
|
||||
const ReplacePlugin = require('webpack-plugin-replace');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const WorkboxPlugin = require('workbox-webpack-plugin');
|
||||
const HtmlInlineCssPlugin = require('./config/html-webpack-inline-critical-css-plugin');
|
||||
const CrittersPlugin = require('./config/critters-webpack-plugin');
|
||||
const WatchTimestampsPlugin = require('./config/watch-timestamps-plugin');
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
|
||||
@@ -175,8 +175,11 @@ module.exports = function(_, env) {
|
||||
|
||||
// Inject <link rel="preload"> for resources
|
||||
isProd && new PreloadWebpackPlugin(),
|
||||
isProd && new HtmlInlineCssPlugin(),
|
||||
|
||||
isProd && new CrittersPlugin({
|
||||
// convert critical'd <link rel="stylesheet"> to <link rel="preload" as="style" onload="this.rel='stylesheet'">
|
||||
async: true
|
||||
}),
|
||||
|
||||
// Inline constants during build, so they can be folded by UglifyJS.
|
||||
new webpack.DefinePlugin({
|
||||
|
||||
Reference in New Issue
Block a user