| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /*
- 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;
|