UNPKG

mikel-webpack-plugin

Version:

Generate HTML files using the Mikel templating

98 lines (89 loc) 4 kB
import fs from "node:fs"; import path from "node:path"; import mikel from "mikel"; // @description global variables const PLUGIN_NAME = "MikelWebpackPlugin"; // @description get an array value const getArrayValue = (value, defaultValue) => { return value && Array.isArray(value) ? value : defaultValue; }; // @description get object value const getObjectValue = (value, defaultValue) => { return value && typeof value === "object" ? value : defaultValue; }; // @description returns the template content from the given options const getTemplateContent = options => { // using options.template to specify the the absolute path to the template file if (typeof options.template === "string") { return fs.readFileSync(options.template, "utf8"); } // using templateContent to specify the string content of the template if (typeof options.templateContent === "string") { return options.templateContent; } // Other case: use the default template return fs.readFileSync("./template.html", "utf8"); }; // @description get the entry names to include in the output HTML const getEntryNames = (compilation, includeChunks = []) => { const entryNames = Array.from(compilation.entrypoints.keys()); // note: empty includeChunks means that no assets will be injected in the generated HTML // if (!includeChunks || includeChunks.length === 0) { if (!includeChunks) { return entryNames; } // get only entries that are included in the includeChunks array return entryNames.filter(entryName => includeChunks.includes(entryName)); }; // @description get assets related to the specified entries const getAssets = (compilation, entryNames, publicPath = "./") => { const assets = new Set(); entryNames.forEach(entryName => { compilation.entrypoints.get(entryName) .getFiles() .filter(file => !!compilation.getAsset(file)) .filter(file => [".js", ".css"].includes(path.extname(file))) .map(file => publicPath + file) .forEach(file => assets.add(file)); }); // return Array.from(assets); return { publicPath: publicPath, js: Array.from(assets).filter(file => file.endsWith(".js")), css: Array.from(assets).filter(file => file.endsWith(".css")), }; }; // @description MikelWebpackPlugin class export default class MikelWebpackPlugin { constructor(options = {}) { this.options = options; } apply(compiler) { const includeChunks = getArrayValue(this.options.chunks, ["main"]); const filename = this.options.filename || "index.html"; const template = getTemplateContent(this.options); compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => { const processAssetsOptions = { name: PLUGIN_NAME, stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE, }; compilation.hooks.processAssets.tap(processAssetsOptions, () => { const publicPath = this.options.publicPath || "./"; const entryNames = getEntryNames(compilation, includeChunks); const assets = getAssets(compilation, entryNames, publicPath); // compile the provided template const pluginData = { ...(this.options.templateData || {}), options: this.options, assets: assets, metaTags: getObjectValue(this.options.meta, {}), linkTags: getArrayValue(this.options.link, []), }; const content = mikel(template, pluginData, this.options.templateOptions || {}); // emit the HTML file as a new asset compilation.emitAsset(filename, new compiler.webpack.sources.RawSource(content)); } ); }); } }