UNPKG

@roots/critical-css-webpack-plugin

Version:

Webpack plugin for generating critical-path CSS

98 lines (97 loc) 3.07 kB
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);