UNPKG

html-bundler-webpack-plugin

Version:

Generates complete single-page or multi-page website from source assets. Build-in support for Markdown, Eta, EJS, Handlebars, Nunjucks, Pug. Alternative to html-webpack-plugin.

114 lines (95 loc) 3.19 kB
const path = require('path'); /** @typedef {import('webpack').Compilation} Compilation */ /** @typedef {import('webpack').sources.ConcatSource} ConcatSource */ /** * The plugin module to extract the CSS and source map from asset. * * @note If webpack mode is `production`, then `scss-loader` minifies the CSS self. * If webpack is in `development` mode, then CSS is pretty formatted. */ class CssExtractModule { /** @type {Compilation} */ compilation = null; assetTrash = null; /** * * @param {AssetTrash} assetTrash * @param {Compilation} compilation */ constructor({ assetTrash, compilation }) { this.compilation = compilation; this.assetTrash = assetTrash; } /** * @param {Compilation} compilation */ init(compilation) { this.compilation = compilation; } /** * Extract CSS and source map from the result of the css-loader. * * @note The @import handling in CSS is not supported, e.g.: @import 'assets/css/style.css'. * Disable @import at-rules handling in `css-loader`: * { * test: /\.css$/i, * use: [ * { * loader: 'css-loader' * options: { * import: false, // disable @import at-rules handling * }, * }, * ], * }, * * @param {Array<[]>} data The data generated by `css-loader`. * @param {Function?} update The callback to replace in url() the raw request with the output filename. * @returns {ConcatSource} */ apply(data, update) { const { compiler } = this.compilation; const { ConcatSource, SourceMapSource } = compiler.webpack.sources; const source = new ConcatSource(); const hasUpdate = typeof update === 'function'; for (const item of data) { if (!Array.isArray(item)) continue; let [sourceFile, content, media, sourceMap, supports, layer] = item; // when in SCSS is used import of CSS file, like `@import url('./style.css');` // then `sourceFile` is null and `content` contains the output CSS filename if (sourceFile == null && content.endsWith('.css')) { source.add(`@import url(${content});`); continue; } if (hasUpdate) { content = update(content); } if (sourceMap) { source.add(new SourceMapSource(content, sourceFile, JSON.stringify(sourceMap))); } else { source.add(content); } } return source; } /** * @param {string} assetFile The asset filename. * @returns {string} */ getInlineSource(assetFile) { const sources = this.compilation.assets; const assetMapFile = assetFile + '.map'; const mapFilename = path.basename(assetMapFile); const sourceMap = sources[assetMapFile]?.source(); let source = sources[assetFile].source(); if (sourceMap) { const base64 = Buffer.from(JSON.stringify(sourceMap)).toString('base64'); const inlineSourceMap = 'data:application/json;charset=utf-8;base64,' + base64; source = source.replace(mapFilename, inlineSourceMap); } // don't generate css file for inlined styles this.assetTrash.add(assetFile); return source; } } module.exports = CssExtractModule;