@roots/critical-css-webpack-plugin
Version:
Webpack plugin for generating critical-path CSS
98 lines (97 loc) • 3.07 kB
JavaScript
import { __decorate } from "tslib";
import { join } from 'node:path';
import * as critical from 'critical';
import { bind } from 'helpful-decorators';
import vinyl from 'vinyl';
import Webpack from 'webpack';
/**
* CriticalCSSWebpackPlugin
*/
export default class CriticalCssWebpackPlugin {
/**
* Plugin options
*/
options = {
extract: true,
height: 900,
request: {
https: {
rejectUnauthorized: false,
},
},
width: 1300,
};
/**
* Plugin ident
*/
plugin = {
name: `CriticalCssWebpackPlugin`,
stage: Webpack.Compilation.PROCESS_ASSETS_STAGE_DERIVED,
};
/**
* Class constructor
*
* @param options - The options for the plugin.
*/
constructor(options) {
options && Object.assign(this.options, options);
}
/**
* Webpack apply hook
*
* @remarks
* This method is called when the plugin is applied to a {@link Webpack.Compiler | Compiler}.
*
* @param compiler - The {@link Webpack.Compiler | Compiler}.
*/
async apply(compiler) {
compiler.hooks.thisCompilation.tap(this.plugin, compilation => {
compilation.hooks.processAssets.tapPromise(this.plugin, this.makeProcessAssetsHook(compilation));
});
}
/**
* Process assets
*
* @param compilation - The {@link Webpack.Compilation | Compilation}.
* @returns A function that processes the assets.
*/
makeProcessAssetsHook(compilation) {
return async (assets) => {
const base = this.options.base ?? compilation.outputOptions.path;
await Promise.all(Object.keys(assets).map(async (ident) => {
if (!ident.endsWith(`.css`))
return;
const asset = compilation.getAsset(ident);
if (!asset)
return;
compilation.buildDependencies.add(asset.name);
const vfile = new vinyl({
base,
contents: asset.source.buffer(),
path: asset.name,
});
const result = await critical
.generate({
...this.options,
base,
css: [vfile],
})
.catch((error) => {
throw error;
});
if (!result?.css)
return; // nothing to do here
if (this.options.extract && result.uncritical) {
compilation.updateAsset(asset.name, new Webpack.sources.RawSource(result.uncritical));
}
compilation.emitAsset(join(`critical`, asset.name), new Webpack.sources.RawSource(result.css), asset.info);
}));
};
}
}
__decorate([
bind
], CriticalCssWebpackPlugin.prototype, "apply", null);
__decorate([
bind
], CriticalCssWebpackPlugin.prototype, "makeProcessAssetsHook", null);