1 | "use strict";
|
2 |
|
3 |
|
4 | const path = require("path");
|
5 |
|
6 | const {
|
7 | validate
|
8 | } = require("schema-utils");
|
9 |
|
10 | const schema = require("./plugin-options.json");
|
11 |
|
12 | const {
|
13 | trueFn,
|
14 | MODULE_TYPE,
|
15 | AUTO_PUBLIC_PATH,
|
16 | ABSOLUTE_PUBLIC_PATH,
|
17 | SINGLE_DOT_PATH_SEGMENT,
|
18 | compareModulesByIdentifier,
|
19 | getUndoPath,
|
20 | BASE_URI
|
21 | } = require("./utils");
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 | const pluginName = "mini-css-extract-plugin";
|
91 | const pluginSymbol = Symbol(pluginName);
|
92 | const DEFAULT_FILENAME = "[name].css";
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | const TYPES = new Set([MODULE_TYPE]);
|
98 |
|
99 |
|
100 |
|
101 |
|
102 | const CODE_GENERATION_RESULT = {
|
103 | sources: new Map(),
|
104 | runtimeRequirements: new Set()
|
105 | };
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 | const cssModuleCache = new WeakMap();
|
124 |
|
125 |
|
126 |
|
127 |
|
128 | const cssDependencyCache = new WeakMap();
|
129 |
|
130 |
|
131 |
|
132 |
|
133 | const registered = new WeakSet();
|
134 |
|
135 | class MiniCssExtractPlugin {
|
136 | |
137 |
|
138 |
|
139 |
|
140 | static getCssModule(webpack) {
|
141 | |
142 |
|
143 |
|
144 | if (cssModuleCache.has(webpack)) {
|
145 | return (
|
146 |
|
147 | cssModuleCache.get(webpack)
|
148 | );
|
149 | }
|
150 |
|
151 | class CssModule extends webpack.Module {
|
152 | |
153 |
|
154 |
|
155 | constructor({
|
156 | context,
|
157 | identifier,
|
158 | identifierIndex,
|
159 | content,
|
160 | layer,
|
161 | supports,
|
162 | media,
|
163 | sourceMap,
|
164 | assets,
|
165 | assetsInfo
|
166 | }) {
|
167 | super(MODULE_TYPE,
|
168 |
|
169 | context);
|
170 | this.id = "";
|
171 | this._context = context;
|
172 | this._identifier = identifier;
|
173 | this._identifierIndex = identifierIndex;
|
174 | this.content = content;
|
175 | this.layer = layer;
|
176 | this.supports = supports;
|
177 | this.media = media;
|
178 | this.sourceMap = sourceMap;
|
179 | this.assets = assets;
|
180 | this.assetsInfo = assetsInfo;
|
181 | this._needBuild = true;
|
182 | }
|
183 |
|
184 |
|
185 | size() {
|
186 | return this.content.length;
|
187 | }
|
188 |
|
189 | identifier() {
|
190 | return `css|${this._identifier}|${this._identifierIndex}`;
|
191 | }
|
192 | |
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 | readableIdentifier(requestShortener) {
|
199 | return `css ${requestShortener.shorten(this._identifier)}${this._identifierIndex ? ` (${this._identifierIndex})` : ""}`;
|
200 | }
|
201 |
|
202 |
|
203 | getSourceTypes() {
|
204 | return TYPES;
|
205 | }
|
206 |
|
207 |
|
208 | codeGeneration() {
|
209 | return CODE_GENERATION_RESULT;
|
210 | }
|
211 |
|
212 | nameForCondition() {
|
213 | const resource =
|
214 |
|
215 | this._identifier.split("!").pop();
|
216 |
|
217 | const idx = resource.indexOf("?");
|
218 |
|
219 | if (idx >= 0) {
|
220 | return resource.substring(0, idx);
|
221 | }
|
222 |
|
223 | return resource;
|
224 | }
|
225 | |
226 |
|
227 |
|
228 |
|
229 |
|
230 | updateCacheModule(module) {
|
231 | if (this.content !==
|
232 |
|
233 | module.content || this.layer !==
|
234 |
|
235 | module.layer || this.supports !==
|
236 |
|
237 | module.supports || this.media !==
|
238 |
|
239 | module.media || this.sourceMap !==
|
240 |
|
241 | module.sourceMap || this.assets !==
|
242 |
|
243 | module.assets || this.assetsInfo !==
|
244 |
|
245 | module.assetsInfo) {
|
246 | this._needBuild = true;
|
247 | this.content =
|
248 |
|
249 | module.content;
|
250 | this.layer =
|
251 |
|
252 | module.layer;
|
253 | this.supports =
|
254 |
|
255 | module.supports;
|
256 | this.media =
|
257 |
|
258 | module.media;
|
259 | this.sourceMap =
|
260 |
|
261 | module.sourceMap;
|
262 | this.assets =
|
263 |
|
264 | module.assets;
|
265 | this.assetsInfo =
|
266 |
|
267 | module.assetsInfo;
|
268 | }
|
269 | }
|
270 |
|
271 |
|
272 | needRebuild() {
|
273 | return this._needBuild;
|
274 | }
|
275 |
|
276 | |
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 | needBuild(context, callback) {
|
283 |
|
284 | callback(undefined, this._needBuild);
|
285 | }
|
286 | |
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 | build(options, compilation, resolver, fileSystem, callback) {
|
296 | this.buildInfo = {
|
297 | assets: this.assets,
|
298 | assetsInfo: this.assetsInfo,
|
299 | cacheable: true,
|
300 | hash: this._computeHash(
|
301 |
|
302 | compilation.outputOptions.hashFunction)
|
303 | };
|
304 | this.buildMeta = {};
|
305 | this._needBuild = false;
|
306 | callback();
|
307 | }
|
308 | |
309 |
|
310 |
|
311 |
|
312 |
|
313 |
|
314 |
|
315 | _computeHash(hashFunction) {
|
316 | const hash = webpack.util.createHash(hashFunction);
|
317 | hash.update(this.content);
|
318 |
|
319 | if (this.layer) {
|
320 | hash.update(this.layer);
|
321 | }
|
322 |
|
323 | hash.update(this.supports || "");
|
324 | hash.update(this.media || "");
|
325 | hash.update(this.sourceMap || "");
|
326 | return hash.digest("hex");
|
327 | }
|
328 | |
329 |
|
330 |
|
331 |
|
332 |
|
333 |
|
334 | updateHash(hash, context) {
|
335 | super.updateHash(hash, context);
|
336 | hash.update(this.buildInfo.hash);
|
337 | }
|
338 | |
339 |
|
340 |
|
341 |
|
342 |
|
343 | serialize(context) {
|
344 | const {
|
345 | write
|
346 | } = context;
|
347 | write(this._context);
|
348 | write(this._identifier);
|
349 | write(this._identifierIndex);
|
350 | write(this.content);
|
351 | write(this.layer);
|
352 | write(this.supports);
|
353 | write(this.media);
|
354 | write(this.sourceMap);
|
355 | write(this.assets);
|
356 | write(this.assetsInfo);
|
357 | write(this._needBuild);
|
358 | super.serialize(context);
|
359 | }
|
360 | |
361 |
|
362 |
|
363 |
|
364 |
|
365 | deserialize(context) {
|
366 | this._needBuild = context.read();
|
367 | super.deserialize(context);
|
368 | }
|
369 |
|
370 | }
|
371 |
|
372 | cssModuleCache.set(webpack, CssModule);
|
373 | webpack.util.serialization.register(CssModule, path.resolve(__dirname, "CssModule"),
|
374 | null, {
|
375 | serialize(instance, context) {
|
376 | instance.serialize(context);
|
377 | },
|
378 |
|
379 | deserialize(context) {
|
380 | const {
|
381 | read
|
382 | } = context;
|
383 | const contextModule = read();
|
384 | const identifier = read();
|
385 | const identifierIndex = read();
|
386 | const content = read();
|
387 | const layer = read();
|
388 | const supports = read();
|
389 | const media = read();
|
390 | const sourceMap = read();
|
391 | const assets = read();
|
392 | const assetsInfo = read();
|
393 | const dep = new CssModule({
|
394 | context: contextModule,
|
395 | identifier,
|
396 | identifierIndex,
|
397 | content,
|
398 | layer,
|
399 | supports,
|
400 | media,
|
401 | sourceMap,
|
402 | assets,
|
403 | assetsInfo
|
404 | });
|
405 | dep.deserialize(context);
|
406 | return dep;
|
407 | }
|
408 |
|
409 | });
|
410 | return CssModule;
|
411 | }
|
412 | |
413 |
|
414 |
|
415 |
|
416 |
|
417 |
|
418 | static getCssDependency(webpack) {
|
419 | |
420 |
|
421 |
|
422 | if (cssDependencyCache.has(webpack)) {
|
423 | return (
|
424 |
|
425 | cssDependencyCache.get(webpack)
|
426 | );
|
427 | }
|
428 |
|
429 | class CssDependency extends webpack.Dependency {
|
430 | |
431 |
|
432 |
|
433 |
|
434 |
|
435 | constructor({
|
436 | identifier,
|
437 | content,
|
438 | layer,
|
439 | supports,
|
440 | media,
|
441 | sourceMap
|
442 | }, context, identifierIndex) {
|
443 | super();
|
444 | this.identifier = identifier;
|
445 | this.identifierIndex = identifierIndex;
|
446 | this.content = content;
|
447 | this.layer = layer;
|
448 | this.supports = supports;
|
449 | this.media = media;
|
450 | this.sourceMap = sourceMap;
|
451 | this.context = context;
|
452 |
|
453 |
|
454 |
|
455 | this.assets = undefined;
|
456 |
|
457 |
|
458 |
|
459 | this.assetsInfo = undefined;
|
460 | }
|
461 | |
462 |
|
463 |
|
464 |
|
465 |
|
466 | getResourceIdentifier() {
|
467 | return `css-module-${this.identifier}-${this.identifierIndex}`;
|
468 | }
|
469 | |
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|
475 | getModuleEvaluationSideEffectsState() {
|
476 | return webpack.ModuleGraphConnection.TRANSITIVE_ONLY;
|
477 | }
|
478 | |
479 |
|
480 |
|
481 |
|
482 |
|
483 | serialize(context) {
|
484 | const {
|
485 | write
|
486 | } = context;
|
487 | write(this.identifier);
|
488 | write(this.content);
|
489 | write(this.layer);
|
490 | write(this.supports);
|
491 | write(this.media);
|
492 | write(this.sourceMap);
|
493 | write(this.context);
|
494 | write(this.identifierIndex);
|
495 | write(this.assets);
|
496 | write(this.assetsInfo);
|
497 | super.serialize(context);
|
498 | }
|
499 | |
500 |
|
501 |
|
502 |
|
503 |
|
504 | deserialize(context) {
|
505 | super.deserialize(context);
|
506 | }
|
507 |
|
508 | }
|
509 |
|
510 | cssDependencyCache.set(webpack, CssDependency);
|
511 | webpack.util.serialization.register(CssDependency, path.resolve(__dirname, "CssDependency"),
|
512 | null, {
|
513 | serialize(instance, context) {
|
514 | instance.serialize(context);
|
515 | },
|
516 |
|
517 | deserialize(context) {
|
518 | const {
|
519 | read
|
520 | } = context;
|
521 | const dep = new CssDependency({
|
522 | identifier: read(),
|
523 | content: read(),
|
524 | layer: read(),
|
525 | supports: read(),
|
526 | media: read(),
|
527 | sourceMap: read()
|
528 | }, read(), read());
|
529 | const assets = read();
|
530 | const assetsInfo = read();
|
531 | dep.assets = assets;
|
532 | dep.assetsInfo = assetsInfo;
|
533 | dep.deserialize(context);
|
534 | return dep;
|
535 | }
|
536 |
|
537 | });
|
538 | return CssDependency;
|
539 | }
|
540 | |
541 |
|
542 |
|
543 |
|
544 |
|
545 | constructor(options = {}) {
|
546 | validate(
|
547 |
|
548 | schema, options, {
|
549 | baseDataPath: "options"
|
550 | });
|
551 | |
552 |
|
553 |
|
554 |
|
555 |
|
556 |
|
557 | this._sortedModulesCache = new WeakMap();
|
558 | |
559 |
|
560 |
|
561 |
|
562 |
|
563 | this.options = Object.assign({
|
564 | filename: DEFAULT_FILENAME,
|
565 | ignoreOrder: false,
|
566 |
|
567 |
|
568 | experimentalUseImportModule: undefined,
|
569 | runtime: true
|
570 | }, options);
|
571 | |
572 |
|
573 |
|
574 |
|
575 |
|
576 | this.runtimeOptions = {
|
577 | insert: options.insert,
|
578 | linkType:
|
579 | typeof options.linkType === "boolean" &&
|
580 |
|
581 | options.linkType === true || typeof options.linkType === "undefined" ? "text/css" : options.linkType,
|
582 | attributes: options.attributes
|
583 | };
|
584 |
|
585 | if (!this.options.chunkFilename) {
|
586 | const {
|
587 | filename
|
588 | } = this.options;
|
589 |
|
590 | if (typeof filename !== "function") {
|
591 | const hasName =
|
592 |
|
593 | filename.includes("[name]");
|
594 | const hasId =
|
595 |
|
596 | filename.includes("[id]");
|
597 | const hasChunkHash =
|
598 |
|
599 | filename.includes("[chunkhash]");
|
600 | const hasContentHash =
|
601 |
|
602 | filename.includes("[contenthash]");
|
603 |
|
604 | if (hasChunkHash || hasContentHash || hasName || hasId) {
|
605 | this.options.chunkFilename = filename;
|
606 | } else {
|
607 |
|
608 | this.options.chunkFilename =
|
609 |
|
610 | filename.replace(/(^|\/)([^/]*(?:\?|$))/, "$1[id].$2");
|
611 | }
|
612 | } else {
|
613 | this.options.chunkFilename = "[id].css";
|
614 | }
|
615 | }
|
616 | }
|
617 | |
618 |
|
619 |
|
620 |
|
621 |
|
622 | apply(compiler) {
|
623 | const {
|
624 | webpack
|
625 | } = compiler;
|
626 |
|
627 | if (this.options.experimentalUseImportModule) {
|
628 | if (typeof
|
629 |
|
630 | compiler.options.experiments.executeModule === "undefined") {
|
631 |
|
632 |
|
633 | compiler.options.experiments.executeModule = true;
|
634 | }
|
635 | }
|
636 |
|
637 |
|
638 |
|
639 | if (!registered.has(webpack)) {
|
640 | registered.add(webpack);
|
641 | webpack.util.serialization.registerLoader(/^mini-css-extract-plugin\//, trueFn);
|
642 | }
|
643 |
|
644 | const {
|
645 | splitChunks
|
646 | } = compiler.options.optimization;
|
647 |
|
648 | if (splitChunks) {
|
649 | if (
|
650 |
|
651 | splitChunks.defaultSizeTypes.includes("...")) {
|
652 |
|
653 | splitChunks.defaultSizeTypes.push(MODULE_TYPE);
|
654 | }
|
655 | }
|
656 |
|
657 | const CssModule = MiniCssExtractPlugin.getCssModule(webpack);
|
658 | const CssDependency = MiniCssExtractPlugin.getCssDependency(webpack);
|
659 | const {
|
660 | NormalModule
|
661 | } = compiler.webpack;
|
662 | compiler.hooks.compilation.tap(pluginName, compilation => {
|
663 | const {
|
664 | loader: normalModuleHook
|
665 | } = NormalModule.getCompilationHooks(compilation);
|
666 | normalModuleHook.tap(pluginName,
|
667 | |
668 |
|
669 |
|
670 | loaderContext => {
|
671 |
|
672 |
|
673 | loaderContext[pluginSymbol] = {
|
674 | experimentalUseImportModule: this.options.experimentalUseImportModule
|
675 | };
|
676 | });
|
677 | });
|
678 | compiler.hooks.thisCompilation.tap(pluginName, compilation => {
|
679 | class CssModuleFactory {
|
680 | |
681 |
|
682 |
|
683 |
|
684 |
|
685 | create({
|
686 | dependencies: [dependency]
|
687 | }, callback) {
|
688 |
|
689 | callback(undefined, new CssModule(
|
690 |
|
691 | dependency));
|
692 | }
|
693 |
|
694 | }
|
695 |
|
696 | compilation.dependencyFactories.set(CssDependency, new CssModuleFactory());
|
697 |
|
698 | class CssDependencyTemplate {
|
699 |
|
700 | apply() {}
|
701 |
|
702 | }
|
703 |
|
704 | compilation.dependencyTemplates.set(CssDependency, new CssDependencyTemplate());
|
705 | compilation.hooks.renderManifest.tap(pluginName,
|
706 | |
707 |
|
708 |
|
709 |
|
710 |
|
711 | (result, {
|
712 | chunk
|
713 | }) => {
|
714 | const {
|
715 | chunkGraph
|
716 | } = compilation;
|
717 | const {
|
718 | HotUpdateChunk
|
719 | } = webpack;
|
720 |
|
721 |
|
722 | if (chunk instanceof HotUpdateChunk) {
|
723 | return;
|
724 | }
|
725 |
|
726 |
|
727 |
|
728 | const renderedModules = Array.from(
|
729 |
|
730 | this.getChunkModules(chunk, chunkGraph)).filter(module => module.type === MODULE_TYPE);
|
731 | const filenameTemplate =
|
732 |
|
733 | chunk.canBeInitial() ? this.options.filename : this.options.chunkFilename;
|
734 |
|
735 | if (renderedModules.length > 0) {
|
736 | result.push({
|
737 | render: () => this.renderContentAsset(compiler, compilation, chunk, renderedModules, compilation.runtimeTemplate.requestShortener, filenameTemplate, {
|
738 | contentHashType: MODULE_TYPE,
|
739 | chunk
|
740 | }),
|
741 | filenameTemplate,
|
742 | pathOptions: {
|
743 | chunk,
|
744 | contentHashType: MODULE_TYPE
|
745 | },
|
746 | identifier: `${pluginName}.${chunk.id}`,
|
747 | hash: chunk.contentHash[MODULE_TYPE]
|
748 | });
|
749 | }
|
750 | });
|
751 | compilation.hooks.contentHash.tap(pluginName, chunk => {
|
752 | const {
|
753 | outputOptions,
|
754 | chunkGraph
|
755 | } = compilation;
|
756 | const modules = this.sortModules(compilation, chunk,
|
757 |
|
758 | chunkGraph.getChunkModulesIterableBySourceType(chunk, MODULE_TYPE), compilation.runtimeTemplate.requestShortener);
|
759 |
|
760 | if (modules) {
|
761 | const {
|
762 | hashFunction,
|
763 | hashDigest,
|
764 | hashDigestLength
|
765 | } = outputOptions;
|
766 | const {
|
767 | createHash
|
768 | } = compiler.webpack.util;
|
769 | const hash = createHash(
|
770 |
|
771 | hashFunction);
|
772 |
|
773 | for (const m of modules) {
|
774 | hash.update(chunkGraph.getModuleHash(m, chunk.runtime));
|
775 | }
|
776 |
|
777 |
|
778 | chunk.contentHash[MODULE_TYPE] =
|
779 |
|
780 | hash.digest(hashDigest).substring(0, hashDigestLength);
|
781 | }
|
782 | });
|
783 |
|
784 | if (!this.options.runtime) {
|
785 | return;
|
786 | }
|
787 |
|
788 | const {
|
789 | Template,
|
790 | RuntimeGlobals,
|
791 | RuntimeModule,
|
792 | runtime
|
793 | } = webpack;
|
794 | |
795 |
|
796 |
|
797 |
|
798 |
|
799 |
|
800 |
|
801 | const getCssChunkObject = (mainChunk, compilation) => {
|
802 |
|
803 | const obj = {};
|
804 | const {
|
805 | chunkGraph
|
806 | } = compilation;
|
807 |
|
808 | for (const chunk of mainChunk.getAllAsyncChunks()) {
|
809 | const modules = chunkGraph.getOrderedChunkModulesIterable(chunk, compareModulesByIdentifier);
|
810 |
|
811 | for (const module of modules) {
|
812 | if (module.type === MODULE_TYPE) {
|
813 | obj[
|
814 |
|
815 | chunk.id] = 1;
|
816 | break;
|
817 | }
|
818 | }
|
819 | }
|
820 |
|
821 | return obj;
|
822 | };
|
823 |
|
824 | class CssLoadingRuntimeModule extends RuntimeModule {
|
825 | |
826 |
|
827 |
|
828 |
|
829 | constructor(runtimeRequirements, runtimeOptions) {
|
830 | super("css loading", 10);
|
831 | this.runtimeRequirements = runtimeRequirements;
|
832 | this.runtimeOptions = runtimeOptions;
|
833 | }
|
834 |
|
835 | generate() {
|
836 | const {
|
837 | chunk,
|
838 | runtimeRequirements
|
839 | } = this;
|
840 | const {
|
841 | runtimeTemplate,
|
842 | outputOptions: {
|
843 | crossOriginLoading
|
844 | }
|
845 | } = this.compilation;
|
846 | const chunkMap = getCssChunkObject(chunk, this.compilation);
|
847 | const withLoading = runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers) && Object.keys(chunkMap).length > 0;
|
848 | const withHmr = runtimeRequirements.has(RuntimeGlobals.hmrDownloadUpdateHandlers);
|
849 |
|
850 | if (!withLoading && !withHmr) {
|
851 | return "";
|
852 | }
|
853 |
|
854 | return Template.asString([`var createStylesheet = ${runtimeTemplate.basicFunction("chunkId, fullhref, resolve, reject", ['var linkTag = document.createElement("link");', this.runtimeOptions.attributes ? Template.asString(Object.entries(this.runtimeOptions.attributes).map(entry => {
|
855 | const [key, value] = entry;
|
856 | return `linkTag.setAttribute(${JSON.stringify(key)}, ${JSON.stringify(value)});`;
|
857 | })) : "", 'linkTag.rel = "stylesheet";', this.runtimeOptions.linkType ? `linkTag.type = ${JSON.stringify(this.runtimeOptions.linkType)};` : "", `var onLinkComplete = ${runtimeTemplate.basicFunction("event", ["// avoid mem leaks.", "linkTag.onerror = linkTag.onload = null;", "if (event.type === 'load') {", Template.indent(["resolve();"]), "} else {", Template.indent(["var errorType = event && (event.type === 'load' ? 'missing' : event.type);", "var realHref = event && event.target && event.target.href || fullhref;", 'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + realHref + ")");', 'err.code = "CSS_CHUNK_LOAD_FAILED";', "err.type = errorType;", "err.request = realHref;", "linkTag.parentNode.removeChild(linkTag)", "reject(err);"]), "}"])}`, "linkTag.onerror = linkTag.onload = onLinkComplete;", "linkTag.href = fullhref;", crossOriginLoading ? Template.asString([`if (linkTag.href.indexOf(window.location.origin + '/') !== 0) {`, Template.indent(`linkTag.crossOrigin = ${JSON.stringify(crossOriginLoading)};`), "}"]) : "", typeof this.runtimeOptions.insert !== "undefined" ? typeof this.runtimeOptions.insert === "function" ? `(${this.runtimeOptions.insert.toString()})(linkTag)` : Template.asString([`var target = document.querySelector("${this.runtimeOptions.insert}");`, `target.parentNode.insertBefore(linkTag, target.nextSibling);`]) : Template.asString(["document.head.appendChild(linkTag);"]), "return linkTag;"])};`, `var findStylesheet = ${runtimeTemplate.basicFunction("href, fullhref", ['var existingLinkTags = document.getElementsByTagName("link");', "for(var i = 0; i < existingLinkTags.length; i++) {", Template.indent(["var tag = existingLinkTags[i];", 'var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");', 'if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return tag;']), "}", 'var existingStyleTags = document.getElementsByTagName("style");', "for(var i = 0; i < existingStyleTags.length; i++) {", Template.indent(["var tag = existingStyleTags[i];", 'var dataHref = tag.getAttribute("data-href");', "if(dataHref === href || dataHref === fullhref) return tag;"]), "}"])};`, `var loadStylesheet = ${runtimeTemplate.basicFunction("chunkId", `return new Promise(${runtimeTemplate.basicFunction("resolve, reject", [`var href = ${RuntimeGlobals.require}.miniCssF(chunkId);`, `var fullhref = ${RuntimeGlobals.publicPath} + href;`, "if(findStylesheet(href, fullhref)) return resolve();", "createStylesheet(chunkId, fullhref, resolve, reject);"])});`)}`, withLoading ? Template.asString(["// object to store loaded CSS chunks", "var installedCssChunks = {", Template.indent(
|
858 |
|
859 | chunk.ids.map(id => `${JSON.stringify(id)}: 0`).join(",\n")), "};", "", `${RuntimeGlobals.ensureChunkHandlers}.miniCss = ${runtimeTemplate.basicFunction("chunkId, promises", [`var cssChunks = ${JSON.stringify(chunkMap)};`, "if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);", "else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {", Template.indent([`promises.push(installedCssChunks[chunkId] = loadStylesheet(chunkId).then(${runtimeTemplate.basicFunction("", "installedCssChunks[chunkId] = 0;")}, ${runtimeTemplate.basicFunction("e", ["delete installedCssChunks[chunkId];", "throw e;"])}));`]), "}"])};`]) : "// no chunk loading", "", withHmr ? Template.asString(["var oldTags = [];", "var newTags = [];", `var applyHandler = ${runtimeTemplate.basicFunction("options", [`return { dispose: ${runtimeTemplate.basicFunction("", ["for(var i = 0; i < oldTags.length; i++) {", Template.indent(["var oldTag = oldTags[i];", "if(oldTag.parentNode) oldTag.parentNode.removeChild(oldTag);"]), "}", "oldTags.length = 0;"])}, apply: ${runtimeTemplate.basicFunction("", ['for(var i = 0; i < newTags.length; i++) newTags[i].rel = "stylesheet";', "newTags.length = 0;"])} };`])}`, `${RuntimeGlobals.hmrDownloadUpdateHandlers}.miniCss = ${runtimeTemplate.basicFunction("chunkIds, removedChunks, removedModules, promises, applyHandlers, updatedModulesList", ["applyHandlers.push(applyHandler);", `chunkIds.forEach(${runtimeTemplate.basicFunction("chunkId", [`var href = ${RuntimeGlobals.require}.miniCssF(chunkId);`, `var fullhref = ${RuntimeGlobals.publicPath} + href;`, "var oldTag = findStylesheet(href, fullhref);", "if(!oldTag) return;", `promises.push(new Promise(${runtimeTemplate.basicFunction("resolve, reject", [`var tag = createStylesheet(chunkId, fullhref, ${runtimeTemplate.basicFunction("", ['tag.as = "style";', 'tag.rel = "preload";', "resolve();"])}, reject);`, "oldTags.push(oldTag);", "newTags.push(tag);"])}));`])});`])}`]) : "// no hmr"]);
|
860 | }
|
861 |
|
862 | }
|
863 |
|
864 | const enabledChunks = new WeakSet();
|
865 | |
866 |
|
867 |
|
868 |
|
869 |
|
870 | const handler = (chunk, set) => {
|
871 | if (enabledChunks.has(chunk)) {
|
872 | return;
|
873 | }
|
874 |
|
875 | enabledChunks.add(chunk);
|
876 |
|
877 | if (typeof this.options.chunkFilename === "string" && /\[(full)?hash(:\d+)?\]/.test(this.options.chunkFilename)) {
|
878 | set.add(RuntimeGlobals.getFullHash);
|
879 | }
|
880 |
|
881 | set.add(RuntimeGlobals.publicPath);
|
882 | compilation.addRuntimeModule(chunk, new runtime.GetChunkFilenameRuntimeModule(MODULE_TYPE, "mini-css", `${RuntimeGlobals.require}.miniCssF`,
|
883 | /**
|
884 | * @param {Chunk} referencedChunk
|
885 | * @returns {TODO}
|
886 | */
|
887 | referencedChunk => {
|
888 | if (!referencedChunk.contentHash[MODULE_TYPE]) {
|
889 | return false;
|
890 | }
|
891 |
|
892 | return referencedChunk.canBeInitial() ? this.options.filename : this.options.chunkFilename;
|
893 | }, false));
|
894 | compilation.addRuntimeModule(chunk, new CssLoadingRuntimeModule(set, this.runtimeOptions));
|
895 | };
|
896 |
|
897 | compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.ensureChunkHandlers).tap(pluginName, handler);
|
898 | compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.hmrDownloadUpdateHandlers).tap(pluginName, handler);
|
899 | });
|
900 | }
|
901 | /**
|
902 | * @private
|
903 | * @param {Chunk} chunk
|
904 | * @param {ChunkGraph} chunkGraph
|
905 | * @returns {Iterable<Module>}
|
906 | */
|
907 |
|
908 |
|
909 | getChunkModules(chunk, chunkGraph) {
|
910 | return typeof chunkGraph !== "undefined" ? chunkGraph.getOrderedChunkModulesIterable(chunk, compareModulesByIdentifier) : chunk.modulesIterable;
|
911 | }
|
912 | /**
|
913 | * @private
|
914 | * @param {Compilation} compilation
|
915 | * @param {Chunk} chunk
|
916 | * @param {CssModule[]} modules
|
917 | * @param {Compilation["requestShortener"]} requestShortener
|
918 | * @returns {Set<CssModule>}
|
919 | */
|
920 |
|
921 |
|
922 | sortModules(compilation, chunk, modules, requestShortener) {
|
923 | let usedModules = this._sortedModulesCache.get(chunk);
|
924 |
|
925 | if (usedModules || !modules) {
|
926 | return (
|
927 | /** @type {Set<CssModule>} */
|
928 | usedModules
|
929 | );
|
930 | }
|
931 | /** @type {CssModule[]} */
|
932 |
|
933 |
|
934 | const modulesList = [...modules]; // Store dependencies for modules
|
935 |
|
936 | /** @type {Map<CssModule, Set<CssModule>>} */
|
937 |
|
938 | const moduleDependencies = new Map(modulesList.map(m => [m,
|
939 | /** @type {Set<CssModule>} */
|
940 | new Set()]));
|
941 | /** @type {Map<CssModule, Map<CssModule, Set<ChunkGroup>>>} */
|
942 |
|
943 | const moduleDependenciesReasons = new Map(modulesList.map(m => [m, new Map()])); // Get ordered list of modules per chunk group
|
944 | // This loop also gathers dependencies from the ordered lists
|
945 | // Lists are in reverse order to allow to use Array.pop()
|
946 |
|
947 | /** @type {CssModule[][]} */
|
948 |
|
949 | const modulesByChunkGroup = Array.from(chunk.groupsIterable, chunkGroup => {
|
950 | const sortedModules = modulesList.map(module => {
|
951 | return {
|
952 | module,
|
953 | index: chunkGroup.getModulePostOrderIndex(module)
|
954 | };
|
955 | }) // eslint-disable-next-line no-undefined
|
956 | .filter(item => item.index !== undefined).sort((a, b) => b.index - a.index).map(item => item.module);
|
957 |
|
958 | for (let i = 0; i < sortedModules.length; i++) {
|
959 | const set = moduleDependencies.get(sortedModules[i]);
|
960 | const reasons =
|
961 | /** @type {Map<CssModule, Set<ChunkGroup>>} */
|
962 | moduleDependenciesReasons.get(sortedModules[i]);
|
963 |
|
964 | for (let j = i + 1; j < sortedModules.length; j++) {
|
965 | const module = sortedModules[j];
|
966 | /** @type {Set<CssModule>} */
|
967 |
|
968 | set.add(module);
|
969 | const reason = reasons.get(module) ||
|
970 | /** @type {Set<ChunkGroup>} */
|
971 | new Set();
|
972 | reason.add(chunkGroup);
|
973 | reasons.set(module, reason);
|
974 | }
|
975 | }
|
976 |
|
977 | return sortedModules;
|
978 | }); // set with already included modules in correct order
|
979 |
|
980 | usedModules = new Set();
|
981 | /**
|
982 | * @param {CssModule} m
|
983 | * @returns {boolean}
|
984 | */
|
985 |
|
986 | const unusedModulesFilter = m => !
|
987 | /** @type {Set<CssModule>} */
|
988 | usedModules.has(m);
|
989 |
|
990 | while (usedModules.size < modulesList.length) {
|
991 | let success = false;
|
992 | let bestMatch;
|
993 | let bestMatchDeps; // get first module where dependencies are fulfilled
|
994 |
|
995 | for (const list of modulesByChunkGroup) {
|
996 | // skip and remove already added modules
|
997 | while (list.length > 0 && usedModules.has(list[list.length - 1])) {
|
998 | list.pop();
|
999 | } // skip empty lists
|
1000 |
|
1001 |
|
1002 | if (list.length !== 0) {
|
1003 | const module = list[list.length - 1];
|
1004 | const deps = moduleDependencies.get(module); // determine dependencies that are not yet included
|
1005 |
|
1006 | const failedDeps = Array.from(
|
1007 | /** @type {Set<CssModule>} */
|
1008 | deps).filter(unusedModulesFilter); // store best match for fallback behavior
|
1009 |
|
1010 | if (!bestMatchDeps || bestMatchDeps.length > failedDeps.length) {
|
1011 | bestMatch = list;
|
1012 | bestMatchDeps = failedDeps;
|
1013 | }
|
1014 |
|
1015 | if (failedDeps.length === 0) {
|
1016 | // use this module and remove it from list
|
1017 | usedModules.add(
|
1018 | /** @type {CssModule} */
|
1019 | list.pop());
|
1020 | success = true;
|
1021 | break;
|
1022 | }
|
1023 | }
|
1024 | }
|
1025 |
|
1026 | if (!success) {
|
1027 | // no module found => there is a conflict
|
1028 | // use list with fewest failed deps
|
1029 | // and emit a warning
|
1030 | const fallbackModule =
|
1031 | /** @type {CssModule[]} */
|
1032 | bestMatch.pop();
|
1033 |
|
1034 | if (!this.options.ignoreOrder) {
|
1035 | const reasons = moduleDependenciesReasons.get(
|
1036 | /** @type {CssModule} */
|
1037 | fallbackModule);
|
1038 | compilation.warnings.push(
|
1039 | /** @type {WebpackError} */
|
1040 | new Error([`chunk ${chunk.name || chunk.id} [${pluginName}]`, "Conflicting order. Following module has been added:", ` * ${
|
1041 |
|
1042 | fallbackModule.readableIdentifier(requestShortener)}`, "despite it was not able to fulfill desired ordering with these modules:", ...
|
1043 | /** @type {CssModule[]} */
|
1044 | bestMatchDeps.map(m => {
|
1045 | const goodReasonsMap = moduleDependenciesReasons.get(m);
|
1046 | const goodReasons = goodReasonsMap && goodReasonsMap.get(
|
1047 | /** @type {CssModule} */
|
1048 | fallbackModule);
|
1049 | const failedChunkGroups = Array.from(
|
1050 | /** @type {Set<ChunkGroup>} */
|
1051 |
|
1052 | /** @type {Map<CssModule, Set<ChunkGroup>>} */
|
1053 | reasons.get(m), cg => cg.name).join(", ");
|
1054 | const goodChunkGroups = goodReasons && Array.from(goodReasons, cg => cg.name).join(", ");
|
1055 | return [` * ${m.readableIdentifier(requestShortener)}`, ` - couldn't fulfill desired order of chunk group(s) ${failedChunkGroups}`, goodChunkGroups && ` - while fulfilling desired order of chunk group(s) ${goodChunkGroups}`].filter(Boolean).join("\n");
|
1056 | })].join("\n")));
|
1057 | }
|
1058 |
|
1059 | usedModules.add(
|
1060 |
|
1061 | fallbackModule);
|
1062 | }
|
1063 | }
|
1064 |
|
1065 | this._sortedModulesCache.set(chunk, usedModules);
|
1066 |
|
1067 | return usedModules;
|
1068 | }
|
1069 | |
1070 |
|
1071 |
|
1072 |
|
1073 |
|
1074 |
|
1075 |
|
1076 |
|
1077 |
|
1078 |
|
1079 |
|
1080 |
|
1081 |
|
1082 | renderContentAsset(compiler, compilation, chunk, modules, requestShortener, filenameTemplate, pathData) {
|
1083 | const usedModules = this.sortModules(compilation, chunk, modules, requestShortener);
|
1084 | const {
|
1085 | ConcatSource,
|
1086 | SourceMapSource,
|
1087 | RawSource
|
1088 | } = compiler.webpack.sources;
|
1089 | const source = new ConcatSource();
|
1090 | const externalsSource = new ConcatSource();
|
1091 |
|
1092 | for (const module of usedModules) {
|
1093 | let content = module.content.toString();
|
1094 | const readableIdentifier = module.readableIdentifier(requestShortener);
|
1095 | const startsWithAtRuleImport = /^@import url/.test(content);
|
1096 | let header;
|
1097 |
|
1098 | if (compilation.outputOptions.pathinfo) {
|
1099 |
|
1100 | const reqStr = readableIdentifier.replace(/\*\//g, "*_/");
|
1101 | const reqStrStar = "*".repeat(reqStr.length);
|
1102 | const headerStr = `/*!****${reqStrStar}****!*\\\n !*** ${reqStr} ***!\n \\****${reqStrStar}****/\n`;
|
1103 | header = new RawSource(headerStr);
|
1104 | }
|
1105 |
|
1106 | if (startsWithAtRuleImport) {
|
1107 | if (typeof header !== "undefined") {
|
1108 | externalsSource.add(header);
|
1109 | }
|
1110 |
|
1111 |
|
1112 |
|
1113 | if (module.media) {
|
1114 |
|
1115 |
|
1116 |
|
1117 | content = content.replace(/;|\s*$/, module.media);
|
1118 | }
|
1119 |
|
1120 | externalsSource.add(content);
|
1121 | externalsSource.add("\n");
|
1122 | } else {
|
1123 | if (typeof header !== "undefined") {
|
1124 | source.add(header);
|
1125 | }
|
1126 |
|
1127 | if (module.supports) {
|
1128 | source.add(`@supports (${module.supports}) {\n`);
|
1129 | }
|
1130 |
|
1131 | if (module.media) {
|
1132 | source.add(`@media ${module.media} {\n`);
|
1133 | }
|
1134 |
|
1135 | const needLayer = typeof module.layer !== "undefined";
|
1136 |
|
1137 | if (needLayer) {
|
1138 | source.add(`@layer${module.layer.length > 0 ? ` ${module.layer}` : ""} {\n`);
|
1139 | }
|
1140 |
|
1141 | const {
|
1142 | path: filename
|
1143 | } = compilation.getPathWithInfo(filenameTemplate, pathData);
|
1144 | const undoPath = getUndoPath(filename, compiler.outputPath, false);
|
1145 |
|
1146 | content = content.replace(new RegExp(ABSOLUTE_PUBLIC_PATH, "g"), "");
|
1147 | content = content.replace(new RegExp(SINGLE_DOT_PATH_SEGMENT, "g"), ".");
|
1148 | content = content.replace(new RegExp(AUTO_PUBLIC_PATH, "g"), undoPath);
|
1149 | const entryOptions = chunk.getEntryOptions();
|
1150 | const baseUriReplacement = entryOptions && entryOptions.baseUri || undoPath;
|
1151 | content = content.replace(new RegExp(BASE_URI, "g"), baseUriReplacement);
|
1152 |
|
1153 | if (module.sourceMap) {
|
1154 | source.add(new SourceMapSource(content, readableIdentifier, module.sourceMap.toString()));
|
1155 | } else {
|
1156 | source.add(new RawSource(content));
|
1157 | }
|
1158 |
|
1159 | source.add("\n");
|
1160 |
|
1161 | if (needLayer) {
|
1162 | source.add("}\n");
|
1163 | }
|
1164 |
|
1165 | if (module.media) {
|
1166 | source.add("}\n");
|
1167 | }
|
1168 |
|
1169 | if (module.supports) {
|
1170 | source.add("}\n");
|
1171 | }
|
1172 | }
|
1173 | }
|
1174 |
|
1175 | return new ConcatSource(externalsSource, source);
|
1176 | }
|
1177 |
|
1178 | }
|
1179 |
|
1180 | MiniCssExtractPlugin.pluginName = pluginName;
|
1181 | MiniCssExtractPlugin.pluginSymbol = pluginSymbol;
|
1182 | MiniCssExtractPlugin.loader = require.resolve("./loader");
|
1183 | module.exports = MiniCssExtractPlugin; |
\ | No newline at end of file |