source: imaps-frontend/node_modules/webpack/lib/css/CssModulesPlugin.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 25.8 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const { SyncWaterfallHook, SyncHook } = require("tapable");
9const {
10 ConcatSource,
11 PrefixSource,
12 ReplaceSource,
13 CachedSource,
14 RawSource
15} = require("webpack-sources");
16const Compilation = require("../Compilation");
17const CssModule = require("../CssModule");
18const { tryRunOrWebpackError } = require("../HookWebpackError");
19const HotUpdateChunk = require("../HotUpdateChunk");
20const {
21 CSS_MODULE_TYPE,
22 CSS_MODULE_TYPE_GLOBAL,
23 CSS_MODULE_TYPE_MODULE,
24 CSS_MODULE_TYPE_AUTO
25} = require("../ModuleTypeConstants");
26const RuntimeGlobals = require("../RuntimeGlobals");
27const SelfModuleFactory = require("../SelfModuleFactory");
28const Template = require("../Template");
29const WebpackError = require("../WebpackError");
30const CssIcssExportDependency = require("../dependencies/CssIcssExportDependency");
31const CssIcssImportDependency = require("../dependencies/CssIcssImportDependency");
32const CssIcssSymbolDependency = require("../dependencies/CssIcssSymbolDependency");
33const CssImportDependency = require("../dependencies/CssImportDependency");
34const CssLocalIdentifierDependency = require("../dependencies/CssLocalIdentifierDependency");
35const CssSelfLocalIdentifierDependency = require("../dependencies/CssSelfLocalIdentifierDependency");
36const CssUrlDependency = require("../dependencies/CssUrlDependency");
37const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
38const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin");
39const { compareModulesByIdentifier } = require("../util/comparators");
40const createSchemaValidation = require("../util/create-schema-validation");
41const createHash = require("../util/createHash");
42const { getUndoPath } = require("../util/identifier");
43const memoize = require("../util/memoize");
44const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
45const CssGenerator = require("./CssGenerator");
46const CssParser = require("./CssParser");
47
48/** @typedef {import("webpack-sources").Source} Source */
49/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputOptions */
50/** @typedef {import("../Chunk")} Chunk */
51/** @typedef {import("../ChunkGraph")} ChunkGraph */
52/** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
53/** @typedef {import("../Compilation").ChunkHashContext} ChunkHashContext */
54/** @typedef {import("../Compiler")} Compiler */
55/** @typedef {import("../CssModule").Inheritance} Inheritance */
56/** @typedef {import("../Module")} Module */
57/** @typedef {import("../Template").RuntimeTemplate} RuntimeTemplate */
58/** @typedef {import("../TemplatedPathPlugin").TemplatePath} TemplatePath */
59/** @typedef {import("../util/Hash")} Hash */
60/** @typedef {import("../util/createHash").Algorithm} Algorithm */
61/** @typedef {import("../util/memoize")} Memoize */
62
63/**
64 * @typedef {object} RenderContext
65 * @property {Chunk} chunk the chunk
66 * @property {ChunkGraph} chunkGraph the chunk graph
67 * @property {CodeGenerationResults} codeGenerationResults results of code generation
68 * @property {RuntimeTemplate} runtimeTemplate the runtime template
69 * @property {string} uniqueName the unique name
70 * @property {string} undoPath undo path to css file
71 * @property {CssModule[]} modules modules
72 */
73
74/**
75 * @typedef {object} ChunkRenderContext
76 * @property {Chunk} chunk the chunk
77 * @property {ChunkGraph} chunkGraph the chunk graph
78 * @property {CodeGenerationResults} codeGenerationResults results of code generation
79 * @property {RuntimeTemplate} runtimeTemplate the runtime template
80 * @property {string} undoPath undo path to css file
81 */
82
83/**
84 * @typedef {object} CompilationHooks
85 * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModulePackage
86 * @property {SyncHook<[Chunk, Hash, ChunkHashContext]>} chunkHash
87 */
88
89const getCssLoadingRuntimeModule = memoize(() =>
90 require("./CssLoadingRuntimeModule")
91);
92
93/**
94 * @param {string} name name
95 * @returns {{oneOf: [{$ref: string}], definitions: *}} schema
96 */
97const getSchema = name => {
98 const { definitions } = require("../../schemas/WebpackOptions.json");
99 return {
100 definitions,
101 oneOf: [{ $ref: `#/definitions/${name}` }]
102 };
103};
104
105const generatorValidationOptions = {
106 name: "Css Modules Plugin",
107 baseDataPath: "generator"
108};
109const validateGeneratorOptions = {
110 css: createSchemaValidation(
111 require("../../schemas/plugins/css/CssGeneratorOptions.check.js"),
112 () => getSchema("CssGeneratorOptions"),
113 generatorValidationOptions
114 ),
115 "css/auto": createSchemaValidation(
116 require("../../schemas/plugins/css/CssAutoGeneratorOptions.check.js"),
117 () => getSchema("CssAutoGeneratorOptions"),
118 generatorValidationOptions
119 ),
120 "css/module": createSchemaValidation(
121 require("../../schemas/plugins/css/CssModuleGeneratorOptions.check.js"),
122 () => getSchema("CssModuleGeneratorOptions"),
123 generatorValidationOptions
124 ),
125 "css/global": createSchemaValidation(
126 require("../../schemas/plugins/css/CssGlobalGeneratorOptions.check.js"),
127 () => getSchema("CssGlobalGeneratorOptions"),
128 generatorValidationOptions
129 )
130};
131
132const parserValidationOptions = {
133 name: "Css Modules Plugin",
134 baseDataPath: "parser"
135};
136const validateParserOptions = {
137 css: createSchemaValidation(
138 require("../../schemas/plugins/css/CssParserOptions.check.js"),
139 () => getSchema("CssParserOptions"),
140 parserValidationOptions
141 ),
142 "css/auto": createSchemaValidation(
143 require("../../schemas/plugins/css/CssAutoParserOptions.check.js"),
144 () => getSchema("CssAutoParserOptions"),
145 parserValidationOptions
146 ),
147 "css/module": createSchemaValidation(
148 require("../../schemas/plugins/css/CssModuleParserOptions.check.js"),
149 () => getSchema("CssModuleParserOptions"),
150 parserValidationOptions
151 ),
152 "css/global": createSchemaValidation(
153 require("../../schemas/plugins/css/CssGlobalParserOptions.check.js"),
154 () => getSchema("CssGlobalParserOptions"),
155 parserValidationOptions
156 )
157};
158
159/** @type {WeakMap<Compilation, CompilationHooks>} */
160const compilationHooksMap = new WeakMap();
161
162const PLUGIN_NAME = "CssModulesPlugin";
163
164class CssModulesPlugin {
165 /**
166 * @param {Compilation} compilation the compilation
167 * @returns {CompilationHooks} the attached hooks
168 */
169 static getCompilationHooks(compilation) {
170 if (!(compilation instanceof Compilation)) {
171 throw new TypeError(
172 "The 'compilation' argument must be an instance of Compilation"
173 );
174 }
175 let hooks = compilationHooksMap.get(compilation);
176 if (hooks === undefined) {
177 hooks = {
178 renderModulePackage: new SyncWaterfallHook([
179 "source",
180 "module",
181 "renderContext"
182 ]),
183 chunkHash: new SyncHook(["chunk", "hash", "context"])
184 };
185 compilationHooksMap.set(compilation, hooks);
186 }
187 return hooks;
188 }
189
190 constructor() {
191 /** @type {WeakMap<Source, { undoPath: string, inheritance: Inheritance, source: CachedSource }>} */
192 this._moduleFactoryCache = new WeakMap();
193 }
194
195 /**
196 * Apply the plugin
197 * @param {Compiler} compiler the compiler instance
198 * @returns {void}
199 */
200 apply(compiler) {
201 compiler.hooks.compilation.tap(
202 PLUGIN_NAME,
203 (compilation, { normalModuleFactory }) => {
204 const hooks = CssModulesPlugin.getCompilationHooks(compilation);
205 const selfFactory = new SelfModuleFactory(compilation.moduleGraph);
206 compilation.dependencyFactories.set(
207 CssImportDependency,
208 normalModuleFactory
209 );
210 compilation.dependencyTemplates.set(
211 CssImportDependency,
212 new CssImportDependency.Template()
213 );
214 compilation.dependencyFactories.set(
215 CssUrlDependency,
216 normalModuleFactory
217 );
218 compilation.dependencyTemplates.set(
219 CssUrlDependency,
220 new CssUrlDependency.Template()
221 );
222 compilation.dependencyTemplates.set(
223 CssLocalIdentifierDependency,
224 new CssLocalIdentifierDependency.Template()
225 );
226 compilation.dependencyFactories.set(
227 CssSelfLocalIdentifierDependency,
228 selfFactory
229 );
230 compilation.dependencyTemplates.set(
231 CssSelfLocalIdentifierDependency,
232 new CssSelfLocalIdentifierDependency.Template()
233 );
234 compilation.dependencyFactories.set(
235 CssIcssImportDependency,
236 normalModuleFactory
237 );
238 compilation.dependencyTemplates.set(
239 CssIcssImportDependency,
240 new CssIcssImportDependency.Template()
241 );
242 compilation.dependencyTemplates.set(
243 CssIcssExportDependency,
244 new CssIcssExportDependency.Template()
245 );
246 compilation.dependencyTemplates.set(
247 CssIcssSymbolDependency,
248 new CssIcssSymbolDependency.Template()
249 );
250 compilation.dependencyTemplates.set(
251 StaticExportsDependency,
252 new StaticExportsDependency.Template()
253 );
254 for (const type of [
255 CSS_MODULE_TYPE,
256 CSS_MODULE_TYPE_GLOBAL,
257 CSS_MODULE_TYPE_MODULE,
258 CSS_MODULE_TYPE_AUTO
259 ]) {
260 normalModuleFactory.hooks.createParser
261 .for(type)
262 .tap(PLUGIN_NAME, parserOptions => {
263 validateParserOptions[type](parserOptions);
264 const { url, import: importOption, namedExports } = parserOptions;
265
266 switch (type) {
267 case CSS_MODULE_TYPE:
268 return new CssParser({
269 importOption,
270 url,
271 namedExports
272 });
273 case CSS_MODULE_TYPE_GLOBAL:
274 return new CssParser({
275 defaultMode: "global",
276 importOption,
277 url,
278 namedExports
279 });
280 case CSS_MODULE_TYPE_MODULE:
281 return new CssParser({
282 defaultMode: "local",
283 importOption,
284 url,
285 namedExports
286 });
287 case CSS_MODULE_TYPE_AUTO:
288 return new CssParser({
289 defaultMode: "auto",
290 importOption,
291 url,
292 namedExports
293 });
294 }
295 });
296 normalModuleFactory.hooks.createGenerator
297 .for(type)
298 .tap(PLUGIN_NAME, generatorOptions => {
299 validateGeneratorOptions[type](generatorOptions);
300
301 return new CssGenerator(generatorOptions);
302 });
303 normalModuleFactory.hooks.createModuleClass
304 .for(type)
305 .tap(PLUGIN_NAME, (createData, resolveData) => {
306 if (resolveData.dependencies.length > 0) {
307 // When CSS is imported from CSS there is only one dependency
308 const dependency = resolveData.dependencies[0];
309
310 if (dependency instanceof CssImportDependency) {
311 const parent =
312 /** @type {CssModule} */
313 (compilation.moduleGraph.getParentModule(dependency));
314
315 if (parent instanceof CssModule) {
316 /** @type {import("../CssModule").Inheritance | undefined} */
317 let inheritance;
318
319 if (
320 parent.cssLayer !== undefined ||
321 parent.supports ||
322 parent.media
323 ) {
324 if (!inheritance) {
325 inheritance = [];
326 }
327
328 inheritance.push([
329 parent.cssLayer,
330 parent.supports,
331 parent.media
332 ]);
333 }
334
335 if (parent.inheritance) {
336 if (!inheritance) {
337 inheritance = [];
338 }
339
340 inheritance.push(...parent.inheritance);
341 }
342
343 return new CssModule({
344 ...createData,
345 cssLayer: dependency.layer,
346 supports: dependency.supports,
347 media: dependency.media,
348 inheritance
349 });
350 }
351
352 return new CssModule({
353 ...createData,
354 cssLayer: dependency.layer,
355 supports: dependency.supports,
356 media: dependency.media
357 });
358 }
359 }
360
361 return new CssModule(createData);
362 });
363 }
364
365 JavascriptModulesPlugin.getCompilationHooks(
366 compilation
367 ).renderModuleContent.tap(PLUGIN_NAME, (source, module) => {
368 if (module instanceof CssModule && module.hot) {
369 const exports = module.buildInfo.cssData.exports;
370 const stringifiedExports = JSON.stringify(
371 JSON.stringify(
372 Array.from(exports).reduce((obj, [key, value]) => {
373 obj[key] = value;
374 return obj;
375 }, {})
376 )
377 );
378
379 const hmrCode = Template.asString([
380 "",
381 `var __webpack_css_exports__ = ${stringifiedExports};`,
382 "// only invalidate when locals change",
383 "if (module.hot.data && module.hot.data.__webpack_css_exports__ && module.hot.data.__webpack_css_exports__ != __webpack_css_exports__) {",
384 Template.indent("module.hot.invalidate();"),
385 "} else {",
386 Template.indent("module.hot.accept();"),
387 "}",
388 "module.hot.dispose(function(data) { data.__webpack_css_exports__ = __webpack_css_exports__; });"
389 ]);
390
391 return new ConcatSource(source, "\n", new RawSource(hmrCode));
392 }
393 });
394 const orderedCssModulesPerChunk = new WeakMap();
395 compilation.hooks.afterCodeGeneration.tap(PLUGIN_NAME, () => {
396 const { chunkGraph } = compilation;
397 for (const chunk of compilation.chunks) {
398 if (CssModulesPlugin.chunkHasCss(chunk, chunkGraph)) {
399 orderedCssModulesPerChunk.set(
400 chunk,
401 this.getOrderedChunkCssModules(chunk, chunkGraph, compilation)
402 );
403 }
404 }
405 });
406 compilation.hooks.chunkHash.tap(PLUGIN_NAME, (chunk, hash, context) => {
407 hooks.chunkHash.call(chunk, hash, context);
408 });
409 compilation.hooks.contentHash.tap(PLUGIN_NAME, chunk => {
410 const {
411 chunkGraph,
412 codeGenerationResults,
413 moduleGraph,
414 runtimeTemplate,
415 outputOptions: {
416 hashSalt,
417 hashDigest,
418 hashDigestLength,
419 hashFunction
420 }
421 } = compilation;
422 const hash = createHash(/** @type {Algorithm} */ (hashFunction));
423 if (hashSalt) hash.update(hashSalt);
424 hooks.chunkHash.call(chunk, hash, {
425 chunkGraph,
426 codeGenerationResults,
427 moduleGraph,
428 runtimeTemplate
429 });
430 const modules = orderedCssModulesPerChunk.get(chunk);
431 if (modules) {
432 for (const module of modules) {
433 hash.update(chunkGraph.getModuleHash(module, chunk.runtime));
434 }
435 }
436 const digest = /** @type {string} */ (hash.digest(hashDigest));
437 chunk.contentHash.css = nonNumericOnlyHash(
438 digest,
439 /** @type {number} */
440 (hashDigestLength)
441 );
442 });
443 compilation.hooks.renderManifest.tap(PLUGIN_NAME, (result, options) => {
444 const { chunkGraph } = compilation;
445 const { hash, chunk, codeGenerationResults, runtimeTemplate } =
446 options;
447
448 if (chunk instanceof HotUpdateChunk) return result;
449
450 /** @type {CssModule[] | undefined} */
451 const modules = orderedCssModulesPerChunk.get(chunk);
452 if (modules !== undefined) {
453 const { path: filename, info } = compilation.getPathWithInfo(
454 CssModulesPlugin.getChunkFilenameTemplate(
455 chunk,
456 compilation.outputOptions
457 ),
458 {
459 hash,
460 runtime: chunk.runtime,
461 chunk,
462 contentHashType: "css"
463 }
464 );
465 const undoPath = getUndoPath(
466 filename,
467 /** @type {string} */
468 (compilation.outputOptions.path),
469 false
470 );
471 result.push({
472 render: () =>
473 this.renderChunk(
474 {
475 chunk,
476 chunkGraph,
477 codeGenerationResults,
478 uniqueName: compilation.outputOptions.uniqueName,
479 undoPath,
480 modules,
481 runtimeTemplate
482 },
483 hooks
484 ),
485 filename,
486 info,
487 identifier: `css${chunk.id}`,
488 hash: chunk.contentHash.css
489 });
490 }
491 return result;
492 });
493 const globalChunkLoading = compilation.outputOptions.chunkLoading;
494 /**
495 * @param {Chunk} chunk the chunk
496 * @returns {boolean} true, when enabled
497 */
498 const isEnabledForChunk = chunk => {
499 const options = chunk.getEntryOptions();
500 const chunkLoading =
501 options && options.chunkLoading !== undefined
502 ? options.chunkLoading
503 : globalChunkLoading;
504 return chunkLoading === "jsonp" || chunkLoading === "import";
505 };
506 const onceForChunkSet = new WeakSet();
507 /**
508 * @param {Chunk} chunk chunk to check
509 * @param {Set<string>} set runtime requirements
510 */
511 const handler = (chunk, set) => {
512 if (onceForChunkSet.has(chunk)) return;
513 onceForChunkSet.add(chunk);
514 if (!isEnabledForChunk(chunk)) return;
515
516 set.add(RuntimeGlobals.makeNamespaceObject);
517
518 const CssLoadingRuntimeModule = getCssLoadingRuntimeModule();
519 compilation.addRuntimeModule(chunk, new CssLoadingRuntimeModule(set));
520 };
521 compilation.hooks.runtimeRequirementInTree
522 .for(RuntimeGlobals.hasCssModules)
523 .tap(PLUGIN_NAME, handler);
524 compilation.hooks.runtimeRequirementInTree
525 .for(RuntimeGlobals.ensureChunkHandlers)
526 .tap(PLUGIN_NAME, (chunk, set, { chunkGraph }) => {
527 if (!isEnabledForChunk(chunk)) return;
528 if (
529 !chunkGraph.hasModuleInGraph(
530 chunk,
531 m =>
532 m.type === CSS_MODULE_TYPE ||
533 m.type === CSS_MODULE_TYPE_GLOBAL ||
534 m.type === CSS_MODULE_TYPE_MODULE ||
535 m.type === CSS_MODULE_TYPE_AUTO
536 )
537 ) {
538 return;
539 }
540
541 set.add(RuntimeGlobals.hasOwnProperty);
542 set.add(RuntimeGlobals.publicPath);
543 set.add(RuntimeGlobals.getChunkCssFilename);
544 });
545 compilation.hooks.runtimeRequirementInTree
546 .for(RuntimeGlobals.hmrDownloadUpdateHandlers)
547 .tap(PLUGIN_NAME, (chunk, set, { chunkGraph }) => {
548 if (!isEnabledForChunk(chunk)) return;
549 if (
550 !chunkGraph.hasModuleInGraph(
551 chunk,
552 m =>
553 m.type === CSS_MODULE_TYPE ||
554 m.type === CSS_MODULE_TYPE_GLOBAL ||
555 m.type === CSS_MODULE_TYPE_MODULE ||
556 m.type === CSS_MODULE_TYPE_AUTO
557 )
558 ) {
559 return;
560 }
561 set.add(RuntimeGlobals.publicPath);
562 set.add(RuntimeGlobals.getChunkCssFilename);
563 });
564 }
565 );
566 }
567
568 /**
569 * @param {Chunk} chunk chunk
570 * @param {Iterable<Module>} modules unordered modules
571 * @param {Compilation} compilation compilation
572 * @returns {Module[]} ordered modules
573 */
574 getModulesInOrder(chunk, modules, compilation) {
575 if (!modules) return [];
576
577 /** @type {Module[]} */
578 const modulesList = [...modules];
579
580 // Get ordered list of modules per chunk group
581 // Lists are in reverse order to allow to use Array.pop()
582 const modulesByChunkGroup = Array.from(chunk.groupsIterable, chunkGroup => {
583 const sortedModules = modulesList
584 .map(module => ({
585 module,
586 index: chunkGroup.getModulePostOrderIndex(module)
587 }))
588 .filter(item => item.index !== undefined)
589 .sort(
590 (a, b) =>
591 /** @type {number} */ (b.index) - /** @type {number} */ (a.index)
592 )
593 .map(item => item.module);
594
595 return { list: sortedModules, set: new Set(sortedModules) };
596 });
597
598 if (modulesByChunkGroup.length === 1)
599 return modulesByChunkGroup[0].list.reverse();
600
601 /**
602 * @param {{ list: Module[] }} a a
603 * @param {{ list: Module[] }} b b
604 * @returns {-1 | 0 | 1} result
605 */
606 const compareModuleLists = ({ list: a }, { list: b }) => {
607 if (a.length === 0) {
608 return b.length === 0 ? 0 : 1;
609 }
610 if (b.length === 0) return -1;
611 return compareModulesByIdentifier(a[a.length - 1], b[b.length - 1]);
612 };
613
614 modulesByChunkGroup.sort(compareModuleLists);
615
616 /** @type {Module[]} */
617 const finalModules = [];
618
619 for (;;) {
620 const failedModules = new Set();
621 const list = modulesByChunkGroup[0].list;
622 if (list.length === 0) {
623 // done, everything empty
624 break;
625 }
626 /** @type {Module} */
627 let selectedModule = list[list.length - 1];
628 let hasFailed;
629 outer: for (;;) {
630 for (const { list, set } of modulesByChunkGroup) {
631 if (list.length === 0) continue;
632 const lastModule = list[list.length - 1];
633 if (lastModule === selectedModule) continue;
634 if (!set.has(selectedModule)) continue;
635 failedModules.add(selectedModule);
636 if (failedModules.has(lastModule)) {
637 // There is a conflict, try other alternatives
638 hasFailed = lastModule;
639 continue;
640 }
641 selectedModule = lastModule;
642 hasFailed = false;
643 continue outer; // restart
644 }
645 break;
646 }
647 if (hasFailed) {
648 // There is a not resolve-able conflict with the selectedModule
649 // TODO print better warning
650 compilation.warnings.push(
651 new WebpackError(
652 `chunk ${chunk.name || chunk.id}\nConflicting order between ${
653 /** @type {Module} */
654 (hasFailed).readableIdentifier(compilation.requestShortener)
655 } and ${selectedModule.readableIdentifier(
656 compilation.requestShortener
657 )}`
658 )
659 );
660 selectedModule = /** @type {Module} */ (hasFailed);
661 }
662 // Insert the selected module into the final modules list
663 finalModules.push(selectedModule);
664 // Remove the selected module from all lists
665 for (const { list, set } of modulesByChunkGroup) {
666 const lastModule = list[list.length - 1];
667 if (lastModule === selectedModule) list.pop();
668 else if (hasFailed && set.has(selectedModule)) {
669 const idx = list.indexOf(selectedModule);
670 if (idx >= 0) list.splice(idx, 1);
671 }
672 }
673 modulesByChunkGroup.sort(compareModuleLists);
674 }
675 return finalModules;
676 }
677
678 /**
679 * @param {Chunk} chunk chunk
680 * @param {ChunkGraph} chunkGraph chunk graph
681 * @param {Compilation} compilation compilation
682 * @returns {Module[]} ordered css modules
683 */
684 getOrderedChunkCssModules(chunk, chunkGraph, compilation) {
685 return [
686 ...this.getModulesInOrder(
687 chunk,
688 /** @type {Iterable<Module>} */
689 (
690 chunkGraph.getOrderedChunkModulesIterableBySourceType(
691 chunk,
692 "css-import",
693 compareModulesByIdentifier
694 )
695 ),
696 compilation
697 ),
698 ...this.getModulesInOrder(
699 chunk,
700 /** @type {Iterable<Module>} */
701 (
702 chunkGraph.getOrderedChunkModulesIterableBySourceType(
703 chunk,
704 "css",
705 compareModulesByIdentifier
706 )
707 ),
708 compilation
709 )
710 ];
711 }
712
713 /**
714 * @param {CssModule} module css module
715 * @param {ChunkRenderContext} renderContext options object
716 * @param {CompilationHooks} hooks hooks
717 * @returns {Source} css module source
718 */
719 renderModule(module, renderContext, hooks) {
720 const { codeGenerationResults, chunk, undoPath } = renderContext;
721 const codeGenResult = codeGenerationResults.get(module, chunk.runtime);
722 const moduleSourceContent =
723 /** @type {Source} */
724 (
725 codeGenResult.sources.get("css") ||
726 codeGenResult.sources.get("css-import")
727 );
728 const cacheEntry = this._moduleFactoryCache.get(moduleSourceContent);
729
730 /** @type {Inheritance} */
731 const inheritance = [[module.cssLayer, module.supports, module.media]];
732 if (module.inheritance) {
733 inheritance.push(...module.inheritance);
734 }
735
736 let source;
737 if (
738 cacheEntry &&
739 cacheEntry.undoPath === undoPath &&
740 cacheEntry.inheritance.every(([layer, supports, media], i) => {
741 const item = inheritance[i];
742 if (Array.isArray(item)) {
743 return layer === item[0] && supports === item[1] && media === item[2];
744 }
745 return false;
746 })
747 ) {
748 source = cacheEntry.source;
749 } else {
750 const moduleSourceCode =
751 /** @type {string} */
752 (moduleSourceContent.source());
753 const publicPathAutoRegex = new RegExp(
754 CssUrlDependency.PUBLIC_PATH_AUTO,
755 "g"
756 );
757 /** @type {Source} */
758 let moduleSource = new ReplaceSource(moduleSourceContent);
759 let match;
760 while ((match = publicPathAutoRegex.exec(moduleSourceCode))) {
761 /** @type {ReplaceSource} */ (moduleSource).replace(
762 match.index,
763 (match.index += match[0].length - 1),
764 undoPath
765 );
766 }
767
768 for (let i = 0; i < inheritance.length; i++) {
769 const layer = inheritance[i][0];
770 const supports = inheritance[i][1];
771 const media = inheritance[i][2];
772
773 if (media) {
774 moduleSource = new ConcatSource(
775 `@media ${media} {\n`,
776 new PrefixSource("\t", moduleSource),
777 "}\n"
778 );
779 }
780
781 if (supports) {
782 moduleSource = new ConcatSource(
783 `@supports (${supports}) {\n`,
784 new PrefixSource("\t", moduleSource),
785 "}\n"
786 );
787 }
788
789 // Layer can be anonymous
790 if (layer !== undefined && layer !== null) {
791 moduleSource = new ConcatSource(
792 `@layer${layer ? ` ${layer}` : ""} {\n`,
793 new PrefixSource("\t", moduleSource),
794 "}\n"
795 );
796 }
797 }
798
799 if (moduleSource) {
800 moduleSource = new ConcatSource(moduleSource, "\n");
801 }
802
803 source = new CachedSource(moduleSource);
804 this._moduleFactoryCache.set(moduleSourceContent, {
805 inheritance,
806 undoPath,
807 source
808 });
809 }
810
811 return tryRunOrWebpackError(
812 () => hooks.renderModulePackage.call(source, module, renderContext),
813 "CssModulesPlugin.getCompilationHooks().renderModulePackage"
814 );
815 }
816
817 /**
818 * @param {RenderContext} renderContext the render context
819 * @param {CompilationHooks} hooks hooks
820 * @returns {Source} generated source
821 */
822 renderChunk(
823 {
824 undoPath,
825 chunk,
826 chunkGraph,
827 codeGenerationResults,
828 modules,
829 runtimeTemplate
830 },
831 hooks
832 ) {
833 const source = new ConcatSource();
834 for (const module of modules) {
835 try {
836 const moduleSource = this.renderModule(
837 module,
838 {
839 undoPath,
840 chunk,
841 chunkGraph,
842 codeGenerationResults,
843 runtimeTemplate
844 },
845 hooks
846 );
847 source.add(moduleSource);
848 } catch (err) {
849 /** @type {Error} */
850 (err).message += `\nduring rendering of css ${module.identifier()}`;
851 throw err;
852 }
853 }
854 chunk.rendered = true;
855 return source;
856 }
857
858 /**
859 * @param {Chunk} chunk chunk
860 * @param {OutputOptions} outputOptions output options
861 * @returns {TemplatePath} used filename template
862 */
863 static getChunkFilenameTemplate(chunk, outputOptions) {
864 if (chunk.cssFilenameTemplate) {
865 return chunk.cssFilenameTemplate;
866 } else if (chunk.canBeInitial()) {
867 return /** @type {TemplatePath} */ (outputOptions.cssFilename);
868 }
869 return /** @type {TemplatePath} */ (outputOptions.cssChunkFilename);
870 }
871
872 /**
873 * @param {Chunk} chunk chunk
874 * @param {ChunkGraph} chunkGraph chunk graph
875 * @returns {boolean} true, when the chunk has css
876 */
877 static chunkHasCss(chunk, chunkGraph) {
878 return (
879 Boolean(chunkGraph.getChunkModulesIterableBySourceType(chunk, "css")) ||
880 Boolean(
881 chunkGraph.getChunkModulesIterableBySourceType(chunk, "css-import")
882 )
883 );
884 }
885}
886
887module.exports = CssModulesPlugin;
Note: See TracBrowser for help on using the repository browser.