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.

181 lines (167 loc) 5.21 kB
/* MIT License http://www.opensource.org/licenses/mit-license.php Author Natsu @xiaoxiaojx */ "use strict"; const { SyncWaterfallHook } = require("tapable"); const Compilation = require("../Compilation"); const RuntimeGlobals = require("../RuntimeGlobals"); const RuntimeModule = require("../RuntimeModule"); const Template = require("../Template"); /** @typedef {import("../Chunk")} Chunk */ /** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */ /** * @typedef {object} CssInjectCompilationHooks * @property {SyncWaterfallHook<[string, Chunk]>} createStyle */ /** @type {WeakMap<Compilation, CssInjectCompilationHooks>} */ const compilationHooksMap = new WeakMap(); class CssInjectStyleRuntimeModule extends RuntimeModule { /** * @param {Compilation} compilation the compilation * @returns {CssInjectCompilationHooks} hooks */ static getCompilationHooks(compilation) { if (!(compilation instanceof Compilation)) { throw new TypeError( "The 'compilation' argument must be an instance of Compilation" ); } let hooks = compilationHooksMap.get(compilation); if (hooks === undefined) { hooks = { createStyle: new SyncWaterfallHook(["source", "chunk"]) }; compilationHooksMap.set(compilation, hooks); } return hooks; } /** * @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements */ constructor(runtimeRequirements) { super("css inject style", RuntimeModule.STAGE_ATTACH); /** @type {ReadOnlyRuntimeRequirements} */ this._runtimeRequirements = runtimeRequirements; } /** * Generates runtime code for this runtime module. * @returns {string | null} runtime code */ generate() { const compilation = /** @type {Compilation} */ (this.compilation); const { runtimeTemplate, outputOptions } = compilation; const { uniqueName } = outputOptions; const { _runtimeRequirements } = this; /** @type {boolean} */ const withHmr = _runtimeRequirements && _runtimeRequirements.has(RuntimeGlobals.hmrDownloadUpdateHandlers); const { createStyle } = CssInjectStyleRuntimeModule.getCompilationHooks(compilation); const createStyleElementCode = Template.asString([ "var style = document.createElement('style');", "", `if (${RuntimeGlobals.scriptNonce}) {`, Template.indent( `style.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});` ), "}", 'style.setAttribute("data-webpack", getDataWebpackId(key));' ]); return Template.asString([ `var dataWebpackPrefix = ${uniqueName ? JSON.stringify(`${uniqueName}:`) : '"webpack:"'};`, "", "function getDataWebpackId(identifier) {", Template.indent("return dataWebpackPrefix + identifier;"), "}", "", "function applyStyle(styleElement, css) {", Template.indent("styleElement.textContent = css;"), "}", "", "function removeStyleElement(styleElement) {", Template.indent([ "if (styleElement.parentNode) {", Template.indent("styleElement.parentNode.removeChild(styleElement);"), "}" ]), "}", "", "function findStyleElement(identifier) {", Template.indent([ "var elements = document.getElementsByTagName('style');", "for (var i = 0; i < elements.length; i++) {", Template.indent([ "var el = elements[i];", "if (el.getAttribute('data-webpack') === getDataWebpackId(identifier)) {", Template.indent("return el;"), "}" ]), "}", "return null;" ]), "}", "", "function insertStyleElement(key) {", Template.indent([ createStyle.call( createStyleElementCode, /** @type {Chunk} */ (this.chunk) ), "", "document.head.appendChild(style);", "", "return style;" ]), "}", "", `${RuntimeGlobals.cssInjectStyle} = ${runtimeTemplate.basicFunction( "identifier, css", [ "var element = findStyleElement(identifier);", "if (element) {", Template.indent("applyStyle(element, css);"), "} else {", Template.indent([ "var element = insertStyleElement(identifier);", "applyStyle(element, css);" ]), "}" ] )};`, "", `${RuntimeGlobals.cssInjectStyle}.removeModules = ${runtimeTemplate.basicFunction( "removedModules", [ "if (!removedModules) return;", "var identifiers = Array.isArray(removedModules) ? removedModules : [removedModules];", "for (var i = 0; i < identifiers.length; i++) {", Template.indent([ "var identifier = identifiers[i];", "var element = findStyleElement(identifier);", "if (element) {", Template.indent("removeStyleElement(element);"), "}" ]), "}" ] )};`, withHmr ? Template.asString([ `${RuntimeGlobals.hmrDownloadUpdateHandlers}.cssInjectStyle = ${runtimeTemplate.basicFunction( "chunkIds, removedChunks, removedModules, promises, applyHandlers, updatedModulesList, css", [ "if (removedModules) {", Template.indent( `${RuntimeGlobals.cssInjectStyle}.removeModules(removedModules);` ), "}" ] )};` ]) : "// no css inject style HMR download handler" ]); } } module.exports = CssInjectStyleRuntimeModule;