UNPKG

4.25 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Florent Cailhol @ooflorent
4*/
5
6"use strict";
7
8const { ConcatSource } = require("webpack-sources");
9
10/** @typedef {import("webpack-sources").Source} Source */
11/** @typedef {import("./Generator").GenerateContext} GenerateContext */
12
13/**
14 * @param {InitFragment} fragment the init fragment
15 * @param {number} index index
16 * @returns {[InitFragment, number]} tuple with both
17 */
18const extractFragmentIndex = (fragment, index) => [fragment, index];
19
20/**
21 * @param {[InitFragment, number]} a first pair
22 * @param {[InitFragment, number]} b second pair
23 * @returns {number} sort value
24 */
25const sortFragmentWithIndex = ([a, i], [b, j]) => {
26 const stageCmp = a.stage - b.stage;
27 if (stageCmp !== 0) return stageCmp;
28 const positionCmp = a.position - b.position;
29 if (positionCmp !== 0) return positionCmp;
30 return i - j;
31};
32
33class InitFragment {
34 /**
35 * @param {string|Source} content the source code that will be included as initialization code
36 * @param {number} stage category of initialization code (contribute to order)
37 * @param {number} position position in the category (contribute to order)
38 * @param {string=} key unique key to avoid emitting the same initialization code twice
39 * @param {string|Source=} endContent the source code that will be included at the end of the module
40 */
41 constructor(content, stage, position, key, endContent) {
42 this.content = content;
43 this.stage = stage;
44 this.position = position;
45 this.key = key;
46 this.endContent = endContent;
47 }
48
49 /**
50 * @param {GenerateContext} generateContext context for generate
51 * @returns {string|Source} the source code that will be included as initialization code
52 */
53 getContent(generateContext) {
54 return this.content;
55 }
56
57 /**
58 * @param {GenerateContext} generateContext context for generate
59 * @returns {string|Source=} the source code that will be included at the end of the module
60 */
61 getEndContent(generateContext) {
62 return this.endContent;
63 }
64
65 static addToSource(source, initFragments, generateContext) {
66 if (initFragments.length > 0) {
67 // Sort fragments by position. If 2 fragments have the same position,
68 // use their index.
69 const sortedFragments = initFragments
70 .map(extractFragmentIndex)
71 .sort(sortFragmentWithIndex);
72
73 // Deduplicate fragments. If a fragment has no key, it is always included.
74 const keyedFragments = new Map();
75 for (const [fragment] of sortedFragments) {
76 if (typeof fragment.mergeAll === "function") {
77 if (!fragment.key) {
78 throw new Error(
79 `InitFragment with mergeAll function must have a valid key: ${fragment.constructor.name}`
80 );
81 }
82 const oldValue = keyedFragments.get(fragment.key);
83 if (oldValue === undefined) {
84 keyedFragments.set(fragment.key, fragment);
85 } else if (Array.isArray(oldValue)) {
86 oldValue.push(fragment);
87 } else {
88 keyedFragments.set(fragment.key, [oldValue, fragment]);
89 }
90 continue;
91 } else if (typeof fragment.merge === "function") {
92 const oldValue = keyedFragments.get(fragment.key);
93 if (oldValue !== undefined) {
94 keyedFragments.set(fragment.key, fragment.merge(oldValue));
95 continue;
96 }
97 }
98 keyedFragments.set(fragment.key || Symbol(), fragment);
99 }
100
101 const concatSource = new ConcatSource();
102 const endContents = [];
103 for (let fragment of keyedFragments.values()) {
104 if (Array.isArray(fragment)) {
105 fragment = fragment[0].mergeAll(fragment);
106 }
107 concatSource.add(fragment.getContent(generateContext));
108 const endContent = fragment.getEndContent(generateContext);
109 if (endContent) {
110 endContents.push(endContent);
111 }
112 }
113
114 concatSource.add(source);
115 for (const content of endContents.reverse()) {
116 concatSource.add(content);
117 }
118 return concatSource;
119 } else {
120 return source;
121 }
122 }
123}
124
125InitFragment.prototype.merge = undefined;
126
127InitFragment.STAGE_CONSTANTS = 10;
128InitFragment.STAGE_ASYNC_BOUNDARY = 20;
129InitFragment.STAGE_HARMONY_EXPORTS = 30;
130InitFragment.STAGE_HARMONY_IMPORTS = 40;
131InitFragment.STAGE_PROVIDES = 50;
132InitFragment.STAGE_ASYNC_DEPENDENCIES = 60;
133InitFragment.STAGE_ASYNC_HARMONY_IMPORTS = 70;
134
135module.exports = InitFragment;