UNPKG

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