webpack 5.2.1 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of webpack might be problematic. Click here for more details.

@@ -25,6 +25,12 @@ const createHash = require("../util/createHash");
25
25
  const contextify = require("../util/identifier").contextify;
26
26
  const makeSerializable = require("../util/makeSerializable");
27
27
  const propertyAccess = require("../util/propertyAccess");
28
+ const {
29
+ filterRuntime,
30
+ mergeRuntime,
31
+ runtimeToString,
32
+ intersectRuntime
33
+ } = require("../util/runtime");
28
34
 
29
35
  /** @typedef {import("eslint-scope").Scope} Scope */
30
36
  /** @typedef {import("webpack-sources").Source} Source */
@@ -103,6 +109,7 @@ const propertyAccess = require("../util/propertyAccess");
103
109
  * @typedef {Object} ExternalModuleInfo
104
110
  * @property {"external"} type
105
111
  * @property {Module} module
112
+ * @property {RuntimeSpec | boolean} runtimeCondition
106
113
  * @property {number} index
107
114
  * @property {string} name
108
115
  * @property {boolean} interopNamespaceObjectUsed
@@ -185,6 +192,7 @@ const joinIterableWithComma = iterable => {
185
192
  * @typedef {Object} ConcatenationEntry
186
193
  * @property {"concatenated" | "external"} type
187
194
  * @property {Module} module
195
+ * @property {RuntimeSpec | boolean} runtimeCondition
188
196
  */
189
197
 
190
198
  /**
@@ -586,10 +594,11 @@ class ConcatenatedModule extends Module {
586
594
  /**
587
595
  * @param {Module} rootModule the root module of the concatenation
588
596
  * @param {Set<Module>} modules all modules in the concatenation (including the root module)
597
+ * @param {RuntimeSpec} runtime the runtime
589
598
  * @param {Object=} associatedObjectForCache object for caching
590
599
  * @returns {ConcatenatedModule} the module
591
600
  */
592
- static create(rootModule, modules, associatedObjectForCache) {
601
+ static create(rootModule, modules, runtime, associatedObjectForCache) {
593
602
  const identifier = ConcatenatedModule._createIdentifier(
594
603
  rootModule,
595
604
  modules,
@@ -598,7 +607,8 @@ class ConcatenatedModule extends Module {
598
607
  return new ConcatenatedModule({
599
608
  identifier,
600
609
  rootModule,
601
- modules
610
+ modules,
611
+ runtime
602
612
  });
603
613
  }
604
614
 
@@ -606,9 +616,10 @@ class ConcatenatedModule extends Module {
606
616
  * @param {Object} options options
607
617
  * @param {string} options.identifier the identifier of the module
608
618
  * @param {Module=} options.rootModule the root module of the concatenation
619
+ * @param {RuntimeSpec} options.runtime the selected runtime
609
620
  * @param {Set<Module>=} options.modules all concatenated modules
610
621
  */
611
- constructor({ identifier, rootModule, modules }) {
622
+ constructor({ identifier, rootModule, modules, runtime }) {
612
623
  super("javascript/esm", null);
613
624
 
614
625
  // Info from Factory
@@ -618,6 +629,7 @@ class ConcatenatedModule extends Module {
618
629
  this.rootModule = rootModule;
619
630
  /** @type {Set<Module>} */
620
631
  this._modules = modules;
632
+ this._runtime = runtime;
621
633
  this.factoryMeta = rootModule && rootModule.factoryMeta;
622
634
 
623
635
  // Caching
@@ -637,6 +649,7 @@ class ConcatenatedModule extends Module {
637
649
  this._identifier = m._identifier;
638
650
  this.rootModule = m.rootModule;
639
651
  this._modules = m._modules;
652
+ this._runtime = m._runtime;
640
653
  }
641
654
  /**
642
655
  * @returns {Set<string>} types available (do not mutate)
@@ -789,7 +802,7 @@ class ConcatenatedModule extends Module {
789
802
 
790
803
  /**
791
804
  * @param {Module} module a module
792
- * @returns {ModuleGraphConnection[]} imported modules in order
805
+ * @returns {Iterable<{ connection: ModuleGraphConnection, runtimeCondition: RuntimeSpec | boolean }>} imported modules in order
793
806
  */
794
807
  const getConcatenatedImports = module => {
795
808
  let connections = Array.from(moduleGraph.getOutgoingConnections(module));
@@ -816,14 +829,38 @@ class ConcatenatedModule extends Module {
816
829
  references.sort(
817
830
  concatComparators(bySourceOrder, keepOriginalOrder(references))
818
831
  );
819
- return references.map(({ connection }) => connection);
832
+ /** @type {Map<Module, { connection, runtimeCondition }>} */
833
+ const referencesMap = new Map();
834
+ for (const { connection } of references) {
835
+ const runtimeCondition = filterRuntime(runtime, r =>
836
+ connection.isTargetActive(r)
837
+ );
838
+ const module = connection.module;
839
+ const entry = referencesMap.get(module);
840
+ if (entry === undefined) {
841
+ referencesMap.set(module, { connection, runtimeCondition });
842
+ continue;
843
+ }
844
+ if (runtimeCondition === false || entry.runtimeCondition === true)
845
+ continue;
846
+ if (entry.runtimeCondition === false || runtimeCondition === true) {
847
+ entry.runtimeCondition = runtimeCondition;
848
+ continue;
849
+ }
850
+ entry.runtimeCondition = mergeRuntime(
851
+ entry.runtimeCondition,
852
+ runtimeCondition
853
+ );
854
+ }
855
+ return referencesMap.values();
820
856
  };
821
857
 
822
858
  /**
823
859
  * @param {ModuleGraphConnection} connection graph connection
860
+ * @param {RuntimeSpec | boolean} runtimeCondition runtime condition
824
861
  * @returns {void}
825
862
  */
826
- const enterModule = connection => {
863
+ const enterModule = (connection, runtimeCondition) => {
827
864
  const module = connection.module;
828
865
  if (!module) return;
829
866
  if (existingEntries.has(module)) {
@@ -831,11 +868,20 @@ class ConcatenatedModule extends Module {
831
868
  }
832
869
  if (modulesSet.has(module)) {
833
870
  existingEntries.add(module);
871
+ if (runtimeCondition !== true) {
872
+ throw new Error(
873
+ `Cannot runtime-conditional concatenate a module (${module.identifier()} in ${this.rootModule.identifier()}, ${
874
+ runtimeCondition && runtimeToString(runtimeCondition)
875
+ }). This should not happen.`
876
+ );
877
+ }
834
878
  const imports = getConcatenatedImports(module);
835
- imports.forEach(enterModule);
879
+ for (const { connection, runtimeCondition } of imports)
880
+ enterModule(connection, runtimeCondition);
836
881
  list.push({
837
882
  type: "concatenated",
838
- module: connection.module
883
+ module: connection.module,
884
+ runtimeCondition
839
885
  });
840
886
  } else {
841
887
  existingEntries.add(connection.module);
@@ -846,17 +892,20 @@ class ConcatenatedModule extends Module {
846
892
  // could be replaced by some other process (i. e. also replaced with a
847
893
  // concatenated module)
848
894
  return connection.module;
849
- }
895
+ },
896
+ runtimeCondition
850
897
  });
851
898
  }
852
899
  };
853
900
 
854
901
  existingEntries.add(rootModule);
855
902
  const imports = getConcatenatedImports(rootModule);
856
- imports.forEach(enterModule);
903
+ for (const { connection, runtimeCondition } of imports)
904
+ enterModule(connection, runtimeCondition);
857
905
  list.push({
858
906
  type: "concatenated",
859
- module: rootModule
907
+ module: rootModule,
908
+ runtimeCondition: true
860
909
  });
861
910
 
862
911
  return list;
@@ -908,10 +957,11 @@ class ConcatenatedModule extends Module {
908
957
  runtimeTemplate,
909
958
  moduleGraph,
910
959
  chunkGraph,
911
- runtime
960
+ runtime: generationRuntime
912
961
  }) {
913
962
  /** @type {Set<string>} */
914
963
  const runtimeRequirements = new Set();
964
+ const runtime = intersectRuntime(generationRuntime, this._runtime);
915
965
 
916
966
  const requestShortener = runtimeTemplate.requestShortener;
917
967
  // Meta info for each module
@@ -1337,6 +1387,7 @@ ${defineGetters}`
1337
1387
  // evaluate modules in order
1338
1388
  for (const info of modulesWithInfo) {
1339
1389
  let name;
1390
+ let isConditional = false;
1340
1391
  switch (info.type) {
1341
1392
  case "concatenated": {
1342
1393
  result.add(
@@ -1353,13 +1404,23 @@ ${defineGetters}`
1353
1404
  name = info.namespaceObjectName;
1354
1405
  break;
1355
1406
  }
1356
- case "external":
1407
+ case "external": {
1357
1408
  result.add(
1358
1409
  `\n// EXTERNAL MODULE: ${info.module.readableIdentifier(
1359
1410
  requestShortener
1360
1411
  )}\n`
1361
1412
  );
1362
1413
  runtimeRequirements.add(RuntimeGlobals.require);
1414
+ const condition = runtimeTemplate.runtimeConditionExpression({
1415
+ chunkGraph,
1416
+ runtimeCondition: info.runtimeCondition,
1417
+ runtime,
1418
+ runtimeRequirements
1419
+ });
1420
+ if (condition !== "true") {
1421
+ isConditional = true;
1422
+ result.add(`if (${condition}) {\n`);
1423
+ }
1363
1424
  result.add(
1364
1425
  `var ${info.name} = __webpack_require__(${JSON.stringify(
1365
1426
  chunkGraph.getModuleId(info.module)
@@ -1367,6 +1428,7 @@ ${defineGetters}`
1367
1428
  );
1368
1429
  name = info.name;
1369
1430
  break;
1431
+ }
1370
1432
  default:
1371
1433
  // @ts-expect-error never is expected here
1372
1434
  throw new Error(`Unsupported concatenation entry type ${info.type}`);
@@ -1375,7 +1437,7 @@ ${defineGetters}`
1375
1437
  if (info.module.buildMeta.exportsType === "default") {
1376
1438
  runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
1377
1439
  result.add(
1378
- `\nvar ${info.interopNamespaceObjectName} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${name}, 2);\n`
1440
+ `\nvar ${info.interopNamespaceObjectName} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${name}, 2);`
1379
1441
  );
1380
1442
  } else if (
1381
1443
  info.module.buildMeta.exportsType === "flagged" ||
@@ -1384,16 +1446,19 @@ ${defineGetters}`
1384
1446
  ) {
1385
1447
  runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
1386
1448
  result.add(
1387
- `\nvar ${info.interopNamespaceObjectName} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${name});\n`
1449
+ `\nvar ${info.interopNamespaceObjectName} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${name});`
1388
1450
  );
1389
1451
  }
1390
1452
  }
1391
1453
  if (info.interopDefaultAccessUsed) {
1392
1454
  runtimeRequirements.add(RuntimeGlobals.compatGetDefaultExport);
1393
1455
  result.add(
1394
- `\nvar ${info.interopDefaultAccessName} = /*#__PURE__*/${RuntimeGlobals.compatGetDefaultExport}(${name});\n`
1456
+ `\nvar ${info.interopDefaultAccessName} = /*#__PURE__*/${RuntimeGlobals.compatGetDefaultExport}(${name});`
1395
1457
  );
1396
1458
  }
1459
+ if (isConditional) {
1460
+ result.add("\n}");
1461
+ }
1397
1462
  }
1398
1463
 
1399
1464
  /** @type {CodeGenerationResult} */
@@ -1539,6 +1604,7 @@ ${defineGetters}`
1539
1604
  return {
1540
1605
  type: "external",
1541
1606
  module: info.module,
1607
+ runtimeCondition: info.runtimeCondition,
1542
1608
  index,
1543
1609
  name: undefined,
1544
1610
  interopNamespaceObjectUsed: false,
@@ -1601,7 +1667,7 @@ ${defineGetters}`
1601
1667
  for (const info of this._createConcatenationList(
1602
1668
  this.rootModule,
1603
1669
  this._modules,
1604
- runtime,
1670
+ intersectRuntime(runtime, this._runtime),
1605
1671
  chunkGraph.moduleGraph
1606
1672
  )) {
1607
1673
  switch (info.type) {
@@ -1620,7 +1686,8 @@ ${defineGetters}`
1620
1686
  const obj = new ConcatenatedModule({
1621
1687
  identifier: undefined,
1622
1688
  rootModule: undefined,
1623
- modules: undefined
1689
+ modules: undefined,
1690
+ runtime: undefined
1624
1691
  });
1625
1692
  obj.deserialize(context);
1626
1693
  return obj;
@@ -14,7 +14,13 @@ const { STAGE_DEFAULT } = require("../OptimizationStages");
14
14
  const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
15
15
  const StackedMap = require("../util/StackedMap");
16
16
  const { compareModulesByIdentifier } = require("../util/comparators");
17
- const { intersectRuntime, mergeRuntimeOwned } = require("../util/runtime");
17
+ const {
18
+ intersectRuntime,
19
+ mergeRuntimeOwned,
20
+ filterRuntime,
21
+ runtimeToString,
22
+ mergeRuntime
23
+ } = require("../util/runtime");
18
24
  const ConcatenatedModule = require("./ConcatenatedModule");
19
25
 
20
26
  /** @typedef {import("../Compilation")} Compilation */
@@ -211,13 +217,26 @@ class ModuleConcatenationPlugin {
211
217
  // the other configuration is better and we can skip this one
212
218
  if (usedAsInner.has(currentRoot)) continue;
213
219
 
214
- let runtime = undefined;
220
+ let chunkRuntime = undefined;
215
221
  for (const r of chunkGraph.getModuleRuntimes(currentRoot)) {
216
- runtime = mergeRuntimeOwned(runtime, r);
222
+ chunkRuntime = mergeRuntimeOwned(chunkRuntime, r);
217
223
  }
224
+ const exportsInfo = moduleGraph.getExportsInfo(currentRoot);
225
+ const filteredRuntime = filterRuntime(chunkRuntime, r =>
226
+ exportsInfo.isModuleUsed(r)
227
+ );
228
+ const runtime =
229
+ filteredRuntime === true
230
+ ? chunkRuntime
231
+ : filteredRuntime === false
232
+ ? undefined
233
+ : filteredRuntime;
218
234
 
219
235
  // create a configuration with the root
220
- const currentConfiguration = new ConcatConfiguration(currentRoot);
236
+ const currentConfiguration = new ConcatConfiguration(
237
+ currentRoot,
238
+ runtime
239
+ );
221
240
 
222
241
  // cache failures to add modules
223
242
  const failureCache = new Map();
@@ -313,6 +332,7 @@ class ModuleConcatenationPlugin {
313
332
  let newModule = ConcatenatedModule.create(
314
333
  rootModule,
315
334
  modules,
335
+ concatConfiguration.runtime,
316
336
  compiler.root
317
337
  );
318
338
 
@@ -657,6 +677,50 @@ class ModuleConcatenationPlugin {
657
677
  return problem;
658
678
  }
659
679
 
680
+ if (runtime !== undefined && typeof runtime !== "string") {
681
+ // Module must be consistently referenced in the same runtimes
682
+ /** @type {Map<Module, boolean | RuntimeSpec>} */
683
+ const runtimeConditionMap = new Map();
684
+ for (const connection of incomingConnections) {
685
+ const runtimeCondition = filterRuntime(runtime, runtime => {
686
+ return connection.isTargetActive(runtime);
687
+ });
688
+ if (runtimeCondition === false) continue;
689
+ const old = runtimeConditionMap.get(connection.originModule) || false;
690
+ if (old === true) continue;
691
+ if (old !== false && runtimeCondition !== true) {
692
+ runtimeConditionMap.set(
693
+ connection.originModule,
694
+ mergeRuntime(old, runtimeCondition)
695
+ );
696
+ } else {
697
+ runtimeConditionMap.set(connection.originModule, runtimeCondition);
698
+ }
699
+ }
700
+ const otherRuntimeConnections = Array.from(runtimeConditionMap).filter(
701
+ ([, runtimeCondition]) => typeof runtimeCondition !== "boolean"
702
+ );
703
+ if (otherRuntimeConnections.length > 0) {
704
+ const problem = requestShortener => {
705
+ return `Module ${module.readableIdentifier(
706
+ requestShortener
707
+ )} is runtime-dependent referenced by these modules: ${Array.from(
708
+ otherRuntimeConnections,
709
+ ([module, runtimeCondition]) =>
710
+ `${module.readableIdentifier(
711
+ requestShortener
712
+ )} (expected runtime ${runtimeToString(
713
+ runtime
714
+ )}, module is only referenced in ${runtimeToString(
715
+ /** @type {RuntimeSpec} */ (runtimeCondition)
716
+ )})`
717
+ ).join(", ")}`;
718
+ };
719
+ failureCache.set(module, problem); // cache failures for performance
720
+ return problem;
721
+ }
722
+ }
723
+
660
724
  const incomingModules = Array.from(
661
725
  new Set(incomingConnections.map(c => c.originModule))
662
726
  ).sort(compareModulesByIdentifier);
@@ -689,11 +753,12 @@ class ModuleConcatenationPlugin {
689
753
 
690
754
  class ConcatConfiguration {
691
755
  /**
692
- *
693
756
  * @param {Module} rootModule the root module
757
+ * @param {RuntimeSpec} runtime the runtime
694
758
  */
695
- constructor(rootModule) {
759
+ constructor(rootModule, runtime) {
696
760
  this.rootModule = rootModule;
761
+ this.runtime = runtime;
697
762
  /** @type {StackedMap<Module, true>} */
698
763
  this.modules = new StackedMap();
699
764
  this.modules.set(rootModule, true);
@@ -50,6 +50,12 @@ const globToRegexp = (glob, cache) => {
50
50
  };
51
51
 
52
52
  class SideEffectsFlagPlugin {
53
+ /**
54
+ * @param {boolean} analyseSource analyse source code for side effects
55
+ */
56
+ constructor(analyseSource = true) {
57
+ this._analyseSource = analyseSource;
58
+ }
53
59
  /**
54
60
  * Apply the plugin
55
61
  * @param {Compiler} compiler the compiler instance
@@ -98,108 +104,114 @@ class SideEffectsFlagPlugin {
98
104
  }
99
105
  return module;
100
106
  });
101
- /**
102
- * @param {JavascriptParser} parser the parser
103
- * @returns {void}
104
- */
105
- const parserHandler = parser => {
106
- let hasSideEffects = false;
107
- parser.hooks.program.tap("SideEffectsFlagPlugin", () => {
108
- hasSideEffects = false;
109
- });
110
- parser.hooks.statement.tap(
111
- { name: "SideEffectsFlagPlugin", stage: -100 },
112
- statement => {
113
- if (hasSideEffects) return;
114
- if (parser.scope.topLevelScope !== true) return;
115
- switch (statement.type) {
116
- case "ExpressionStatement":
117
- if (!parser.isPure(statement.expression, statement.range[0])) {
118
- hasSideEffects = true;
119
- }
120
- break;
121
- case "IfStatement":
122
- case "WhileStatement":
123
- case "DoWhileStatement":
124
- if (!parser.isPure(statement.test, statement.range[0])) {
125
- hasSideEffects = true;
126
- }
127
- // statement hook will be called for child statements too
128
- break;
129
- case "ForStatement":
130
- if (
131
- !parser.isPure(statement.init, statement.range[0]) ||
132
- !parser.isPure(
133
- statement.test,
134
- statement.init
135
- ? statement.init.range[1]
136
- : statement.range[0]
137
- ) ||
138
- !parser.isPure(
139
- statement.update,
140
- statement.test
141
- ? statement.test.range[1]
142
- : statement.init
143
- ? statement.init.range[1]
144
- : statement.range[0]
145
- )
146
- ) {
147
- hasSideEffects = true;
148
- }
149
- // statement hook will be called for child statements too
150
- break;
151
- case "SwitchStatement":
152
- if (
153
- !parser.isPure(statement.discriminant, statement.range[0])
154
- ) {
155
- hasSideEffects = true;
156
- }
157
- // statement hook will be called for child statements too
158
- break;
159
- case "VariableDeclaration":
160
- case "ClassDeclaration":
161
- case "FunctionDeclaration":
162
- if (!parser.isPure(statement, statement.range[0])) {
163
- hasSideEffects = true;
164
- }
165
- break;
166
- case "ExportDefaultDeclaration":
167
- if (!parser.isPure(statement.declaration, statement.range[0])) {
168
- hasSideEffects = true;
169
- }
170
- break;
171
- case "ExportNamedDeclaration":
172
- if (statement.source) {
107
+ if (this._analyseSource) {
108
+ /**
109
+ * @param {JavascriptParser} parser the parser
110
+ * @returns {void}
111
+ */
112
+ const parserHandler = parser => {
113
+ let hasSideEffects = false;
114
+ parser.hooks.program.tap("SideEffectsFlagPlugin", () => {
115
+ hasSideEffects = false;
116
+ });
117
+ parser.hooks.statement.tap(
118
+ { name: "SideEffectsFlagPlugin", stage: -100 },
119
+ statement => {
120
+ if (hasSideEffects) return;
121
+ if (parser.scope.topLevelScope !== true) return;
122
+ switch (statement.type) {
123
+ case "ExpressionStatement":
124
+ if (
125
+ !parser.isPure(statement.expression, statement.range[0])
126
+ ) {
127
+ hasSideEffects = true;
128
+ }
129
+ break;
130
+ case "IfStatement":
131
+ case "WhileStatement":
132
+ case "DoWhileStatement":
133
+ if (!parser.isPure(statement.test, statement.range[0])) {
134
+ hasSideEffects = true;
135
+ }
136
+ // statement hook will be called for child statements too
137
+ break;
138
+ case "ForStatement":
139
+ if (
140
+ !parser.isPure(statement.init, statement.range[0]) ||
141
+ !parser.isPure(
142
+ statement.test,
143
+ statement.init
144
+ ? statement.init.range[1]
145
+ : statement.range[0]
146
+ ) ||
147
+ !parser.isPure(
148
+ statement.update,
149
+ statement.test
150
+ ? statement.test.range[1]
151
+ : statement.init
152
+ ? statement.init.range[1]
153
+ : statement.range[0]
154
+ )
155
+ ) {
156
+ hasSideEffects = true;
157
+ }
158
+ // statement hook will be called for child statements too
159
+ break;
160
+ case "SwitchStatement":
161
+ if (
162
+ !parser.isPure(statement.discriminant, statement.range[0])
163
+ ) {
164
+ hasSideEffects = true;
165
+ }
166
+ // statement hook will be called for child statements too
167
+ break;
168
+ case "VariableDeclaration":
169
+ case "ClassDeclaration":
170
+ case "FunctionDeclaration":
171
+ if (!parser.isPure(statement, statement.range[0])) {
172
+ hasSideEffects = true;
173
+ }
174
+ break;
175
+ case "ExportDefaultDeclaration":
176
+ if (
177
+ !parser.isPure(statement.declaration, statement.range[0])
178
+ ) {
179
+ hasSideEffects = true;
180
+ }
181
+ break;
182
+ case "ExportNamedDeclaration":
183
+ if (statement.source) {
184
+ hasSideEffects = true;
185
+ }
186
+ break;
187
+ case "LabeledStatement":
188
+ case "BlockStatement":
189
+ // statement hook will be called for child statements too
190
+ break;
191
+ case "EmptyStatement":
192
+ break;
193
+ case "ImportDeclaration":
194
+ // imports will be handled by the dependencies
195
+ break;
196
+ default:
173
197
  hasSideEffects = true;
174
- }
175
- break;
176
- case "LabeledStatement":
177
- case "BlockStatement":
178
- // statement hook will be called for child statements too
179
- break;
180
- case "EmptyStatement":
181
- break;
182
- case "ImportDeclaration":
183
- // imports will be handled by the dependencies
184
- break;
185
- default:
186
- hasSideEffects = true;
187
- break;
198
+ break;
199
+ }
188
200
  }
189
- }
190
- );
191
- parser.hooks.finish.tap("SideEffectsFlagPlugin", () => {
192
- if (!hasSideEffects) {
193
- parser.state.module.buildMeta.sideEffectFree = true;
194
- }
195
- });
196
- };
197
- for (const key of [
198
- "javascript/auto",
199
- "javascript/esm",
200
- "javascript/dynamic"
201
- ]) {
202
- nmf.hooks.parser.for(key).tap("SideEffectsFlagPlugin", parserHandler);
201
+ );
202
+ parser.hooks.finish.tap("SideEffectsFlagPlugin", () => {
203
+ if (!hasSideEffects) {
204
+ parser.state.module.buildMeta.sideEffectFree = true;
205
+ }
206
+ });
207
+ };
208
+ for (const key of [
209
+ "javascript/auto",
210
+ "javascript/esm",
211
+ "javascript/dynamic"
212
+ ]) {
213
+ nmf.hooks.parser.for(key).tap("SideEffectsFlagPlugin", parserHandler);
214
+ }
203
215
  }
204
216
  });
205
217
  compiler.hooks.compilation.tap("SideEffectsFlagPlugin", compilation => {
@@ -0,0 +1,29 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ */
4
+
5
+ "use strict";
6
+
7
+ const RuntimeGlobals = require("../RuntimeGlobals");
8
+ const RuntimeModule = require("../RuntimeModule");
9
+
10
+ class RuntimeIdRuntimeModule extends RuntimeModule {
11
+ constructor() {
12
+ super("runtimeId");
13
+ }
14
+
15
+ /**
16
+ * @returns {string} runtime code
17
+ */
18
+ generate() {
19
+ const { chunk, compilation } = this;
20
+ const { chunkGraph } = compilation;
21
+ const runtime = chunk.runtime;
22
+ if (typeof runtime !== "string")
23
+ throw new Error("RuntimeIdRuntimeModule must be in a single runtime");
24
+ const id = chunkGraph.getRuntimeId(runtime);
25
+ return `${RuntimeGlobals.runtimeId} = ${JSON.stringify(id)};`;
26
+ }
27
+ }
28
+
29
+ module.exports = RuntimeIdRuntimeModule;
@@ -25,6 +25,17 @@ const compileBooleanMatcher = map => {
25
25
  const negativeItems = Object.keys(map).filter(i => !map[i]);
26
26
  if (positiveItems.length === 0) return false;
27
27
  if (negativeItems.length === 0) return true;
28
+ return compileBooleanMatcherFromLists(positiveItems, negativeItems);
29
+ };
30
+
31
+ /**
32
+ * @param {string[]} positiveItems positive items
33
+ * @param {string[]} negativeItems negative items
34
+ * @returns {function(string): string} a template function to determine the value at runtime
35
+ */
36
+ const compileBooleanMatcherFromLists = (positiveItems, negativeItems) => {
37
+ if (positiveItems.length === 0) return () => "false";
38
+ if (negativeItems.length === 0) return () => "true";
28
39
  if (positiveItems.length === 1)
29
40
  return value => `${toSimpleString(positiveItems[0])} == ${value}`;
30
41
  if (negativeItems.length === 1)
@@ -188,5 +199,6 @@ const itemsToRegexp = itemsArr => {
188
199
  return `(${conditional.join("|")})`;
189
200
  };
190
201
 
202
+ compileBooleanMatcher.fromLists = compileBooleanMatcherFromLists;
203
+ compileBooleanMatcher.itemsToRegexp = itemsToRegexp;
191
204
  module.exports = compileBooleanMatcher;
192
- module.exports.itemsToRegexp = itemsToRegexp;