@atlaspack/packager-js 2.14.10 → 2.15.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @atlaspack/packager-js
2
2
 
3
+ ## 2.15.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#627](https://github.com/atlassian-labs/atlaspack/pull/627) [`85c52d3`](https://github.com/atlassian-labs/atlaspack/commit/85c52d3f7717b3c84a118d18ab98cfbfd71dcbd2) Thanks [@benjervis](https://github.com/benjervis)! - Expands the situations where scope hoisting may be applied to include assets with no dependencies, regardless of whether if they have a wrapped ancestor.
8
+
9
+ Can be enabled with the `applyScopeHoistingImprovement` feature flag.
10
+
11
+ ### Patch Changes
12
+
13
+ - [#632](https://github.com/atlassian-labs/atlaspack/pull/632) [`10fbcfb`](https://github.com/atlassian-labs/atlaspack/commit/10fbcfbfa49c7a83da5d7c40983e36e87f524a75) Thanks [@marcins](https://github.com/marcins)! - Added a new feature flag `inlineConstOptimisationFix` which when enabled changes the behaviour for output of constant modules. This fixes two issues with constant modules:
14
+
15
+ - Previously constant modules, if they needed a namespace anywhere, would have a namespace everywhere, with this change they only have a namespace in the bundles where needed.
16
+ - Previously in the case of wrapped assets, a constant module dependnecy of that wrapped asset would be rendered after the module - which meant the minifier would not be able to inline the constants safely. With this flag all constant modules are rendered at the top of the bundle.
17
+
18
+ - Updated dependencies [[`10fbcfb`](https://github.com/atlassian-labs/atlaspack/commit/10fbcfbfa49c7a83da5d7c40983e36e87f524a75), [`85c52d3`](https://github.com/atlassian-labs/atlaspack/commit/85c52d3f7717b3c84a118d18ab98cfbfd71dcbd2), [`e39c6cf`](https://github.com/atlassian-labs/atlaspack/commit/e39c6cf05f7e95ce5420dbcea66f401b1cbd397c)]:
19
+ - @atlaspack/feature-flags@2.18.0
20
+ - @atlaspack/utils@2.15.0
21
+ - @atlaspack/types@2.15.2
22
+ - @atlaspack/plugin@2.14.12
23
+
24
+ ## 2.14.11
25
+
26
+ ### Patch Changes
27
+
28
+ - Updated dependencies [[`73ea3c4`](https://github.com/atlassian-labs/atlaspack/commit/73ea3c4d85d4401fdd15abcbf988237e890e7ad3), [`b1b3693`](https://github.com/atlassian-labs/atlaspack/commit/b1b369317c66f8a431c170df2ebba4fa5b2e38ef)]:
29
+ - @atlaspack/feature-flags@2.17.0
30
+ - @atlaspack/utils@2.14.11
31
+ - @atlaspack/types@2.15.1
32
+ - @atlaspack/plugin@2.14.11
33
+
3
34
  ## 2.14.10
4
35
 
5
36
  ### Patch Changes
@@ -115,7 +115,10 @@ class ScopeHoistingPackager {
115
115
  }
116
116
  async package() {
117
117
  var _sourceMap;
118
- let wrappedAssets = await this.loadAssets();
118
+ let {
119
+ wrapped: wrappedAssets,
120
+ constant: constantAssets
121
+ } = await this.loadAssets();
119
122
  this.buildExportedSymbols();
120
123
 
121
124
  // If building a library, the target is actually another bundler rather
@@ -143,6 +146,14 @@ class ScopeHoistingPackager {
143
146
  res += content + '\n';
144
147
  lineCount += lines + 1;
145
148
  };
149
+ if ((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix')) {
150
+ // Write out all constant modules used by this bundle
151
+ for (let asset of constantAssets) {
152
+ if (!this.seenAssets.has(asset.id)) {
153
+ processAsset(asset);
154
+ }
155
+ }
156
+ }
146
157
 
147
158
  // Hoist wrapped asset to the top of the bundle to ensure that they are registered
148
159
  // before they are used.
@@ -265,6 +276,7 @@ class ScopeHoistingPackager {
265
276
  maxConcurrent: 32
266
277
  });
267
278
  let wrapped = [];
279
+ let constant = [];
268
280
  this.bundle.traverseAssets(asset => {
269
281
  queue.add(async () => {
270
282
  let [code, map] = await Promise.all([asset.getCode(), this.bundle.env.sourceMap ? asset.getMapBuffer() : null]);
@@ -278,38 +290,76 @@ class ScopeHoistingPackager {
278
290
  if (!asset.meta.isConstantModule || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.priority === 'lazy')) {
279
291
  this.wrappedAssets.add(asset.id);
280
292
  wrapped.push(asset);
293
+ } else if ((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix') && asset.meta.isConstantModule) {
294
+ constant.push(asset);
281
295
  }
282
296
  }
283
297
  });
284
- for (let wrappedAssetRoot of [...wrapped]) {
285
- this.bundle.traverseAssets((asset, _, actions) => {
286
- if (asset === wrappedAssetRoot) {
287
- return;
288
- }
289
- if (this.wrappedAssets.has(asset.id)) {
290
- actions.skipChildren();
291
- return;
292
- }
293
- // This prevents children of a wrapped asset also being wrapped - it's an "unsafe" optimisation
294
- // that should only be used when you know (or think you know) what you're doing.
295
- //
296
- // In particular this can force an async bundle to be scope hoisted where it previously would not be
297
- // due to the entry asset being wrapped.
298
- if (this.forceSkipWrapAssets.length > 0 && this.forceSkipWrapAssets.some(p => p === _path().default.relative(this.options.projectRoot, asset.filePath))) {
299
- this.logger.verbose({
300
- message: `Force skipping wrapping of ${_path().default.relative(this.options.projectRoot, asset.filePath)}`
301
- });
302
- actions.skipChildren();
303
- return;
304
- }
305
- if (!asset.meta.isConstantModule) {
306
- this.wrappedAssets.add(asset.id);
307
- wrapped.push(asset);
308
- }
309
- }, wrappedAssetRoot);
298
+ if ((0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovement')) {
299
+ // Tracks which assets have been assigned to a wrap group
300
+ let assignedAssets = new Set();
301
+ for (let wrappedAsset of wrapped) {
302
+ this.bundle.traverseAssets((asset, _, actions) => {
303
+ if (asset === wrappedAsset) {
304
+ return;
305
+ }
306
+ if (this.wrappedAssets.has(asset.id)) {
307
+ actions.skipChildren();
308
+ return;
309
+ }
310
+ if (assignedAssets.has(asset) || this.isReExported(asset)) {
311
+ wrapped.push(asset);
312
+ this.wrappedAssets.add(asset.id);
313
+ actions.skipChildren();
314
+ return;
315
+ }
316
+ assignedAssets.add(asset);
317
+ }, wrappedAsset);
318
+ }
319
+ } else {
320
+ for (let wrappedAssetRoot of [...wrapped]) {
321
+ this.bundle.traverseAssets((asset, _, actions) => {
322
+ if (asset === wrappedAssetRoot) {
323
+ return;
324
+ }
325
+ if (this.wrappedAssets.has(asset.id)) {
326
+ actions.skipChildren();
327
+ return;
328
+ }
329
+ // This prevents children of a wrapped asset also being wrapped - it's an "unsafe" optimisation
330
+ // that should only be used when you know (or think you know) what you're doing.
331
+ //
332
+ // In particular this can force an async bundle to be scope hoisted where it previously would not be
333
+ // due to the entry asset being wrapped.
334
+ if (this.forceSkipWrapAssets.length > 0 && this.forceSkipWrapAssets.some(p => p === _path().default.relative(this.options.projectRoot, asset.filePath))) {
335
+ this.logger.verbose({
336
+ message: `Force skipping wrapping of ${_path().default.relative(this.options.projectRoot, asset.filePath)}`
337
+ });
338
+ actions.skipChildren();
339
+ return;
340
+ }
341
+ if (!asset.meta.isConstantModule) {
342
+ this.wrappedAssets.add(asset.id);
343
+ wrapped.push(asset);
344
+ }
345
+ }, wrappedAssetRoot);
346
+ }
310
347
  }
311
348
  this.assetOutputs = new Map(await queue.run());
312
- return wrapped;
349
+ return {
350
+ wrapped,
351
+ constant
352
+ };
353
+ }
354
+ isReExported(asset) {
355
+ let parentSymbols = this.bundleGraph.getIncomingDependencies(asset).map(dep => this.bundleGraph.getAssetWithDependency(dep)).flatMap(parent => {
356
+ if (parent == null) {
357
+ return [];
358
+ }
359
+ return this.bundleGraph.getExportedSymbols(parent, this.bundle);
360
+ });
361
+ let assetSymbols = this.bundleGraph.getExportedSymbols(asset, this.bundle);
362
+ return assetSymbols.some(assetSymbol => parentSymbols.some(parentSymbol => parentSymbol.symbol === assetSymbol.symbol));
313
363
  }
314
364
  buildExportedSymbols() {
315
365
  if (!this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') {
@@ -489,13 +539,22 @@ class ScopeHoistingPackager {
489
539
  // outside our parcelRequire.register wrapper. This is safe because all
490
540
  // assets referenced by this asset will also be wrapped. Otherwise, inline the
491
541
  // asset content where the import statement was.
492
- if (shouldWrap) {
493
- depContent.push(this.visitAsset(resolved));
542
+ if ((0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovement')) {
543
+ if (!this.wrappedAssets.has(resolved.id)) {
544
+ let [depCode, depMap, depLines] = this.visitAsset(resolved);
545
+ res = depCode + '\n' + res;
546
+ lines += 1 + depLines;
547
+ map = depMap;
548
+ }
494
549
  } else {
495
- let [depCode, depMap, depLines] = this.visitAsset(resolved);
496
- res = depCode + '\n' + res;
497
- lines += 1 + depLines;
498
- map = depMap;
550
+ if (shouldWrap) {
551
+ depContent.push(this.visitAsset(resolved));
552
+ } else {
553
+ let [depCode, depMap, depLines] = this.visitAsset(resolved);
554
+ res = depCode + '\n' + res;
555
+ lines += 1 + depLines;
556
+ map = depMap;
557
+ }
499
558
  }
500
559
  }
501
560
 
@@ -874,20 +933,26 @@ ${code}
874
933
  // If there's no __esModule flag, and default is a used symbol, we need
875
934
  // to insert an interop helper.
876
935
  let defaultInterop = asset.symbols.hasExportSymbol('*') && usedSymbols.has('default') && !asset.symbols.hasExportSymbol('__esModule');
877
- let usedNamespace =
878
- // If the asset has * in its used symbols, we might need the exports namespace.
879
- // The one case where this isn't true is in ESM library entries, where the only
880
- // dependency on * is the entry dependency. In this case, we will use ESM exports
881
- // instead of the namespace object.
882
- usedSymbols.has('*') && (this.bundle.env.outputFormat !== 'esmodule' || !this.bundle.env.isLibrary || asset !== this.bundle.getMainEntry() || this.bundleGraph.getIncomingDependencies(asset).some(dep => !dep.isEntry && this.bundle.hasDependency(dep) && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep)).has('*'))) ||
883
- // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
884
- // we fallback on the namespace object.
885
- asset.symbols.hasExportSymbol('*') && [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s)) ||
886
- // If the exports has this asset's namespace (e.g. ESM output from CJS input),
887
- // include the namespace object for the default export.
888
- this.exportedSymbols.has(`$${assetId}$exports`) ||
889
- // CommonJS library bundle entries always need a namespace.
890
- this.bundle.env.isLibrary && this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry();
936
+ let usedNamespace;
937
+ if ((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix') && asset.meta.isConstantModule) {
938
+ // Only set usedNamespace if there is an incoming dependency in the current bundle that uses '*'
939
+ usedNamespace = this.bundleGraph.getIncomingDependencies(asset).some(dep => this.bundle.hasDependency(dep) && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep)).has('*'));
940
+ } else {
941
+ usedNamespace =
942
+ // If the asset has * in its used symbols, we might need the exports namespace.
943
+ // The one case where this isn't true is in ESM library entries, where the only
944
+ // dependency on * is the entry dependency. In this case, we will use ESM exports
945
+ // instead of the namespace object.
946
+ usedSymbols.has('*') && (this.bundle.env.outputFormat !== 'esmodule' || !this.bundle.env.isLibrary || asset !== this.bundle.getMainEntry() || this.bundleGraph.getIncomingDependencies(asset).some(dep => !dep.isEntry && this.bundle.hasDependency(dep) && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep)).has('*'))) ||
947
+ // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
948
+ // we fallback on the namespace object.
949
+ asset.symbols.hasExportSymbol('*') && [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s)) ||
950
+ // If the exports has this asset's namespace (e.g. ESM output from CJS input),
951
+ // include the namespace object for the default export.
952
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
953
+ // CommonJS library bundle entries always need a namespace.
954
+ this.bundle.env.isLibrary && this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry();
955
+ }
891
956
 
892
957
  // If the asset doesn't have static exports, should wrap, the namespace is used,
893
958
  // or we need default interop, then we need to synthesize a namespace object for
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaspack/packager-js",
3
- "version": "2.14.10",
3
+ "version": "2.15.0",
4
4
  "license": "(MIT OR Apache-2.0)",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -16,12 +16,12 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "@atlaspack/diagnostic": "2.14.1",
19
- "@atlaspack/feature-flags": "2.16.0",
20
- "@atlaspack/plugin": "2.14.10",
19
+ "@atlaspack/feature-flags": "2.18.0",
20
+ "@atlaspack/plugin": "2.14.12",
21
21
  "@atlaspack/rust": "3.3.5",
22
22
  "@parcel/source-map": "^2.1.1",
23
- "@atlaspack/types": "2.15.0",
24
- "@atlaspack/utils": "2.14.10",
23
+ "@atlaspack/types": "2.15.2",
24
+ "@atlaspack/utils": "2.15.0",
25
25
  "globals": "^13.2.0",
26
26
  "nullthrows": "^1.1.1"
27
27
  },
@@ -134,7 +134,8 @@ export class ScopeHoistingPackager {
134
134
  }
135
135
 
136
136
  async package(): Promise<{|contents: string, map: ?SourceMap|}> {
137
- let wrappedAssets = await this.loadAssets();
137
+ let {wrapped: wrappedAssets, constant: constantAssets} =
138
+ await this.loadAssets();
138
139
  this.buildExportedSymbols();
139
140
 
140
141
  // If building a library, the target is actually another bundler rather
@@ -168,6 +169,15 @@ export class ScopeHoistingPackager {
168
169
  lineCount += lines + 1;
169
170
  };
170
171
 
172
+ if (getFeatureFlag('inlineConstOptimisationFix')) {
173
+ // Write out all constant modules used by this bundle
174
+ for (let asset of constantAssets) {
175
+ if (!this.seenAssets.has(asset.id)) {
176
+ processAsset(asset);
177
+ }
178
+ }
179
+ }
180
+
171
181
  // Hoist wrapped asset to the top of the bundle to ensure that they are registered
172
182
  // before they are used.
173
183
  for (let asset of wrappedAssets) {
@@ -354,15 +364,20 @@ export class ScopeHoistingPackager {
354
364
  return `$parcel$global.rwr(${params.join(', ')});`;
355
365
  }
356
366
 
357
- async loadAssets(): Promise<Array<Asset>> {
367
+ async loadAssets(): Promise<{|
368
+ wrapped: Array<Asset>,
369
+ constant: Array<Asset>,
370
+ |}> {
358
371
  let queue = new PromiseQueue({maxConcurrent: 32});
359
372
  let wrapped = [];
373
+ let constant = [];
360
374
  this.bundle.traverseAssets((asset) => {
361
375
  queue.add(async () => {
362
376
  let [code, map] = await Promise.all([
363
377
  asset.getCode(),
364
378
  this.bundle.env.sourceMap ? asset.getMapBuffer() : null,
365
379
  ]);
380
+
366
381
  return [asset.id, {code, map}];
367
382
  });
368
383
 
@@ -383,50 +398,103 @@ export class ScopeHoistingPackager {
383
398
  ) {
384
399
  this.wrappedAssets.add(asset.id);
385
400
  wrapped.push(asset);
401
+ } else if (
402
+ getFeatureFlag('inlineConstOptimisationFix') &&
403
+ asset.meta.isConstantModule
404
+ ) {
405
+ constant.push(asset);
386
406
  }
387
407
  }
388
408
  });
389
409
 
390
- for (let wrappedAssetRoot of [...wrapped]) {
391
- this.bundle.traverseAssets((asset, _, actions) => {
392
- if (asset === wrappedAssetRoot) {
393
- return;
394
- }
410
+ if (getFeatureFlag('applyScopeHoistingImprovement')) {
411
+ // Tracks which assets have been assigned to a wrap group
412
+ let assignedAssets = new Set<Asset>();
395
413
 
396
- if (this.wrappedAssets.has(asset.id)) {
397
- actions.skipChildren();
398
- return;
399
- }
400
- // This prevents children of a wrapped asset also being wrapped - it's an "unsafe" optimisation
401
- // that should only be used when you know (or think you know) what you're doing.
402
- //
403
- // In particular this can force an async bundle to be scope hoisted where it previously would not be
404
- // due to the entry asset being wrapped.
405
- if (
406
- this.forceSkipWrapAssets.length > 0 &&
407
- this.forceSkipWrapAssets.some(
408
- (p) =>
409
- p === path.relative(this.options.projectRoot, asset.filePath),
410
- )
411
- ) {
412
- this.logger.verbose({
413
- message: `Force skipping wrapping of ${path.relative(
414
- this.options.projectRoot,
415
- asset.filePath,
416
- )}`,
417
- });
418
- actions.skipChildren();
419
- return;
420
- }
421
- if (!asset.meta.isConstantModule) {
422
- this.wrappedAssets.add(asset.id);
423
- wrapped.push(asset);
424
- }
425
- }, wrappedAssetRoot);
414
+ for (let wrappedAsset of wrapped) {
415
+ this.bundle.traverseAssets((asset, _, actions) => {
416
+ if (asset === wrappedAsset) {
417
+ return;
418
+ }
419
+
420
+ if (this.wrappedAssets.has(asset.id)) {
421
+ actions.skipChildren();
422
+ return;
423
+ }
424
+
425
+ if (assignedAssets.has(asset) || this.isReExported(asset)) {
426
+ wrapped.push(asset);
427
+ this.wrappedAssets.add(asset.id);
428
+
429
+ actions.skipChildren();
430
+ return;
431
+ }
432
+
433
+ assignedAssets.add(asset);
434
+ }, wrappedAsset);
435
+ }
436
+ } else {
437
+ for (let wrappedAssetRoot of [...wrapped]) {
438
+ this.bundle.traverseAssets((asset, _, actions) => {
439
+ if (asset === wrappedAssetRoot) {
440
+ return;
441
+ }
442
+
443
+ if (this.wrappedAssets.has(asset.id)) {
444
+ actions.skipChildren();
445
+ return;
446
+ }
447
+ // This prevents children of a wrapped asset also being wrapped - it's an "unsafe" optimisation
448
+ // that should only be used when you know (or think you know) what you're doing.
449
+ //
450
+ // In particular this can force an async bundle to be scope hoisted where it previously would not be
451
+ // due to the entry asset being wrapped.
452
+ if (
453
+ this.forceSkipWrapAssets.length > 0 &&
454
+ this.forceSkipWrapAssets.some(
455
+ (p) =>
456
+ p === path.relative(this.options.projectRoot, asset.filePath),
457
+ )
458
+ ) {
459
+ this.logger.verbose({
460
+ message: `Force skipping wrapping of ${path.relative(
461
+ this.options.projectRoot,
462
+ asset.filePath,
463
+ )}`,
464
+ });
465
+ actions.skipChildren();
466
+ return;
467
+ }
468
+ if (!asset.meta.isConstantModule) {
469
+ this.wrappedAssets.add(asset.id);
470
+ wrapped.push(asset);
471
+ }
472
+ }, wrappedAssetRoot);
473
+ }
426
474
  }
427
475
 
428
476
  this.assetOutputs = new Map(await queue.run());
429
- return wrapped;
477
+ return {wrapped, constant};
478
+ }
479
+
480
+ isReExported(asset: Asset): boolean {
481
+ let parentSymbols = this.bundleGraph
482
+ .getIncomingDependencies(asset)
483
+ .map((dep) => this.bundleGraph.getAssetWithDependency(dep))
484
+ .flatMap((parent) => {
485
+ if (parent == null) {
486
+ return [];
487
+ }
488
+ return this.bundleGraph.getExportedSymbols(parent, this.bundle);
489
+ });
490
+
491
+ let assetSymbols = this.bundleGraph.getExportedSymbols(asset, this.bundle);
492
+
493
+ return assetSymbols.some((assetSymbol) =>
494
+ parentSymbols.some(
495
+ (parentSymbol) => parentSymbol.symbol === assetSymbol.symbol,
496
+ ),
497
+ );
430
498
  }
431
499
 
432
500
  buildExportedSymbols() {
@@ -661,13 +729,24 @@ export class ScopeHoistingPackager {
661
729
  // outside our parcelRequire.register wrapper. This is safe because all
662
730
  // assets referenced by this asset will also be wrapped. Otherwise, inline the
663
731
  // asset content where the import statement was.
664
- if (shouldWrap) {
665
- depContent.push(this.visitAsset(resolved));
732
+ if (getFeatureFlag('applyScopeHoistingImprovement')) {
733
+ if (!this.wrappedAssets.has(resolved.id)) {
734
+ let [depCode, depMap, depLines] =
735
+ this.visitAsset(resolved);
736
+ res = depCode + '\n' + res;
737
+ lines += 1 + depLines;
738
+ map = depMap;
739
+ }
666
740
  } else {
667
- let [depCode, depMap, depLines] = this.visitAsset(resolved);
668
- res = depCode + '\n' + res;
669
- lines += 1 + depLines;
670
- map = depMap;
741
+ if (shouldWrap) {
742
+ depContent.push(this.visitAsset(resolved));
743
+ } else {
744
+ let [depCode, depMap, depLines] =
745
+ this.visitAsset(resolved);
746
+ res = depCode + '\n' + res;
747
+ lines += 1 + depLines;
748
+ map = depMap;
749
+ }
671
750
  }
672
751
  }
673
752
 
@@ -1220,34 +1299,49 @@ ${code}
1220
1299
  usedSymbols.has('default') &&
1221
1300
  !asset.symbols.hasExportSymbol('__esModule');
1222
1301
 
1223
- let usedNamespace =
1224
- // If the asset has * in its used symbols, we might need the exports namespace.
1225
- // The one case where this isn't true is in ESM library entries, where the only
1226
- // dependency on * is the entry dependency. In this case, we will use ESM exports
1227
- // instead of the namespace object.
1228
- (usedSymbols.has('*') &&
1229
- (this.bundle.env.outputFormat !== 'esmodule' ||
1230
- !this.bundle.env.isLibrary ||
1231
- asset !== this.bundle.getMainEntry() ||
1232
- this.bundleGraph
1233
- .getIncomingDependencies(asset)
1234
- .some(
1235
- (dep) =>
1236
- !dep.isEntry &&
1237
- this.bundle.hasDependency(dep) &&
1238
- nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1239
- ))) ||
1240
- // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
1241
- // we fallback on the namespace object.
1242
- (asset.symbols.hasExportSymbol('*') &&
1243
- [...usedSymbols].some((s) => !asset.symbols.hasExportSymbol(s))) ||
1244
- // If the exports has this asset's namespace (e.g. ESM output from CJS input),
1245
- // include the namespace object for the default export.
1246
- this.exportedSymbols.has(`$${assetId}$exports`) ||
1247
- // CommonJS library bundle entries always need a namespace.
1248
- (this.bundle.env.isLibrary &&
1249
- this.bundle.env.outputFormat === 'commonjs' &&
1250
- asset === this.bundle.getMainEntry());
1302
+ let usedNamespace;
1303
+ if (
1304
+ getFeatureFlag('inlineConstOptimisationFix') &&
1305
+ asset.meta.isConstantModule
1306
+ ) {
1307
+ // Only set usedNamespace if there is an incoming dependency in the current bundle that uses '*'
1308
+ usedNamespace = this.bundleGraph
1309
+ .getIncomingDependencies(asset)
1310
+ .some(
1311
+ (dep) =>
1312
+ this.bundle.hasDependency(dep) &&
1313
+ nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1314
+ );
1315
+ } else {
1316
+ usedNamespace =
1317
+ // If the asset has * in its used symbols, we might need the exports namespace.
1318
+ // The one case where this isn't true is in ESM library entries, where the only
1319
+ // dependency on * is the entry dependency. In this case, we will use ESM exports
1320
+ // instead of the namespace object.
1321
+ (usedSymbols.has('*') &&
1322
+ (this.bundle.env.outputFormat !== 'esmodule' ||
1323
+ !this.bundle.env.isLibrary ||
1324
+ asset !== this.bundle.getMainEntry() ||
1325
+ this.bundleGraph
1326
+ .getIncomingDependencies(asset)
1327
+ .some(
1328
+ (dep) =>
1329
+ !dep.isEntry &&
1330
+ this.bundle.hasDependency(dep) &&
1331
+ nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1332
+ ))) ||
1333
+ // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
1334
+ // we fallback on the namespace object.
1335
+ (asset.symbols.hasExportSymbol('*') &&
1336
+ [...usedSymbols].some((s) => !asset.symbols.hasExportSymbol(s))) ||
1337
+ // If the exports has this asset's namespace (e.g. ESM output from CJS input),
1338
+ // include the namespace object for the default export.
1339
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
1340
+ // CommonJS library bundle entries always need a namespace.
1341
+ (this.bundle.env.isLibrary &&
1342
+ this.bundle.env.outputFormat === 'commonjs' &&
1343
+ asset === this.bundle.getMainEntry());
1344
+ }
1251
1345
 
1252
1346
  // If the asset doesn't have static exports, should wrap, the namespace is used,
1253
1347
  // or we need default interop, then we need to synthesize a namespace object for