CssModulesPlugin.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { SyncBailHook, SyncHook, SyncWaterfallHook } = require("tapable");
  7. const {
  8. CachedSource,
  9. ConcatSource,
  10. PrefixSource,
  11. RawSource,
  12. ReplaceSource
  13. } = require("webpack-sources");
  14. /** @import Compilation, { ChunkHashContext } from "../Compilation" */
  15. const HotUpdateChunk = require("../HotUpdateChunk");
  16. const { CSS_IMPORT_TYPE, CSS_TYPE } = require("../ModuleSourceTypeConstants");
  17. const {
  18. CSS_MODULE_TYPE,
  19. CSS_MODULE_TYPE_AUTO,
  20. CSS_MODULE_TYPE_GLOBAL,
  21. CSS_MODULE_TYPE_MODULE
  22. } = require("../ModuleTypeConstants");
  23. const NormalModule = require("../NormalModule");
  24. const RuntimeGlobals = require("../RuntimeGlobals");
  25. const Template = require("../Template");
  26. const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
  27. const { tryRunOrWebpackError } = require("../errors/HookWebpackError");
  28. const WebpackError = require("../errors/WebpackError");
  29. const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin");
  30. const ConcatenatedModule = require("../optimize/ConcatenatedModule");
  31. const { compareModulesByFullName } = require("../util/comparators");
  32. const createHash = require("../util/createHash");
  33. const createHooksRegistry = require("../util/createHooksRegistry");
  34. const { getUndoPath } = require("../util/identifier");
  35. const implicitTypeLoaderFallback = require("../util/implicitTypeLoaderFallback");
  36. const lazyModule = require("../util/lazyModule");
  37. const memoize = require("../util/memoize");
  38. const { digestNonNumericOnlyWithFull } = require("../util/nonNumericOnlyHash");
  39. const preloadModuleType = require("../util/preloadModuleType");
  40. const {
  41. PUBLIC_PATH_AUTO,
  42. walkFullHashPlaceholders
  43. } = require("../util/publicPathPlaceholder");
  44. const removeBOM = require("../util/removeBOM");
  45. const CssModule = require("./CssModule");
  46. /** @import { Source } from "webpack-sources" */
  47. /**
  48. * @import {
  49. * OutputNormalizedWithDefaults as OutputOptions
  50. * } from "../config/defaults"
  51. */
  52. /** @import Chunk, { ChunkFilenameTemplate } from "../Chunk" */
  53. /** @import ChunkGraph from "../ChunkGraph" */
  54. /** @import CodeGenerationResults from "../CodeGenerationResults" */
  55. /** @import Compiler from "../Compiler" */
  56. /** @import RuntimeTemplate from "../RuntimeTemplate" */
  57. /** @import CssGenerator from "./CssGenerator" */
  58. /** @import CssParser from "./CssParser" */
  59. /**
  60. * @import {
  61. * Inheritance,
  62. * CssModuleCreateData,
  63. * CssModuleBuildInfo
  64. * } from "./CssModule"
  65. */
  66. /** @import Module, { RuntimeRequirements } from "../Module" */
  67. /** @import Hash from "../util/Hash" */
  68. /**
  69. * Defines the render context type used by this module.
  70. * @typedef {object} RenderContext
  71. * @property {Chunk} chunk the chunk
  72. * @property {ChunkGraph} chunkGraph the chunk graph
  73. * @property {CodeGenerationResults} codeGenerationResults results of code generation
  74. * @property {RuntimeTemplate} runtimeTemplate the runtime template
  75. * @property {string} uniqueName the unique name
  76. * @property {string} undoPath undo path to css file
  77. * @property {string=} hash compilation hash
  78. * @property {CssModule[]} modules modules
  79. */
  80. /**
  81. * Defines the chunk render context type used by this module.
  82. * @typedef {object} ChunkRenderContext
  83. * @property {Chunk=} chunk the chunk
  84. * @property {ChunkGraph=} chunkGraph the chunk graph
  85. * @property {CodeGenerationResults=} codeGenerationResults results of code generation
  86. * @property {RuntimeTemplate} runtimeTemplate the runtime template
  87. * @property {string} undoPath undo path to css file
  88. * @property {string=} hash compilation hash
  89. * @property {WeakMap<Source, ModuleFactoryCacheEntry>} moduleFactoryCache moduleFactoryCache
  90. * @property {Source} moduleSourceContent content
  91. */
  92. /**
  93. * Defines the module factory cache entry type used by this module.
  94. * @typedef {object} ModuleFactoryCacheEntry
  95. * @property {string} undoPath - The undo path to the CSS file
  96. * @property {string | undefined} hash - The compilation hash
  97. * @property {Inheritance} inheritance - The inheritance chain
  98. * @property {CachedSource} source - The cached source
  99. */
  100. // Lazy: this plugin is applied on every build (`experiments.css` defaults on),
  101. // but the parser and generator are only reached once CSS is in the graph — and
  102. // the parser pulls in the CSS tokenizer.
  103. const getCssParser = lazyModule(() => require("./CssParser"));
  104. const getCssGenerator = lazyModule(() => require("./CssGenerator"));
  105. const CSS_MODULE_TYPES = [
  106. CSS_MODULE_TYPE,
  107. CSS_MODULE_TYPE_GLOBAL,
  108. CSS_MODULE_TYPE_MODULE,
  109. CSS_MODULE_TYPE_AUTO
  110. ];
  111. const getCssImportDependency = memoize(() =>
  112. require("../dependencies/CssImportDependency")
  113. );
  114. const getCssLoadingRuntimeModule = lazyModule(() =>
  115. require("./CssLoadingRuntimeModule")
  116. );
  117. const getCssInjectStyleRuntimeModule = lazyModule(() =>
  118. require("./CssInjectStyleRuntimeModule")
  119. );
  120. /**
  121. * @typedef {object} PublicPathPlaceholderPlan
  122. * @property {number[]} autos start offsets of each `PUBLIC_PATH_AUTO` placeholder
  123. * @property {{ start: number, end: number, length: number }[]} hashes `[start, end)` ranges of each `PUBLIC_PATH_FULL_HASH` placeholder and its requested hash length
  124. */
  125. /**
  126. * Public-path placeholder offsets are invariant for a given module source —
  127. * they don't depend on `undoPath`/`hash`/`inheritance`/runtime — so scan once
  128. * and reuse across renders instead of re-materializing and re-scanning the
  129. * source on every cache miss. Weakly keyed so entries release with the source.
  130. * @type {WeakMap<Source, PublicPathPlaceholderPlan>}
  131. */
  132. const publicPathPlaceholderPlans = new WeakMap();
  133. /**
  134. * Memoized inheritance chain per module, revalidated against its source
  135. * fields — `updateCacheModule` reassigns them on watch rebuilds.
  136. * @type {WeakMap<CssModule, { cssLayer: CssModule["cssLayer"], supports: CssModule["supports"], media: CssModule["media"], inheritance: CssModule["inheritance"], chain: Inheritance }>}
  137. */
  138. const moduleInheritanceCache = new WeakMap();
  139. /**
  140. * Gets the memoized inheritance chain of a css module.
  141. * @param {CssModule} module css module
  142. * @returns {Inheritance} inheritance chain including the module's own entry
  143. */
  144. const getModuleInheritance = (module) => {
  145. const entry = moduleInheritanceCache.get(module);
  146. if (
  147. entry !== undefined &&
  148. entry.cssLayer === module.cssLayer &&
  149. entry.supports === module.supports &&
  150. entry.media === module.media &&
  151. entry.inheritance === module.inheritance
  152. ) {
  153. return entry.chain;
  154. }
  155. /** @type {Inheritance} */
  156. const chain = [[module.cssLayer, module.supports, module.media]];
  157. if (module.inheritance) chain.push(...module.inheritance);
  158. moduleInheritanceCache.set(module, {
  159. cssLayer: module.cssLayer,
  160. supports: module.supports,
  161. media: module.media,
  162. inheritance: module.inheritance,
  163. chain
  164. });
  165. return chain;
  166. };
  167. /**
  168. * Locate the public-path placeholders in a materialized module source.
  169. * @param {string} content materialized module source
  170. * @returns {PublicPathPlaceholderPlan} placeholder offsets
  171. */
  172. const computePublicPathPlaceholderPlan = (content) => {
  173. /** @type {number[]} */
  174. const autos = [];
  175. const autoLen = PUBLIC_PATH_AUTO.length;
  176. for (
  177. let idx = content.indexOf(PUBLIC_PATH_AUTO);
  178. idx !== -1;
  179. idx = content.indexOf(PUBLIC_PATH_AUTO, idx + autoLen)
  180. ) {
  181. autos.push(idx);
  182. }
  183. /** @type {{ start: number, end: number, length: number }[]} */
  184. const hashes = [];
  185. walkFullHashPlaceholders(content, (start, end, length) => {
  186. hashes.push({ start, end, length });
  187. });
  188. return { autos, hashes };
  189. };
  190. /**
  191. * Returns ], definitions: import("../../schemas/WebpackOptions.json")["definitions"] }} schema.
  192. * @param {string} name name
  193. * @returns {{ oneOf: [{ $ref: string }], definitions: import("../../schemas/WebpackOptions.json")["definitions"] }} schema
  194. */
  195. const getSchema = (name) => {
  196. const { definitions } = require("../../schemas/WebpackOptions.json");
  197. return {
  198. definitions,
  199. oneOf: [{ $ref: `#/definitions/${name}` }]
  200. };
  201. };
  202. const parserValidationOptions = {
  203. name: "Css Modules Plugin",
  204. baseDataPath: "parser"
  205. };
  206. const generatorValidationOptions = {
  207. name: "Css Modules Plugin",
  208. baseDataPath: "generator"
  209. };
  210. const PLUGIN_NAME = "CssModulesPlugin";
  211. const createCompilationHooks = () => ({
  212. /**
  213. * @type {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>}
  214. * @since 5.94.0
  215. */
  216. renderModulePackage: new SyncWaterfallHook([
  217. "source",
  218. "module",
  219. "renderContext"
  220. ]),
  221. /**
  222. * @type {SyncHook<[Chunk, Hash, ChunkHashContext]>}
  223. * @since 5.94.0
  224. */
  225. chunkHash: new SyncHook(["chunk", "hash", "context"]),
  226. /**
  227. * Called for each CSS source type (CSS_IMPORT_TYPE, CSS_TYPE) with the chunk's modules pre-sorted by full module name; return an ordered `Module[]` to override the default import-order topological sort, or return `undefined` to keep the default.
  228. * @type {SyncBailHook<[Chunk, Module[], Compilation], Module[] | undefined | void>}
  229. * @since 5.107.0
  230. */
  231. orderModules: new SyncBailHook(["chunk", "modules", "compilation"])
  232. });
  233. /**
  234. * Defines the compilation hooks type used by this module.
  235. * @typedef {ReturnType<typeof createCompilationHooks>} CompilationHooks
  236. */
  237. class CssModulesPlugin {
  238. constructor() {
  239. /** @type {WeakMap<Source, ModuleFactoryCacheEntry>} */
  240. this._moduleFactoryCache = new WeakMap();
  241. }
  242. /**
  243. * Applies the plugin by registering its hooks on the compiler.
  244. * @param {Compiler} compiler the compiler instance
  245. * @returns {void}
  246. */
  247. apply(compiler) {
  248. // `"auto"` marks implicit enablement (no user rule for CSS files) — see
  249. // `applyExperimentsDefaults`. Only then loaders win over the built-in type.
  250. // TODO webpack 6: css defaults to `true`, drop this implicit-only fallback.
  251. const implicitlyEnabled = compiler.options.experiments.css === "auto";
  252. compiler.hooks.compilation.tap(
  253. PLUGIN_NAME,
  254. (compilation, { normalModuleFactory }) => {
  255. if (implicitlyEnabled) {
  256. implicitTypeLoaderFallback(
  257. normalModuleFactory,
  258. PLUGIN_NAME,
  259. /\.css$/i,
  260. CSS_MODULE_TYPE_AUTO
  261. );
  262. }
  263. const hooks = CssModulesPlugin.getCompilationHooks(compilation);
  264. let dependenciesRegistered = false;
  265. // runs when the first css module is prepared, so a build without
  266. // css never loads these dependency classes
  267. const registerDependencies = () => {
  268. // every css type taps this — the registration is shared
  269. if (dependenciesRegistered) return;
  270. dependenciesRegistered = true;
  271. const CssImportDependency = require("../dependencies/CssImportDependency");
  272. const CssUrlDependency = require("../dependencies/CssUrlDependency");
  273. const CssIcssImportDependency = require("../dependencies/CssIcssImportDependency");
  274. const CssIcssExportDependency = require("../dependencies/CssIcssExportDependency");
  275. const CssIcssSymbolDependency = require("../dependencies/CssIcssSymbolDependency");
  276. compilation.dependencyFactories.set(
  277. CssImportDependency,
  278. normalModuleFactory
  279. );
  280. compilation.dependencyTemplates.set(
  281. CssImportDependency,
  282. new CssImportDependency.Template()
  283. );
  284. compilation.dependencyFactories.set(
  285. CssUrlDependency,
  286. normalModuleFactory
  287. );
  288. compilation.dependencyTemplates.set(
  289. CssUrlDependency,
  290. new CssUrlDependency.Template()
  291. );
  292. compilation.dependencyFactories.set(
  293. CssIcssImportDependency,
  294. normalModuleFactory
  295. );
  296. compilation.dependencyTemplates.set(
  297. CssIcssImportDependency,
  298. new CssIcssImportDependency.Template()
  299. );
  300. compilation.dependencyTemplates.set(
  301. CssIcssExportDependency,
  302. new CssIcssExportDependency.Template()
  303. );
  304. compilation.dependencyTemplates.set(
  305. CssIcssSymbolDependency,
  306. new CssIcssSymbolDependency.Template()
  307. );
  308. };
  309. for (const type of CSS_MODULE_TYPES) {
  310. normalModuleFactory.hooks.prepareModuleType
  311. .for(type)
  312. .tap(PLUGIN_NAME, registerDependencies);
  313. }
  314. compilation.dependencyTemplates.set(
  315. StaticExportsDependency,
  316. new StaticExportsDependency.Template()
  317. );
  318. preloadModuleType(
  319. normalModuleFactory,
  320. PLUGIN_NAME,
  321. CSS_MODULE_TYPES.map((type) => [
  322. type,
  323. [getCssParser, getCssGenerator]
  324. ])
  325. );
  326. for (const type of CSS_MODULE_TYPES) {
  327. normalModuleFactory.hooks.createParser
  328. .for(type)
  329. .tap(PLUGIN_NAME, (parserOptions) => {
  330. /** @type {undefined | "global" | "local" | "auto"} */
  331. let defaultMode;
  332. switch (type) {
  333. case CSS_MODULE_TYPE: {
  334. compiler.validate(
  335. () => getSchema("CssParserOptions"),
  336. parserOptions,
  337. parserValidationOptions,
  338. (options) =>
  339. require("../../schemas/plugins/css/CssParserOptions.check")(
  340. options
  341. )
  342. );
  343. break;
  344. }
  345. case CSS_MODULE_TYPE_GLOBAL: {
  346. defaultMode = "global";
  347. compiler.validate(
  348. () => getSchema("CssModuleParserOptions"),
  349. parserOptions,
  350. parserValidationOptions,
  351. (options) =>
  352. require("../../schemas/plugins/css/CssModuleParserOptions.check")(
  353. options
  354. )
  355. );
  356. break;
  357. }
  358. case CSS_MODULE_TYPE_MODULE: {
  359. defaultMode = "local";
  360. compiler.validate(
  361. () => getSchema("CssAutoOrModuleParserOptions"),
  362. parserOptions,
  363. parserValidationOptions,
  364. (options) =>
  365. require("../../schemas/plugins/css/CssAutoOrModuleParserOptions.check")(
  366. options
  367. )
  368. );
  369. break;
  370. }
  371. case CSS_MODULE_TYPE_AUTO: {
  372. defaultMode = "auto";
  373. compiler.validate(
  374. () => getSchema("CssAutoOrModuleParserOptions"),
  375. parserOptions,
  376. parserValidationOptions,
  377. (options) =>
  378. require("../../schemas/plugins/css/CssAutoOrModuleParserOptions.check")(
  379. options
  380. )
  381. );
  382. break;
  383. }
  384. }
  385. return new (getCssParser.loaded())({
  386. defaultMode,
  387. ...parserOptions
  388. });
  389. });
  390. normalModuleFactory.hooks.createGenerator
  391. .for(type)
  392. .tap(PLUGIN_NAME, (generatorOptions) => {
  393. switch (type) {
  394. case CSS_MODULE_TYPE: {
  395. compiler.validate(
  396. () => getSchema("CssGeneratorOptions"),
  397. generatorOptions,
  398. generatorValidationOptions,
  399. (options) =>
  400. require("../../schemas/plugins/css/CssGeneratorOptions.check")(
  401. options
  402. )
  403. );
  404. break;
  405. }
  406. case CSS_MODULE_TYPE_GLOBAL: {
  407. compiler.validate(
  408. () => getSchema("CssModuleGeneratorOptions"),
  409. generatorOptions,
  410. generatorValidationOptions,
  411. (options) =>
  412. require("../../schemas/plugins/css/CssModuleGeneratorOptions.check")(
  413. options
  414. )
  415. );
  416. break;
  417. }
  418. case CSS_MODULE_TYPE_MODULE: {
  419. compiler.validate(
  420. () => getSchema("CssModuleGeneratorOptions"),
  421. generatorOptions,
  422. generatorValidationOptions,
  423. (options) =>
  424. require("../../schemas/plugins/css/CssModuleGeneratorOptions.check")(
  425. options
  426. )
  427. );
  428. break;
  429. }
  430. case CSS_MODULE_TYPE_AUTO: {
  431. compiler.validate(
  432. () => getSchema("CssModuleGeneratorOptions"),
  433. generatorOptions,
  434. generatorValidationOptions,
  435. (options) =>
  436. require("../../schemas/plugins/css/CssModuleGeneratorOptions.check")(
  437. options
  438. )
  439. );
  440. break;
  441. }
  442. }
  443. return new (getCssGenerator.loaded())(
  444. generatorOptions,
  445. compilation.moduleGraph
  446. );
  447. });
  448. normalModuleFactory.hooks.createModuleClass
  449. .for(type)
  450. .tap(PLUGIN_NAME, (createData, resolveData) => {
  451. const exportType =
  452. /** @type {CssParser} */
  453. (createData.parser).options.exportType;
  454. // When CSS is imported from CSS there is only one dependency
  455. const dependency =
  456. resolveData.dependencies.length > 0
  457. ? resolveData.dependencies[0]
  458. : undefined;
  459. if (dependency instanceof getCssImportDependency()) {
  460. return new CssModule(
  461. /** @type {CssModuleCreateData} */
  462. ({
  463. ...createData,
  464. cssLayer: dependency.layer,
  465. supports: dependency.supports,
  466. media: dependency.media,
  467. inheritance: dependency.inheritance,
  468. exportType: dependency.exportType || exportType
  469. })
  470. );
  471. }
  472. return new CssModule(
  473. /** @type {CssModuleCreateData} */
  474. (
  475. /** @type {unknown} */ ({
  476. ...createData,
  477. exportType
  478. })
  479. )
  480. );
  481. });
  482. NormalModule.getCompilationHooks(compilation).processResult.tap(
  483. PLUGIN_NAME,
  484. (result, module) => {
  485. if (module.type === type) {
  486. const [source, ...rest] = result;
  487. return [removeBOM(source), ...rest];
  488. }
  489. return result;
  490. }
  491. );
  492. }
  493. JavascriptModulesPlugin.getCompilationHooks(
  494. compilation
  495. ).renderModuleContent.tap(PLUGIN_NAME, (source, module, ctx) => {
  496. const injectCssStylesVar =
  497. module instanceof ConcatenatedModule &&
  498. module.modules.find(
  499. (m) =>
  500. m instanceof CssModule &&
  501. m.exportType === "style" &&
  502. !(/** @type {CssGenerator} */ (m.generator)._exportsOnly)
  503. );
  504. const injectHMRCode =
  505. (module instanceof CssModule && module.hot) ||
  506. (module instanceof ConcatenatedModule &&
  507. module.rootModule instanceof CssModule &&
  508. module.rootModule.hot);
  509. if (injectCssStylesVar) {
  510. source = new ConcatSource(
  511. "var __webpack_css_styles__ = [];",
  512. "\n",
  513. source
  514. );
  515. }
  516. if (injectHMRCode) {
  517. const currentModule = /** @type {CssModule} */ (
  518. module instanceof ConcatenatedModule ? module.rootModule : module
  519. );
  520. const exportType = currentModule.exportType || "link";
  521. // When exportType !== "link", modules behave like JavaScript modules
  522. if (["link", "style"].includes(exportType)) {
  523. // For exportType === "link", we can optimize with self-acceptance
  524. const cssData = /** @type {CssModuleBuildInfo} */ (
  525. module.buildInfo
  526. ).cssData;
  527. if (!cssData) {
  528. return source;
  529. }
  530. const exports = cssData.exports;
  531. /** @type {Record<string, string>} */
  532. const exportsObj = {};
  533. for (const [key, value] of exports) {
  534. exportsObj[key] = value;
  535. }
  536. const stringifiedExports = JSON.stringify(
  537. JSON.stringify(exportsObj)
  538. );
  539. const hmrCode = Template.asString([
  540. "",
  541. `var __webpack_css_exports__ = ${stringifiedExports};`,
  542. "// only invalidate when locals change",
  543. `if (${ctx.runtimeTemplate.optionalChaining(
  544. "module.hot.data",
  545. "__webpack_css_exports__"
  546. )} && module.hot.data.__webpack_css_exports__ != __webpack_css_exports__) {`,
  547. Template.indent("module.hot.invalidate();"),
  548. "} else {",
  549. Template.indent("module.hot.accept();"),
  550. "}",
  551. "module.hot.dispose(function(data) {",
  552. Template.indent([
  553. "data.__webpack_css_exports__ = __webpack_css_exports__;"
  554. ]),
  555. "});"
  556. ]);
  557. source = new ConcatSource(source, "\n", new RawSource(hmrCode));
  558. }
  559. }
  560. if (injectCssStylesVar) {
  561. /** @type {ConcatSource} */
  562. (source).add(
  563. "for (let i = 0; i < __webpack_css_styles__.length; i++) {\n" +
  564. `${RuntimeGlobals.cssInjectStyle}(__webpack_css_styles__[i][0], __webpack_css_styles__[i][1]);\n` +
  565. "}"
  566. );
  567. }
  568. return source;
  569. });
  570. /** @type {WeakMap<Chunk, CssModule[]>} */
  571. const orderedCssModulesPerChunk = new WeakMap();
  572. compilation.hooks.afterCodeGeneration.tap(PLUGIN_NAME, () => {
  573. const { chunkGraph } = compilation;
  574. for (const chunk of compilation.chunks) {
  575. if (CssModulesPlugin.chunkHasCss(chunk, chunkGraph)) {
  576. orderedCssModulesPerChunk.set(
  577. chunk,
  578. this.getOrderedChunkCssModules(chunk, chunkGraph, compilation)
  579. );
  580. }
  581. }
  582. });
  583. compilation.hooks.chunkHash.tap(PLUGIN_NAME, (chunk, hash, context) => {
  584. hooks.chunkHash.call(chunk, hash, context);
  585. });
  586. compilation.hooks.contentHash.tap(PLUGIN_NAME, (chunk) => {
  587. const {
  588. chunkGraph,
  589. moduleGraph,
  590. runtimeTemplate,
  591. outputOptions: {
  592. hashSalt,
  593. hashDigest,
  594. hashDigestLength,
  595. hashFunction
  596. }
  597. } = compilation;
  598. const hash = createHash(hashFunction);
  599. if (hashSalt) hash.update(hashSalt);
  600. const codeGenerationResults =
  601. /** @type {CodeGenerationResults} */
  602. (compilation.codeGenerationResults);
  603. hooks.chunkHash.call(chunk, hash, {
  604. chunkGraph,
  605. codeGenerationResults,
  606. moduleGraph,
  607. runtimeTemplate
  608. });
  609. const modules = orderedCssModulesPerChunk.get(chunk);
  610. if (modules) {
  611. for (const module of modules) {
  612. hash.update(chunkGraph.getModuleHash(module, chunk.runtime));
  613. }
  614. }
  615. [chunk.contentHash.css, chunk.contentHashFull.css] =
  616. digestNonNumericOnlyWithFull(hash, hashDigest, hashDigestLength);
  617. });
  618. compilation.hooks.renderManifest.tap(PLUGIN_NAME, (result, options) => {
  619. const { chunkGraph } = compilation;
  620. const { hash, chunk, codeGenerationResults, runtimeTemplate } =
  621. options;
  622. if (chunk instanceof HotUpdateChunk) return result;
  623. /** @type {CssModule[] | undefined} */
  624. const modules = orderedCssModulesPerChunk.get(chunk);
  625. if (modules !== undefined) {
  626. const { path: filename, info } = compilation.getPathWithInfo(
  627. CssModulesPlugin.getChunkFilenameTemplate(
  628. chunk,
  629. compilation.outputOptions
  630. ),
  631. {
  632. hash,
  633. runtime: chunk.runtime,
  634. chunk,
  635. contentHashType: "css"
  636. }
  637. );
  638. const undoPath = getUndoPath(
  639. filename,
  640. compilation.outputOptions.path,
  641. false
  642. );
  643. result.push({
  644. render: () =>
  645. this.renderChunk(
  646. {
  647. chunk,
  648. chunkGraph,
  649. codeGenerationResults,
  650. uniqueName: compilation.outputOptions.uniqueName,
  651. undoPath,
  652. hash,
  653. modules,
  654. runtimeTemplate
  655. },
  656. hooks
  657. ),
  658. filename,
  659. info,
  660. identifier: `css${chunk.id}`,
  661. hash: chunk.contentHash.css
  662. });
  663. }
  664. return result;
  665. });
  666. const globalChunkLoading = compilation.outputOptions.chunkLoading;
  667. /**
  668. * Checks whether this css modules plugin is enabled for chunk.
  669. * @param {Chunk} chunk the chunk
  670. * @returns {boolean} true, when enabled
  671. */
  672. const isEnabledForChunk = (chunk) => {
  673. const options = chunk.getEntryOptions();
  674. const chunkLoading =
  675. options && options.chunkLoading !== undefined
  676. ? options.chunkLoading
  677. : globalChunkLoading;
  678. return chunkLoading === "jsonp" || chunkLoading === "import";
  679. };
  680. /**
  681. * The neutral platform's no-DOM branch stores styles on the global.
  682. * @param {RuntimeRequirements} set runtime requirements
  683. */
  684. const addNoDomStyleRegistry = (set) => {
  685. if (
  686. compilation.runtimeTemplate.isNeutralPlatform() &&
  687. !compilation.outputOptions.environment.globalThis
  688. ) {
  689. set.add(RuntimeGlobals.global);
  690. }
  691. };
  692. /**
  693. * Whether a reachable chunk carries css, which is what the loading branch is
  694. * rendered from — a css module in the graph is not enough.
  695. * @param {Chunk} chunk the chunk
  696. * @param {ChunkGraph} chunkGraph the chunk graph
  697. * @returns {boolean} true, when there is a stylesheet to load
  698. */
  699. const hasCssToLoad = (chunk, chunkGraph) => {
  700. for (const referenced of chunk.getAllReferencedChunks()) {
  701. if (CssModulesPlugin.chunkHasCss(referenced, chunkGraph)) {
  702. return true;
  703. }
  704. }
  705. return false;
  706. };
  707. /** @type {WeakSet<Chunk>} */
  708. const onceForChunkSet = new WeakSet();
  709. /**
  710. * Handles the hook callback for this code path.
  711. * @param {Chunk} chunk chunk to check
  712. * @param {RuntimeRequirements} set runtime requirements
  713. */
  714. const handler = (chunk, set) => {
  715. if (onceForChunkSet.has(chunk)) return;
  716. onceForChunkSet.add(chunk);
  717. if (!isEnabledForChunk(chunk)) return;
  718. compilation.addLazyRuntimeModule(
  719. chunk,
  720. getCssLoadingRuntimeModule,
  721. (CssLoadingRuntimeModule) => new CssLoadingRuntimeModule(set)
  722. );
  723. };
  724. compilation.hooks.runtimeRequirementInTree
  725. .for(RuntimeGlobals.hasCssModules)
  726. .tap(PLUGIN_NAME, handler);
  727. compilation.hooks.runtimeRequirementInTree
  728. .for(RuntimeGlobals.ensureChunkHandlers)
  729. .tap(PLUGIN_NAME, (chunk, set, { chunkGraph }) => {
  730. if (!isEnabledForChunk(chunk)) return;
  731. if (!hasCssToLoad(chunk, chunkGraph)) return;
  732. set.add(RuntimeGlobals.hasOwnProperty);
  733. // A baked url carries where the stylesheet is, so neither the public
  734. // path nor the name lookup is read for it. Asked exactly as the
  735. // loading runtime module asks, so the two always agree.
  736. if (
  737. compilation.runtimeTemplate.analyzableCssChunkUrls(
  738. chunk,
  739. chunkGraph,
  740. set
  741. ) === null
  742. ) {
  743. set.add(RuntimeGlobals.publicPath);
  744. set.add(RuntimeGlobals.getChunkCssFilename);
  745. }
  746. // Asked here rather than for `hasCssModules`: the loading runtime
  747. // module renders nothing without loading or hmr, so declaring it
  748. // there ships the polyfill to a build that never reads it.
  749. addNoDomStyleRegistry(set);
  750. // A chunk whose only stylesheet is an `@import` external has no css
  751. // module, so `hasCssModules` never asks for the loading runtime.
  752. handler(chunk, set);
  753. });
  754. compilation.hooks.runtimeRequirementInTree
  755. .for(RuntimeGlobals.hmrDownloadUpdateHandlers)
  756. .tap(PLUGIN_NAME, (chunk, set, { chunkGraph }) => {
  757. if (!isEnabledForChunk(chunk)) return;
  758. if (
  759. !chunkGraph.hasModuleInGraph(
  760. chunk,
  761. (m) =>
  762. m.type === CSS_MODULE_TYPE ||
  763. m.type === CSS_MODULE_TYPE_GLOBAL ||
  764. m.type === CSS_MODULE_TYPE_MODULE ||
  765. m.type === CSS_MODULE_TYPE_AUTO
  766. )
  767. ) {
  768. return;
  769. }
  770. set.add(RuntimeGlobals.publicPath);
  771. set.add(RuntimeGlobals.getChunkCssFilename);
  772. addNoDomStyleRegistry(set);
  773. });
  774. compilation.hooks.runtimeRequirementInTree
  775. .for(RuntimeGlobals.cssInjectStyle)
  776. .tap(PLUGIN_NAME, (chunk, set) => {
  777. // Same as above: namespace stub is enough.
  778. set.add(RuntimeGlobals.requireScope);
  779. addNoDomStyleRegistry(set);
  780. compilation.addLazyRuntimeModule(
  781. chunk,
  782. getCssInjectStyleRuntimeModule,
  783. (CssInjectStyleRuntimeModule) =>
  784. new CssInjectStyleRuntimeModule(set)
  785. );
  786. });
  787. }
  788. );
  789. }
  790. /**
  791. * Gets modules in order.
  792. * @param {Chunk} chunk chunk
  793. * @param {Iterable<Module> | undefined} modules unordered modules
  794. * @param {Compilation} compilation compilation
  795. * @returns {Module[]} ordered modules
  796. */
  797. getModulesInOrder(chunk, modules, compilation) {
  798. if (!modules) return [];
  799. /** @type {Module[]} */
  800. const modulesList = [...modules];
  801. // Get ordered list of modules per chunk group
  802. // Lists are in reverse order to allow to use Array.pop()
  803. const modulesByChunkGroup = Array.from(
  804. chunk.groupsIterable,
  805. (chunkGroup) => {
  806. const sortedModules = modulesList
  807. .map((module) => ({
  808. module,
  809. index: chunkGroup.getModulePostOrderIndex(module)
  810. }))
  811. .filter((item) => item.index !== undefined)
  812. .sort(
  813. (a, b) =>
  814. /** @type {number} */ (b.index) - /** @type {number} */ (a.index)
  815. )
  816. .map((item) => item.module);
  817. return { list: sortedModules, set: new Set(sortedModules) };
  818. }
  819. );
  820. if (modulesByChunkGroup.length === 1) {
  821. return modulesByChunkGroup[0].list.reverse();
  822. }
  823. const boundCompareModulesByFullName = compareModulesByFullName(
  824. compilation.compiler
  825. );
  826. /**
  827. * Compares module lists.
  828. * @param {{ list: Module[] }} a a
  829. * @param {{ list: Module[] }} b b
  830. * @returns {-1 | 0 | 1} result
  831. */
  832. const compareModuleLists = ({ list: a }, { list: b }) => {
  833. if (a.length === 0) {
  834. return b.length === 0 ? 0 : 1;
  835. }
  836. if (b.length === 0) return -1;
  837. return boundCompareModulesByFullName(a[a.length - 1], b[b.length - 1]);
  838. };
  839. modulesByChunkGroup.sort(compareModuleLists);
  840. /** @type {Module[]} */
  841. const finalModules = [];
  842. for (;;) {
  843. /** @type {Set<Module>} */
  844. const failedModules = new Set();
  845. const list = modulesByChunkGroup[0].list;
  846. if (list.length === 0) {
  847. // done, everything empty
  848. break;
  849. }
  850. /** @type {Module} */
  851. let selectedModule = list[list.length - 1];
  852. /** @type {undefined | false | Module} */
  853. let hasFailed;
  854. outer: for (;;) {
  855. for (const { list, set } of modulesByChunkGroup) {
  856. if (list.length === 0) continue;
  857. const lastModule = list[list.length - 1];
  858. if (lastModule === selectedModule) continue;
  859. if (!set.has(selectedModule)) continue;
  860. failedModules.add(selectedModule);
  861. if (failedModules.has(lastModule)) {
  862. // There is a conflict, try other alternatives
  863. hasFailed = lastModule;
  864. continue;
  865. }
  866. selectedModule = lastModule;
  867. hasFailed = false;
  868. continue outer; // restart
  869. }
  870. break;
  871. }
  872. if (hasFailed) {
  873. const fallbackModule = /** @type {Module} */ (hasFailed);
  874. const fallbackIssuers = [
  875. ...compilation.moduleGraph
  876. .getIncomingConnectionsByOriginModule(fallbackModule)
  877. .keys()
  878. ].filter(Boolean);
  879. const selectedIssuers = [
  880. ...compilation.moduleGraph
  881. .getIncomingConnectionsByOriginModule(selectedModule)
  882. .keys()
  883. ].filter(Boolean);
  884. const allIssuers = [
  885. ...new Set([...fallbackIssuers, ...selectedIssuers])
  886. ]
  887. .map((m) =>
  888. /** @type {Module} */ (m).readableIdentifier(
  889. compilation.requestShortener
  890. )
  891. )
  892. .sort();
  893. // There is a not resolve-able conflict with the selectedModule
  894. compilation.warnings.push(
  895. new WebpackError(
  896. `chunk ${
  897. chunk.name || chunk.id
  898. }\nConflicting order between ${fallbackModule.readableIdentifier(
  899. compilation.requestShortener
  900. )} and ${selectedModule.readableIdentifier(
  901. compilation.requestShortener
  902. )}\nCSS modules are imported in:\n - ${allIssuers.join("\n - ")}`
  903. )
  904. );
  905. selectedModule = fallbackModule;
  906. }
  907. // Insert the selected module into the final modules list
  908. finalModules.push(selectedModule);
  909. // Remove the selected module from all lists
  910. for (const { list, set } of modulesByChunkGroup) {
  911. const lastModule = list[list.length - 1];
  912. if (lastModule === selectedModule) {
  913. list.pop();
  914. } else if (hasFailed && set.has(selectedModule)) {
  915. const idx = list.indexOf(selectedModule);
  916. if (idx >= 0) list.splice(idx, 1);
  917. }
  918. }
  919. modulesByChunkGroup.sort(compareModuleLists);
  920. }
  921. return finalModules;
  922. }
  923. /**
  924. * Gets ordered chunk css modules.
  925. * @param {Chunk} chunk chunk
  926. * @param {ChunkGraph} chunkGraph chunk graph
  927. * @param {Compilation} compilation compilation
  928. * @returns {CssModule[]} ordered css modules
  929. */
  930. getOrderedChunkCssModules(chunk, chunkGraph, compilation) {
  931. /** @type {string | undefined} */
  932. let charset;
  933. const hooks = CssModulesPlugin.getCompilationHooks(compilation);
  934. /**
  935. * @param {Iterable<Module> | undefined} iter modules pre-sorted by full module name
  936. * @returns {Module[]} ordered modules
  937. */
  938. const orderModules = (iter) => {
  939. const modules = iter ? [...iter] : [];
  940. const result = hooks.orderModules.call(chunk, modules, compilation);
  941. if (result !== undefined) return result;
  942. return this.getModulesInOrder(chunk, modules, compilation);
  943. };
  944. const comparator = compareModulesByFullName(compilation.compiler);
  945. const importModules = orderModules(
  946. chunkGraph.getOrderedChunkModulesIterableBySourceType(
  947. chunk,
  948. CSS_IMPORT_TYPE,
  949. comparator
  950. )
  951. );
  952. const cssModules = orderModules(
  953. chunkGraph.getOrderedChunkModulesIterableBySourceType(
  954. chunk,
  955. CSS_TYPE,
  956. comparator
  957. )
  958. );
  959. for (const module of cssModules) {
  960. if (
  961. typeof (
  962. /** @type {CssModuleBuildInfo} */ (module.buildInfo).charset
  963. ) !== "undefined"
  964. ) {
  965. if (
  966. typeof charset !== "undefined" &&
  967. charset !==
  968. /** @type {CssModuleBuildInfo} */ (module.buildInfo).charset
  969. ) {
  970. const err = new WebpackError(
  971. `Conflicting @charset at-rules detected: the module ${module.readableIdentifier(
  972. compilation.requestShortener
  973. )} (in chunk ${chunk.name || chunk.id}) specifies "${
  974. /** @type {CssModuleBuildInfo} */ (module.buildInfo).charset
  975. }", but "${charset}" was expected, all modules must use the same character set`
  976. );
  977. err.chunk = chunk;
  978. err.module = module;
  979. err.hideStack = true;
  980. compilation.warnings.push(err);
  981. }
  982. if (typeof charset === "undefined") {
  983. charset = /** @type {CssModuleBuildInfo} */ (module.buildInfo)
  984. .charset;
  985. }
  986. }
  987. }
  988. return /** @type {CssModule[]} */ ([...importModules, ...cssModules]);
  989. }
  990. /**
  991. * Renders css module source.
  992. * @param {CssModule} module css module
  993. * @param {ChunkRenderContext} renderContext options object
  994. * @param {CompilationHooks} hooks hooks
  995. * @returns {Source | null} css module source
  996. */
  997. static renderModule(module, renderContext, hooks) {
  998. const { undoPath, hash, moduleFactoryCache, moduleSourceContent } =
  999. renderContext;
  1000. const cacheEntry = moduleFactoryCache.get(moduleSourceContent);
  1001. const inheritance = getModuleInheritance(module);
  1002. /** @type {CachedSource} */
  1003. let source;
  1004. if (
  1005. cacheEntry &&
  1006. cacheEntry.undoPath === undoPath &&
  1007. cacheEntry.hash === hash &&
  1008. // Memoized per module, so identity implies equal entries.
  1009. cacheEntry.inheritance === inheritance
  1010. ) {
  1011. source = cacheEntry.source;
  1012. } else {
  1013. if (!moduleSourceContent) return null;
  1014. let plan = publicPathPlaceholderPlans.get(moduleSourceContent);
  1015. if (plan === undefined) {
  1016. plan = computePublicPathPlaceholderPlan(
  1017. /** @type {string} */ (moduleSourceContent.source())
  1018. );
  1019. publicPathPlaceholderPlans.set(moduleSourceContent, plan);
  1020. }
  1021. /** @type {Source} */
  1022. let moduleSource = moduleSourceContent;
  1023. // Apply placeholder substitutions only when present; the common
  1024. // (no-placeholder) case skips the ReplaceSource wrapper entirely.
  1025. if (plan.autos.length > 0 || (hash && plan.hashes.length > 0)) {
  1026. const replaceSource = new ReplaceSource(moduleSourceContent);
  1027. const autoLen = PUBLIC_PATH_AUTO.length;
  1028. for (let i = 0; i < plan.autos.length; i++) {
  1029. const start = plan.autos[i];
  1030. replaceSource.replace(start, start + autoLen - 1, undoPath);
  1031. }
  1032. if (hash) {
  1033. for (let i = 0; i < plan.hashes.length; i++) {
  1034. const { start, end, length } = plan.hashes[i];
  1035. // `end` is exclusive; ReplaceSource.replace takes an inclusive end.
  1036. replaceSource.replace(
  1037. start,
  1038. end - 1,
  1039. length === 0 ? hash : hash.slice(0, length)
  1040. );
  1041. }
  1042. }
  1043. moduleSource = replaceSource;
  1044. }
  1045. for (let i = 0; i < inheritance.length; i++) {
  1046. const layer = inheritance[i][0];
  1047. const supports = inheritance[i][1];
  1048. const media = inheritance[i][2];
  1049. if (media) {
  1050. moduleSource = new ConcatSource(
  1051. `@media ${media} {\n`,
  1052. new PrefixSource("\t", moduleSource),
  1053. "}\n"
  1054. );
  1055. }
  1056. if (supports) {
  1057. moduleSource = new ConcatSource(
  1058. `@supports (${supports}) {\n`,
  1059. new PrefixSource("\t", moduleSource),
  1060. "}\n"
  1061. );
  1062. }
  1063. // Layer can be anonymous
  1064. if (layer !== undefined && layer !== null) {
  1065. moduleSource = new ConcatSource(
  1066. `@layer${layer ? ` ${layer}` : ""} {\n`,
  1067. new PrefixSource("\t", moduleSource),
  1068. "}\n"
  1069. );
  1070. }
  1071. }
  1072. if (moduleSource) {
  1073. moduleSource = new ConcatSource(moduleSource, "\n");
  1074. }
  1075. source = new CachedSource(moduleSource);
  1076. moduleFactoryCache.set(moduleSourceContent, {
  1077. inheritance,
  1078. undoPath,
  1079. hash,
  1080. source
  1081. });
  1082. }
  1083. return tryRunOrWebpackError(
  1084. () => hooks.renderModulePackage.call(source, module, renderContext),
  1085. "CssModulesPlugin.getCompilationHooks().renderModulePackage"
  1086. );
  1087. }
  1088. /**
  1089. * Renders generated source.
  1090. * @param {RenderContext} renderContext the render context
  1091. * @param {CompilationHooks} hooks hooks
  1092. * @returns {Source} generated source
  1093. */
  1094. renderChunk(
  1095. {
  1096. undoPath,
  1097. chunk,
  1098. codeGenerationResults,
  1099. modules,
  1100. runtimeTemplate,
  1101. chunkGraph,
  1102. hash
  1103. },
  1104. hooks
  1105. ) {
  1106. const source = new ConcatSource();
  1107. /** @type {string | undefined} */
  1108. let charset;
  1109. for (const module of modules) {
  1110. if (
  1111. typeof (
  1112. /** @type {CssModuleBuildInfo} */ (module.buildInfo).charset
  1113. ) !== "undefined" &&
  1114. typeof charset === "undefined"
  1115. ) {
  1116. charset = /** @type {CssModuleBuildInfo} */ (module.buildInfo).charset;
  1117. }
  1118. try {
  1119. const codeGenResult = codeGenerationResults.get(module, chunk.runtime);
  1120. const moduleSourceContent =
  1121. /** @type {Source} */
  1122. (
  1123. codeGenResult.sources.get(CSS_TYPE) ||
  1124. codeGenResult.sources.get(CSS_IMPORT_TYPE)
  1125. );
  1126. const moduleSource = CssModulesPlugin.renderModule(
  1127. module,
  1128. {
  1129. undoPath,
  1130. hash,
  1131. chunk,
  1132. chunkGraph,
  1133. codeGenerationResults,
  1134. moduleSourceContent,
  1135. moduleFactoryCache: this._moduleFactoryCache,
  1136. runtimeTemplate
  1137. },
  1138. hooks
  1139. );
  1140. if (moduleSource) {
  1141. source.add(moduleSource);
  1142. }
  1143. } catch (err) {
  1144. /** @type {Error} */
  1145. (err).message += `\nduring rendering of css ${module.identifier()}`;
  1146. throw err;
  1147. }
  1148. }
  1149. chunk.rendered = true;
  1150. if (charset) {
  1151. return new ConcatSource(`@charset "${charset}";\n`, source);
  1152. }
  1153. return source;
  1154. }
  1155. /**
  1156. * Gets chunk filename template.
  1157. * @param {Chunk} chunk chunk
  1158. * @param {OutputOptions} outputOptions output options
  1159. * @returns {ChunkFilenameTemplate} used filename template
  1160. */
  1161. static getChunkFilenameTemplate(chunk, outputOptions) {
  1162. if (chunk.cssFilenameTemplate) {
  1163. return chunk.cssFilenameTemplate;
  1164. } else if (chunk.canBeInitial()) {
  1165. return outputOptions.cssFilename;
  1166. }
  1167. return outputOptions.cssChunkFilename;
  1168. }
  1169. /**
  1170. * Returns true, when the chunk has css.
  1171. * @param {Chunk} chunk chunk
  1172. * @param {ChunkGraph} chunkGraph chunk graph
  1173. * @returns {boolean} true, when the chunk has css
  1174. */
  1175. static chunkHasCss(chunk, chunkGraph) {
  1176. return (
  1177. Boolean(
  1178. chunkGraph.getChunkModulesIterableBySourceType(chunk, CSS_TYPE)
  1179. ) ||
  1180. Boolean(
  1181. chunkGraph.getChunkModulesIterableBySourceType(chunk, CSS_IMPORT_TYPE)
  1182. )
  1183. );
  1184. }
  1185. }
  1186. CssModulesPlugin.getCompilationHooks = createHooksRegistry(
  1187. createCompilationHooks
  1188. );
  1189. module.exports = CssModulesPlugin;