UNPKG

webpack

Version:

Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.

148 lines (131 loc) 4.29 kB
/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const { ConcatSource } = require("webpack-sources"); const Compilation = require("./Compilation"); const ModuleFilenameHelpers = require("./ModuleFilenameHelpers"); const Template = require("./Template"); /** @typedef {import("webpack-sources").Source} Source */ /** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginArgument} BannerPluginArgument */ /** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginOptions} BannerPluginOptions */ /** @typedef {import("./Compilation").PathData} PathData */ /** @typedef {import("./Compiler")} Compiler */ /** @typedef {import("./Chunk")} Chunk */ /** @typedef {import("./TemplatedPathPlugin").TemplatePath} TemplatePath */ /** @typedef {(data: { hash?: string, chunk: Chunk, filename: string }) => string} BannerFunction */ /** * Wraps banner text in a JavaScript block comment, preserving multi-line * formatting and escaping accidental comment terminators. * @param {string} str string to wrap * @returns {string} wrapped string */ const wrapComment = (str) => { if (!str.includes("\n")) { return Template.toComment(str); } return `/*!\n * ${str .replace(/\*\//g, "* /") .split("\n") .join("\n * ") .replace(/\s+\n/g, "\n") .trimEnd()}\n */`; }; const PLUGIN_NAME = "BannerPlugin"; /** * Prepends or appends banner text to emitted assets that match the configured * file filters. */ class BannerPlugin { /** * Normalizes banner options and compiles the configured banner source into a * function that can render per-asset banner text. * @param {BannerPluginArgument} options options object */ constructor(options) { if (typeof options === "string" || typeof options === "function") { options = { banner: options }; } /** @type {BannerPluginOptions} */ this.options = options; const bannerOption = options.banner; if (typeof bannerOption === "function") { const getBanner = bannerOption; /** @type {BannerFunction} */ this.banner = this.options.raw ? getBanner : /** @type {BannerFunction} */ (data) => wrapComment(getBanner(data)); } else { const banner = this.options.raw ? bannerOption : wrapComment(bannerOption); /** @type {BannerFunction} */ this.banner = () => banner; } } /** * Validates the configured options and injects rendered banner comments into * matching compilation assets at the configured process-assets stage. * @param {Compiler} compiler the compiler instance * @returns {void} */ apply(compiler) { compiler.hooks.validate.tap(PLUGIN_NAME, () => { compiler.validate( () => require("../schemas/plugins/BannerPlugin.json"), this.options, { name: "Banner Plugin", baseDataPath: "options" }, (options) => require("../schemas/plugins/BannerPlugin.check")(options) ); }); const options = this.options; const banner = this.banner; const matchObject = ModuleFilenameHelpers.matchObject.bind( undefined, options ); /** @type {WeakMap<Source, { source: ConcatSource, comment: string }>} */ const cache = new WeakMap(); const stage = this.options.stage || Compilation.PROCESS_ASSETS_STAGE_ADDITIONS; compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => { compilation.hooks.processAssets.tap({ name: PLUGIN_NAME, stage }, () => { for (const chunk of compilation.chunks) { if (options.entryOnly && !chunk.canBeInitial()) { continue; } for (const file of chunk.files) { if (!matchObject(file)) { continue; } /** @type {PathData} */ const data = { chunk, filename: file }; const comment = compilation.getPath( /** @type {TemplatePath} */ (banner), data ); compilation.updateAsset(file, (old) => { const cached = cache.get(old); if (!cached || cached.comment !== comment) { const source = options.footer ? new ConcatSource(old, "\n", comment) : new ConcatSource(comment, "\n", old); cache.set(old, { source, comment }); return source; } return cached.source; }); } } }); }); } } module.exports = BannerPlugin;