@atlaspack/packager-js 2.14.5-canary.0 → 2.14.5-canary.100

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,139 @@
1
1
  # @atlaspack/packager-js
2
2
 
3
+ ## 2.16.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#654](https://github.com/atlassian-labs/atlaspack/pull/654) [`4d7abde`](https://github.com/atlassian-labs/atlaspack/commit/4d7abde0a6faa148bcf330b08d820f171f853b76) Thanks [@marcins](https://github.com/marcins)! - Fixes constant inlining to work correctly with scope hoisting optimisations
8
+
9
+ - Updated dependencies [[`5ded263`](https://github.com/atlassian-labs/atlaspack/commit/5ded263c7f11b866e8885b81c73e20dd060b25be)]:
10
+ - @atlaspack/feature-flags@2.18.3
11
+ - @atlaspack/utils@2.15.3
12
+ - @atlaspack/types@2.15.5
13
+ - @atlaspack/plugin@2.14.15
14
+
15
+ ## 2.16.1
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies [[`644b157`](https://github.com/atlassian-labs/atlaspack/commit/644b157dee72a871acc2d0facf0b87b8eea51956)]:
20
+ - @atlaspack/feature-flags@2.18.2
21
+ - @atlaspack/utils@2.15.2
22
+ - @atlaspack/types@2.15.4
23
+ - @atlaspack/plugin@2.14.14
24
+
25
+ ## 2.16.0
26
+
27
+ ### Minor Changes
28
+
29
+ - [#644](https://github.com/atlassian-labs/atlaspack/pull/644) [`fc59be7`](https://github.com/atlassian-labs/atlaspack/commit/fc59be71f43dd87d3e6fb7f3f50c424d2b664858) Thanks [@marcins](https://github.com/marcins)! - Removes the unused unstable `forceSkipWrapAssets` feature
30
+
31
+ ### Patch Changes
32
+
33
+ - [#633](https://github.com/atlassian-labs/atlaspack/pull/633) [`26aa9c5`](https://github.com/atlassian-labs/atlaspack/commit/26aa9c599d2be45ce1438a74c5fa22f39b9b554b) Thanks [@sbhuiyan-atlassian](https://github.com/sbhuiyan-atlassian)! - Ported various HMR changes from Parcel
34
+
35
+ - Updated dependencies [[`26aa9c5`](https://github.com/atlassian-labs/atlaspack/commit/26aa9c599d2be45ce1438a74c5fa22f39b9b554b), [`0501255`](https://github.com/atlassian-labs/atlaspack/commit/05012550da35b05ce7d356a8cc29311e7f9afdca)]:
36
+ - @atlaspack/feature-flags@2.18.1
37
+ - @atlaspack/types@2.15.3
38
+ - @atlaspack/utils@2.15.1
39
+ - @atlaspack/plugin@2.14.13
40
+
41
+ ## 2.15.0
42
+
43
+ ### Minor Changes
44
+
45
+ - [#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.
46
+
47
+ Can be enabled with the `applyScopeHoistingImprovement` feature flag.
48
+
49
+ ### Patch Changes
50
+
51
+ - [#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:
52
+
53
+ - 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.
54
+ - 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.
55
+
56
+ - 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)]:
57
+ - @atlaspack/feature-flags@2.18.0
58
+ - @atlaspack/utils@2.15.0
59
+ - @atlaspack/types@2.15.2
60
+ - @atlaspack/plugin@2.14.12
61
+
62
+ ## 2.14.11
63
+
64
+ ### Patch Changes
65
+
66
+ - Updated dependencies [[`73ea3c4`](https://github.com/atlassian-labs/atlaspack/commit/73ea3c4d85d4401fdd15abcbf988237e890e7ad3), [`b1b3693`](https://github.com/atlassian-labs/atlaspack/commit/b1b369317c66f8a431c170df2ebba4fa5b2e38ef)]:
67
+ - @atlaspack/feature-flags@2.17.0
68
+ - @atlaspack/utils@2.14.11
69
+ - @atlaspack/types@2.15.1
70
+ - @atlaspack/plugin@2.14.11
71
+
72
+ ## 2.14.10
73
+
74
+ ### Patch Changes
75
+
76
+ - Updated dependencies [[`51aba5f`](https://github.com/atlassian-labs/atlaspack/commit/51aba5fc0e49235ee06bbc3c376f48c3e7da5c4b), [`1e32d4e`](https://github.com/atlassian-labs/atlaspack/commit/1e32d4eae6b3af3968e8a0ef97d35b4347fd4196), [`35fdd4b`](https://github.com/atlassian-labs/atlaspack/commit/35fdd4b52da0af20f74667f7b8adfb2f90279b7c), [`6dd4ccb`](https://github.com/atlassian-labs/atlaspack/commit/6dd4ccb753541de32322d881f973d571dd57e4ca)]:
77
+ - @atlaspack/types@2.15.0
78
+ - @atlaspack/rust@3.3.5
79
+ - @atlaspack/plugin@2.14.10
80
+ - @atlaspack/utils@2.14.10
81
+
82
+ ## 2.14.9
83
+
84
+ ### Patch Changes
85
+
86
+ - Updated dependencies [[`124b7ff`](https://github.com/atlassian-labs/atlaspack/commit/124b7fff44f71aac9fbad289a9a9509b3dfc9aaa), [`e052521`](https://github.com/atlassian-labs/atlaspack/commit/e0525210850ed1606146eb86991049cf567c5dec), [`15c6d70`](https://github.com/atlassian-labs/atlaspack/commit/15c6d7000bd89da876bc590aa75b17a619a41896), [`e4d966c`](https://github.com/atlassian-labs/atlaspack/commit/e4d966c3c9c4292c5013372ae65b10d19d4bacc6), [`209692f`](https://github.com/atlassian-labs/atlaspack/commit/209692ffb11eae103a0d65c5e1118a5aa1625818), [`42a775d`](https://github.com/atlassian-labs/atlaspack/commit/42a775de8eec638ad188f3271964170d8c04d84b), [`29c2f10`](https://github.com/atlassian-labs/atlaspack/commit/29c2f106de9679adfb5afa04e1910471dc65a427), [`f4da1e1`](https://github.com/atlassian-labs/atlaspack/commit/f4da1e120e73eeb5e8b8927f05e88f04d6148c7b), [`1ef91fc`](https://github.com/atlassian-labs/atlaspack/commit/1ef91fcc863fdd2831511937083dbbc1263b3d9d)]:
87
+ - @atlaspack/rust@3.3.4
88
+ - @atlaspack/feature-flags@2.16.0
89
+ - @atlaspack/utils@2.14.9
90
+ - @atlaspack/types@2.14.9
91
+ - @atlaspack/plugin@2.14.9
92
+
93
+ ## 2.14.8
94
+
95
+ ### Patch Changes
96
+
97
+ - Updated dependencies [[`30f6017`](https://github.com/atlassian-labs/atlaspack/commit/30f60175ba4d272c5fc193973c63bc298584775b), [`1ab0a27`](https://github.com/atlassian-labs/atlaspack/commit/1ab0a275aeca40350415e2b03e7440d1dddc6228), [`b8a4ae8`](https://github.com/atlassian-labs/atlaspack/commit/b8a4ae8f83dc0a83d8b145c5f729936ce52080a3)]:
98
+ - @atlaspack/feature-flags@2.15.1
99
+ - @atlaspack/rust@3.3.3
100
+ - @atlaspack/utils@2.14.8
101
+ - @atlaspack/types@2.14.8
102
+ - @atlaspack/plugin@2.14.8
103
+
104
+ ## 2.14.7
105
+
106
+ ### Patch Changes
107
+
108
+ - Updated dependencies [[`a1773d2`](https://github.com/atlassian-labs/atlaspack/commit/a1773d2a62d0ef7805ac7524621dcabcc1afe929), [`556d6ab`](https://github.com/atlassian-labs/atlaspack/commit/556d6ab8ede759fa7f37fcd3f4da336ef1c55e8f)]:
109
+ - @atlaspack/feature-flags@2.15.0
110
+ - @atlaspack/rust@3.3.2
111
+ - @atlaspack/utils@2.14.7
112
+ - @atlaspack/types@2.14.7
113
+ - @atlaspack/plugin@2.14.7
114
+
115
+ ## 2.14.6
116
+
117
+ ### Patch Changes
118
+
119
+ - Updated dependencies [[`e0f5337`](https://github.com/atlassian-labs/atlaspack/commit/e0f533757bd1019dbd108a04952c87da15286e09)]:
120
+ - @atlaspack/feature-flags@2.14.4
121
+ - @atlaspack/rust@3.3.1
122
+ - @atlaspack/utils@2.14.6
123
+ - @atlaspack/types@2.14.6
124
+ - @atlaspack/plugin@2.14.6
125
+
126
+ ## 2.14.5
127
+
128
+ ### Patch Changes
129
+
130
+ - Updated dependencies [[`11d6f16`](https://github.com/atlassian-labs/atlaspack/commit/11d6f16b6397dee2f217167e5c98b39edb63f7a7), [`e2ba0f6`](https://github.com/atlassian-labs/atlaspack/commit/e2ba0f69702656f3d1ce95ab1454e35062b13b39), [`d2c50c2`](https://github.com/atlassian-labs/atlaspack/commit/d2c50c2c020888b33bb25b8690d9320c2b69e2a6), [`46a90dc`](https://github.com/atlassian-labs/atlaspack/commit/46a90dccd019a26b222c878a92d23acc75dc67c5)]:
131
+ - @atlaspack/feature-flags@2.14.3
132
+ - @atlaspack/rust@3.3.0
133
+ - @atlaspack/utils@2.14.5
134
+ - @atlaspack/types@2.14.5
135
+ - @atlaspack/plugin@2.14.5
136
+
3
137
  ## 2.14.4
4
138
 
5
139
  ### Patch Changes
@@ -18,6 +18,13 @@ function _sourceMap() {
18
18
  };
19
19
  return data;
20
20
  }
21
+ function _featureFlags() {
22
+ const data = require("@atlaspack/feature-flags");
23
+ _featureFlags = function () {
24
+ return data;
25
+ };
26
+ return data;
27
+ }
21
28
  function _assert() {
22
29
  const data = _interopRequireDefault(require("assert"));
23
30
  _assert = function () {
@@ -108,6 +115,17 @@ class DevPackager {
108
115
  deps[specifier] = dep.specifier;
109
116
  }
110
117
  }
118
+ if ((0, _featureFlags().getFeatureFlag)('hmrImprovements')) {
119
+ // Add dependencies for parcelRequire calls added by runtimes
120
+ // so that the HMR runtime can correctly traverse parents.
121
+ let hmrDeps = asset.meta.hmrDeps;
122
+ if (this.options.hmrOptions && Array.isArray(hmrDeps)) {
123
+ for (let id of hmrDeps) {
124
+ (0, _assert().default)(typeof id === 'string');
125
+ deps[id] = id;
126
+ }
127
+ }
128
+ }
111
129
  let {
112
130
  code,
113
131
  mapBuffer
@@ -60,6 +60,13 @@ function _featureFlags() {
60
60
  };
61
61
  return data;
62
62
  }
63
+ function _outdent() {
64
+ const data = require("outdent");
65
+ _outdent = function () {
66
+ return data;
67
+ };
68
+ return data;
69
+ }
63
70
  var _ESMOutputFormat = require("./ESMOutputFormat");
64
71
  var _CJSOutputFormat = require("./CJSOutputFormat");
65
72
  var _GlobalOutputFormat = require("./GlobalOutputFormat");
@@ -99,14 +106,12 @@ class ScopeHoistingPackager {
99
106
  needsPrelude = false;
100
107
  usedHelpers = new Set();
101
108
  externalAssets = new Set();
102
- forceSkipWrapAssets = [];
103
- constructor(options, bundleGraph, bundle, parcelRequireName, useAsyncBundleRuntime, forceSkipWrapAssets, logger) {
109
+ constructor(options, bundleGraph, bundle, parcelRequireName, useAsyncBundleRuntime, logger) {
104
110
  this.options = options;
105
111
  this.bundleGraph = bundleGraph;
106
112
  this.bundle = bundle;
107
113
  this.parcelRequireName = parcelRequireName;
108
114
  this.useAsyncBundleRuntime = useAsyncBundleRuntime;
109
- this.forceSkipWrapAssets = forceSkipWrapAssets ?? [];
110
115
  this.logger = logger;
111
116
  let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
112
117
  this.outputFormat = new OutputFormat(this);
@@ -115,7 +120,10 @@ class ScopeHoistingPackager {
115
120
  }
116
121
  async package() {
117
122
  var _sourceMap;
118
- let wrappedAssets = await this.loadAssets();
123
+ let {
124
+ wrapped: wrappedAssets,
125
+ constant: constantAssets
126
+ } = await this.loadAssets();
119
127
  this.buildExportedSymbols();
120
128
 
121
129
  // If building a library, the target is actually another bundler rather
@@ -143,6 +151,14 @@ class ScopeHoistingPackager {
143
151
  res += content + '\n';
144
152
  lineCount += lines + 1;
145
153
  };
154
+ if ((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix') || (0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovement')) {
155
+ // Write out all constant modules used by this bundle
156
+ for (let asset of constantAssets) {
157
+ if (!this.seenAssets.has(asset.id)) {
158
+ processAsset(asset);
159
+ }
160
+ }
161
+ }
146
162
 
147
163
  // Hoist wrapped asset to the top of the bundle to ensure that they are registered
148
164
  // before they are used.
@@ -265,6 +281,7 @@ class ScopeHoistingPackager {
265
281
  maxConcurrent: 32
266
282
  });
267
283
  let wrapped = [];
284
+ let constant = [];
268
285
  this.bundle.traverseAssets(asset => {
269
286
  queue.add(async () => {
270
287
  let [code, map] = await Promise.all([asset.getCode(), this.bundle.env.sourceMap ? asset.getMapBuffer() : null]);
@@ -278,38 +295,64 @@ class ScopeHoistingPackager {
278
295
  if (!asset.meta.isConstantModule || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.priority === 'lazy')) {
279
296
  this.wrappedAssets.add(asset.id);
280
297
  wrapped.push(asset);
298
+ } else if (((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix') || (0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovement')) && asset.meta.isConstantModule) {
299
+ constant.push(asset);
281
300
  }
282
301
  }
283
302
  });
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);
303
+ if ((0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovement')) {
304
+ // Tracks which assets have been assigned to a wrap group
305
+ let assignedAssets = new Set();
306
+ for (let wrappedAsset of wrapped) {
307
+ this.bundle.traverseAssets((asset, _, actions) => {
308
+ if (asset === wrappedAsset) {
309
+ return;
310
+ }
311
+ if (this.wrappedAssets.has(asset.id)) {
312
+ actions.skipChildren();
313
+ return;
314
+ }
315
+ if (!asset.meta.isConstantModule && (assignedAssets.has(asset) || this.isReExported(asset))) {
316
+ wrapped.push(asset);
317
+ this.wrappedAssets.add(asset.id);
318
+ actions.skipChildren();
319
+ return;
320
+ }
321
+ assignedAssets.add(asset);
322
+ }, wrappedAsset);
323
+ }
324
+ } else {
325
+ for (let wrappedAssetRoot of [...wrapped]) {
326
+ this.bundle.traverseAssets((asset, _, actions) => {
327
+ if (asset === wrappedAssetRoot) {
328
+ return;
329
+ }
330
+ if (this.wrappedAssets.has(asset.id)) {
331
+ actions.skipChildren();
332
+ return;
333
+ }
334
+ if (!asset.meta.isConstantModule) {
335
+ this.wrappedAssets.add(asset.id);
336
+ wrapped.push(asset);
337
+ }
338
+ }, wrappedAssetRoot);
339
+ }
310
340
  }
311
341
  this.assetOutputs = new Map(await queue.run());
312
- return wrapped;
342
+ return {
343
+ wrapped,
344
+ constant
345
+ };
346
+ }
347
+ isReExported(asset) {
348
+ let parentSymbols = this.bundleGraph.getIncomingDependencies(asset).map(dep => this.bundleGraph.getAssetWithDependency(dep)).flatMap(parent => {
349
+ if (parent == null) {
350
+ return [];
351
+ }
352
+ return this.bundleGraph.getExportedSymbols(parent, this.bundle);
353
+ });
354
+ let assetSymbols = this.bundleGraph.getExportedSymbols(asset, this.bundle);
355
+ return assetSymbols.some(assetSymbol => parentSymbols.some(parentSymbol => parentSymbol.symbol === assetSymbol.symbol));
313
356
  }
314
357
  buildExportedSymbols() {
315
358
  if (!this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') {
@@ -395,6 +438,9 @@ class ScopeHoistingPackager {
395
438
  } = (0, _nullthrows().default)(this.assetOutputs.get(asset.id));
396
439
  return this.buildAsset(asset, code, map);
397
440
  }
441
+ getAssetFilePath(asset) {
442
+ return _path().default.relative(this.options.projectRoot, asset.filePath);
443
+ }
398
444
  buildAsset(asset, code, map) {
399
445
  let shouldWrap = this.wrappedAssets.has(asset.id);
400
446
  let deps = this.bundleGraph.getDependencies(asset);
@@ -489,13 +535,33 @@ class ScopeHoistingPackager {
489
535
  // outside our parcelRequire.register wrapper. This is safe because all
490
536
  // assets referenced by this asset will also be wrapped. Otherwise, inline the
491
537
  // asset content where the import statement was.
492
- if (shouldWrap) {
493
- depContent.push(this.visitAsset(resolved));
538
+ if ((0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovement')) {
539
+ if (!resolved.meta.isConstantModule && !this.wrappedAssets.has(resolved.id)) {
540
+ let [depCode, depMap, depLines] = this.visitAsset(resolved);
541
+ if (_utils().debugTools['asset-file-names-in-output']) {
542
+ let resolvedPath = this.getAssetFilePath(resolved);
543
+ res = (0, _outdent().outdent)`
544
+ /* Scope hoisted asset: ${resolvedPath} */
545
+ ${depCode}
546
+ /* End: ${resolvedPath} */
547
+ ${res}
548
+ `;
549
+ lines += 3 + depLines;
550
+ } else {
551
+ res = depCode + '\n' + res;
552
+ lines += 1 + depLines;
553
+ }
554
+ map = depMap;
555
+ }
494
556
  } else {
495
- let [depCode, depMap, depLines] = this.visitAsset(resolved);
496
- res = depCode + '\n' + res;
497
- lines += 1 + depLines;
498
- map = depMap;
557
+ if (shouldWrap) {
558
+ depContent.push(this.visitAsset(resolved));
559
+ } else {
560
+ let [depCode, depMap, depLines] = this.visitAsset(resolved);
561
+ res = depCode + '\n' + res;
562
+ lines += 1 + depLines;
563
+ map = depMap;
564
+ }
499
565
  }
500
566
  }
501
567
 
@@ -542,6 +608,10 @@ ${code}
542
608
  });
543
609
  `;
544
610
  lineCount += 2;
611
+ if (_utils().debugTools['asset-file-names-in-output']) {
612
+ code = `/* ${this.getAssetFilePath(asset)} */\n` + code;
613
+ lineCount += 1;
614
+ }
545
615
  for (let [depCode, map, lines] of depContent) {
546
616
  if (!depCode) continue;
547
617
  code += depCode + '\n';
@@ -874,20 +944,26 @@ ${code}
874
944
  // If there's no __esModule flag, and default is a used symbol, we need
875
945
  // to insert an interop helper.
876
946
  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();
947
+ let usedNamespace;
948
+ if ((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix') && asset.meta.isConstantModule) {
949
+ // Only set usedNamespace if there is an incoming dependency in the current bundle that uses '*'
950
+ usedNamespace = this.bundleGraph.getIncomingDependencies(asset).some(dep => this.bundle.hasDependency(dep) && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep)).has('*'));
951
+ } else {
952
+ usedNamespace =
953
+ // If the asset has * in its used symbols, we might need the exports namespace.
954
+ // The one case where this isn't true is in ESM library entries, where the only
955
+ // dependency on * is the entry dependency. In this case, we will use ESM exports
956
+ // instead of the namespace object.
957
+ 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('*'))) ||
958
+ // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
959
+ // we fallback on the namespace object.
960
+ asset.symbols.hasExportSymbol('*') && [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s)) ||
961
+ // If the exports has this asset's namespace (e.g. ESM output from CJS input),
962
+ // include the namespace object for the default export.
963
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
964
+ // CommonJS library bundle entries always need a namespace.
965
+ this.bundle.env.isLibrary && this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry();
966
+ }
891
967
 
892
968
  // If the asset doesn't have static exports, should wrap, the namespace is used,
893
969
  // or we need default interop, then we need to synthesize a namespace object for
package/lib/index.js CHANGED
@@ -47,12 +47,6 @@ const CONFIG_SCHEMA = {
47
47
  properties: {
48
48
  unstable_asyncBundleRuntime: {
49
49
  type: 'boolean'
50
- },
51
- unstable_forceSkipWrapAssets: {
52
- type: 'array',
53
- items: {
54
- type: 'string'
55
- }
56
50
  }
57
51
  },
58
52
  additionalProperties: false
@@ -62,7 +56,7 @@ var _default = exports.default = new (_plugin().Packager)({
62
56
  config,
63
57
  options
64
58
  }) {
65
- var _conf$contents, _conf$contents2;
59
+ var _conf$contents;
66
60
  let packageKey = '@atlaspack/packager-js';
67
61
  let conf = await config.getConfigFrom(options.projectRoot + '/index', [], {
68
62
  packageKey
@@ -84,8 +78,7 @@ var _default = exports.default = new (_plugin().Packager)({
84
78
  let name = (packageName === null || packageName === void 0 ? void 0 : packageName.contents) ?? '';
85
79
  return {
86
80
  parcelRequireName: 'parcelRequire' + (0, _rust().hashString)(name).slice(-4),
87
- unstable_asyncBundleRuntime: Boolean(conf === null || conf === void 0 || (_conf$contents = conf.contents) === null || _conf$contents === void 0 ? void 0 : _conf$contents.unstable_asyncBundleRuntime),
88
- unstable_forceSkipWrapAssets: (conf === null || conf === void 0 || (_conf$contents2 = conf.contents) === null || _conf$contents2 === void 0 ? void 0 : _conf$contents2.unstable_forceSkipWrapAssets) ?? []
81
+ unstable_asyncBundleRuntime: Boolean(conf === null || conf === void 0 || (_conf$contents = conf.contents) === null || _conf$contents === void 0 ? void 0 : _conf$contents.unstable_asyncBundleRuntime)
89
82
  };
90
83
  },
91
84
  async package({
@@ -108,7 +101,7 @@ var _default = exports.default = new (_plugin().Packager)({
108
101
  }
109
102
  }
110
103
  if (contents == null) {
111
- let packager = bundle.env.shouldScopeHoist ? new _ScopeHoistingPackager.ScopeHoistingPackager(options, bundleGraph, bundle, (0, _nullthrows().default)(config).parcelRequireName, (0, _nullthrows().default)(config).unstable_asyncBundleRuntime, (0, _nullthrows().default)(config).unstable_forceSkipWrapAssets, logger) : new _DevPackager.DevPackager(options, bundleGraph, bundle, (0, _nullthrows().default)(config).parcelRequireName);
104
+ let packager = bundle.env.shouldScopeHoist ? new _ScopeHoistingPackager.ScopeHoistingPackager(options, bundleGraph, bundle, (0, _nullthrows().default)(config).parcelRequireName, (0, _nullthrows().default)(config).unstable_asyncBundleRuntime, logger) : new _DevPackager.DevPackager(options, bundleGraph, bundle, (0, _nullthrows().default)(config).parcelRequireName);
112
105
  ({
113
106
  contents,
114
107
  map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaspack/packager-js",
3
- "version": "2.14.5-canary.0+56fd82cd5",
3
+ "version": "2.14.5-canary.100+f609bf49f",
4
4
  "license": "(MIT OR Apache-2.0)",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -15,16 +15,17 @@
15
15
  "node": ">= 16.0.0"
16
16
  },
17
17
  "dependencies": {
18
- "@atlaspack/diagnostic": "2.14.1-canary.68+56fd82cd5",
19
- "@atlaspack/feature-flags": "2.14.1-canary.68+56fd82cd5",
20
- "@atlaspack/plugin": "2.14.5-canary.0+56fd82cd5",
21
- "@atlaspack/rust": "3.2.1-canary.0+56fd82cd5",
22
- "@atlaspack/types": "2.14.5-canary.0+56fd82cd5",
23
- "@atlaspack/utils": "2.14.5-canary.0+56fd82cd5",
18
+ "@atlaspack/diagnostic": "2.14.1-canary.168+f609bf49f",
19
+ "@atlaspack/feature-flags": "2.14.1-canary.168+f609bf49f",
20
+ "@atlaspack/plugin": "2.14.5-canary.100+f609bf49f",
21
+ "@atlaspack/rust": "3.2.1-canary.100+f609bf49f",
22
+ "@atlaspack/types": "2.14.5-canary.100+f609bf49f",
23
+ "@atlaspack/utils": "2.14.5-canary.100+f609bf49f",
24
24
  "@parcel/source-map": "^2.1.1",
25
25
  "globals": "^13.2.0",
26
- "nullthrows": "^1.1.1"
26
+ "nullthrows": "^1.1.1",
27
+ "outdent": "^0.8.0"
27
28
  },
28
29
  "type": "commonjs",
29
- "gitHead": "56fd82cd544c4c9096be6ebea8261e714435de09"
30
+ "gitHead": "f609bf49ffa3984c0ff81d4853a5c850aaee5fce"
30
31
  }
@@ -8,6 +8,7 @@ import {
8
8
  normalizeSeparators,
9
9
  } from '@atlaspack/utils';
10
10
  import SourceMap from '@parcel/source-map';
11
+ import {getFeatureFlag} from '@atlaspack/feature-flags';
11
12
  import invariant from 'assert';
12
13
  import path from 'path';
13
14
  import fs from 'fs';
@@ -112,6 +113,18 @@ export class DevPackager {
112
113
  }
113
114
  }
114
115
 
116
+ if (getFeatureFlag('hmrImprovements')) {
117
+ // Add dependencies for parcelRequire calls added by runtimes
118
+ // so that the HMR runtime can correctly traverse parents.
119
+ let hmrDeps = asset.meta.hmrDeps;
120
+ if (this.options.hmrOptions && Array.isArray(hmrDeps)) {
121
+ for (let id of hmrDeps) {
122
+ invariant(typeof id === 'string');
123
+ deps[id] = id;
124
+ }
125
+ }
126
+ }
127
+
115
128
  let {code, mapBuffer} = results[i];
116
129
  let output = code || '';
117
130
  wrapped +=
@@ -15,6 +15,7 @@ import {
15
15
  relativeBundlePath,
16
16
  countLines,
17
17
  normalizeSeparators,
18
+ debugTools,
18
19
  } from '@atlaspack/utils';
19
20
  import SourceMap from '@parcel/source-map';
20
21
  import nullthrows from 'nullthrows';
@@ -25,6 +26,7 @@ import ThrowableDiagnostic, {
25
26
  import globals from 'globals';
26
27
  import path from 'path';
27
28
  import {getFeatureFlag} from '@atlaspack/feature-flags';
29
+ import {outdent} from 'outdent';
28
30
 
29
31
  import {ESMOutputFormat} from './ESMOutputFormat';
30
32
  import {CJSOutputFormat} from './CJSOutputFormat';
@@ -102,7 +104,6 @@ export class ScopeHoistingPackager {
102
104
  needsPrelude: boolean = false;
103
105
  usedHelpers: Set<string> = new Set();
104
106
  externalAssets: Set<Asset> = new Set();
105
- forceSkipWrapAssets: Array<string> = [];
106
107
  logger: PluginLogger;
107
108
 
108
109
  constructor(
@@ -111,7 +112,6 @@ export class ScopeHoistingPackager {
111
112
  bundle: NamedBundle,
112
113
  parcelRequireName: string,
113
114
  useAsyncBundleRuntime: boolean,
114
- forceSkipWrapAssets: Array<string>,
115
115
  logger: PluginLogger,
116
116
  ) {
117
117
  this.options = options;
@@ -119,7 +119,6 @@ export class ScopeHoistingPackager {
119
119
  this.bundle = bundle;
120
120
  this.parcelRequireName = parcelRequireName;
121
121
  this.useAsyncBundleRuntime = useAsyncBundleRuntime;
122
- this.forceSkipWrapAssets = forceSkipWrapAssets ?? [];
123
122
  this.logger = logger;
124
123
 
125
124
  let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
@@ -134,7 +133,8 @@ export class ScopeHoistingPackager {
134
133
  }
135
134
 
136
135
  async package(): Promise<{|contents: string, map: ?SourceMap|}> {
137
- let wrappedAssets = await this.loadAssets();
136
+ let {wrapped: wrappedAssets, constant: constantAssets} =
137
+ await this.loadAssets();
138
138
  this.buildExportedSymbols();
139
139
 
140
140
  // If building a library, the target is actually another bundler rather
@@ -168,6 +168,18 @@ export class ScopeHoistingPackager {
168
168
  lineCount += lines + 1;
169
169
  };
170
170
 
171
+ if (
172
+ getFeatureFlag('inlineConstOptimisationFix') ||
173
+ getFeatureFlag('applyScopeHoistingImprovement')
174
+ ) {
175
+ // Write out all constant modules used by this bundle
176
+ for (let asset of constantAssets) {
177
+ if (!this.seenAssets.has(asset.id)) {
178
+ processAsset(asset);
179
+ }
180
+ }
181
+ }
182
+
171
183
  // Hoist wrapped asset to the top of the bundle to ensure that they are registered
172
184
  // before they are used.
173
185
  for (let asset of wrappedAssets) {
@@ -354,15 +366,20 @@ export class ScopeHoistingPackager {
354
366
  return `$parcel$global.rwr(${params.join(', ')});`;
355
367
  }
356
368
 
357
- async loadAssets(): Promise<Array<Asset>> {
369
+ async loadAssets(): Promise<{|
370
+ wrapped: Array<Asset>,
371
+ constant: Array<Asset>,
372
+ |}> {
358
373
  let queue = new PromiseQueue({maxConcurrent: 32});
359
374
  let wrapped = [];
375
+ let constant = [];
360
376
  this.bundle.traverseAssets((asset) => {
361
377
  queue.add(async () => {
362
378
  let [code, map] = await Promise.all([
363
379
  asset.getCode(),
364
380
  this.bundle.env.sourceMap ? asset.getMapBuffer() : null,
365
381
  ]);
382
+
366
383
  return [asset.id, {code, map}];
367
384
  });
368
385
 
@@ -383,50 +400,87 @@ export class ScopeHoistingPackager {
383
400
  ) {
384
401
  this.wrappedAssets.add(asset.id);
385
402
  wrapped.push(asset);
403
+ } else if (
404
+ (getFeatureFlag('inlineConstOptimisationFix') ||
405
+ getFeatureFlag('applyScopeHoistingImprovement')) &&
406
+ asset.meta.isConstantModule
407
+ ) {
408
+ constant.push(asset);
386
409
  }
387
410
  }
388
411
  });
389
412
 
390
- for (let wrappedAssetRoot of [...wrapped]) {
391
- this.bundle.traverseAssets((asset, _, actions) => {
392
- if (asset === wrappedAssetRoot) {
393
- return;
394
- }
413
+ if (getFeatureFlag('applyScopeHoistingImprovement')) {
414
+ // Tracks which assets have been assigned to a wrap group
415
+ let assignedAssets = new Set<Asset>();
395
416
 
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);
417
+ for (let wrappedAsset of wrapped) {
418
+ this.bundle.traverseAssets((asset, _, actions) => {
419
+ if (asset === wrappedAsset) {
420
+ return;
421
+ }
422
+
423
+ if (this.wrappedAssets.has(asset.id)) {
424
+ actions.skipChildren();
425
+ return;
426
+ }
427
+
428
+ if (
429
+ !asset.meta.isConstantModule &&
430
+ (assignedAssets.has(asset) || this.isReExported(asset))
431
+ ) {
432
+ wrapped.push(asset);
433
+ this.wrappedAssets.add(asset.id);
434
+
435
+ actions.skipChildren();
436
+ return;
437
+ }
438
+
439
+ assignedAssets.add(asset);
440
+ }, wrappedAsset);
441
+ }
442
+ } else {
443
+ for (let wrappedAssetRoot of [...wrapped]) {
444
+ this.bundle.traverseAssets((asset, _, actions) => {
445
+ if (asset === wrappedAssetRoot) {
446
+ return;
447
+ }
448
+
449
+ if (this.wrappedAssets.has(asset.id)) {
450
+ actions.skipChildren();
451
+ return;
452
+ }
453
+
454
+ if (!asset.meta.isConstantModule) {
455
+ this.wrappedAssets.add(asset.id);
456
+ wrapped.push(asset);
457
+ }
458
+ }, wrappedAssetRoot);
459
+ }
426
460
  }
427
461
 
428
462
  this.assetOutputs = new Map(await queue.run());
429
- return wrapped;
463
+ return {wrapped, constant};
464
+ }
465
+
466
+ isReExported(asset: Asset): boolean {
467
+ let parentSymbols = this.bundleGraph
468
+ .getIncomingDependencies(asset)
469
+ .map((dep) => this.bundleGraph.getAssetWithDependency(dep))
470
+ .flatMap((parent) => {
471
+ if (parent == null) {
472
+ return [];
473
+ }
474
+ return this.bundleGraph.getExportedSymbols(parent, this.bundle);
475
+ });
476
+
477
+ let assetSymbols = this.bundleGraph.getExportedSymbols(asset, this.bundle);
478
+
479
+ return assetSymbols.some((assetSymbol) =>
480
+ parentSymbols.some(
481
+ (parentSymbol) => parentSymbol.symbol === assetSymbol.symbol,
482
+ ),
483
+ );
430
484
  }
431
485
 
432
486
  buildExportedSymbols() {
@@ -527,6 +581,10 @@ export class ScopeHoistingPackager {
527
581
  return this.buildAsset(asset, code, map);
528
582
  }
529
583
 
584
+ getAssetFilePath(asset: Asset): string {
585
+ return path.relative(this.options.projectRoot, asset.filePath);
586
+ }
587
+
530
588
  buildAsset(
531
589
  asset: Asset,
532
590
  code: string,
@@ -661,13 +719,38 @@ export class ScopeHoistingPackager {
661
719
  // outside our parcelRequire.register wrapper. This is safe because all
662
720
  // assets referenced by this asset will also be wrapped. Otherwise, inline the
663
721
  // asset content where the import statement was.
664
- if (shouldWrap) {
665
- depContent.push(this.visitAsset(resolved));
722
+ if (getFeatureFlag('applyScopeHoistingImprovement')) {
723
+ if (
724
+ !resolved.meta.isConstantModule &&
725
+ !this.wrappedAssets.has(resolved.id)
726
+ ) {
727
+ let [depCode, depMap, depLines] =
728
+ this.visitAsset(resolved);
729
+ if (debugTools['asset-file-names-in-output']) {
730
+ let resolvedPath = this.getAssetFilePath(resolved);
731
+ res = outdent`
732
+ /* Scope hoisted asset: ${resolvedPath} */
733
+ ${depCode}
734
+ /* End: ${resolvedPath} */
735
+ ${res}
736
+ `;
737
+ lines += 3 + depLines;
738
+ } else {
739
+ res = depCode + '\n' + res;
740
+ lines += 1 + depLines;
741
+ }
742
+ map = depMap;
743
+ }
666
744
  } else {
667
- let [depCode, depMap, depLines] = this.visitAsset(resolved);
668
- res = depCode + '\n' + res;
669
- lines += 1 + depLines;
670
- map = depMap;
745
+ if (shouldWrap) {
746
+ depContent.push(this.visitAsset(resolved));
747
+ } else {
748
+ let [depCode, depMap, depLines] =
749
+ this.visitAsset(resolved);
750
+ res = depCode + '\n' + res;
751
+ lines += 1 + depLines;
752
+ map = depMap;
753
+ }
671
754
  }
672
755
  }
673
756
 
@@ -726,6 +809,11 @@ ${code}
726
809
 
727
810
  lineCount += 2;
728
811
 
812
+ if (debugTools['asset-file-names-in-output']) {
813
+ code = `/* ${this.getAssetFilePath(asset)} */\n` + code;
814
+ lineCount += 1;
815
+ }
816
+
729
817
  for (let [depCode, map, lines] of depContent) {
730
818
  if (!depCode) continue;
731
819
  code += depCode + '\n';
@@ -1220,34 +1308,49 @@ ${code}
1220
1308
  usedSymbols.has('default') &&
1221
1309
  !asset.symbols.hasExportSymbol('__esModule');
1222
1310
 
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());
1311
+ let usedNamespace;
1312
+ if (
1313
+ getFeatureFlag('inlineConstOptimisationFix') &&
1314
+ asset.meta.isConstantModule
1315
+ ) {
1316
+ // Only set usedNamespace if there is an incoming dependency in the current bundle that uses '*'
1317
+ usedNamespace = this.bundleGraph
1318
+ .getIncomingDependencies(asset)
1319
+ .some(
1320
+ (dep) =>
1321
+ this.bundle.hasDependency(dep) &&
1322
+ nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1323
+ );
1324
+ } else {
1325
+ usedNamespace =
1326
+ // If the asset has * in its used symbols, we might need the exports namespace.
1327
+ // The one case where this isn't true is in ESM library entries, where the only
1328
+ // dependency on * is the entry dependency. In this case, we will use ESM exports
1329
+ // instead of the namespace object.
1330
+ (usedSymbols.has('*') &&
1331
+ (this.bundle.env.outputFormat !== 'esmodule' ||
1332
+ !this.bundle.env.isLibrary ||
1333
+ asset !== this.bundle.getMainEntry() ||
1334
+ this.bundleGraph
1335
+ .getIncomingDependencies(asset)
1336
+ .some(
1337
+ (dep) =>
1338
+ !dep.isEntry &&
1339
+ this.bundle.hasDependency(dep) &&
1340
+ nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1341
+ ))) ||
1342
+ // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
1343
+ // we fallback on the namespace object.
1344
+ (asset.symbols.hasExportSymbol('*') &&
1345
+ [...usedSymbols].some((s) => !asset.symbols.hasExportSymbol(s))) ||
1346
+ // If the exports has this asset's namespace (e.g. ESM output from CJS input),
1347
+ // include the namespace object for the default export.
1348
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
1349
+ // CommonJS library bundle entries always need a namespace.
1350
+ (this.bundle.env.isLibrary &&
1351
+ this.bundle.env.outputFormat === 'commonjs' &&
1352
+ asset === this.bundle.getMainEntry());
1353
+ }
1251
1354
 
1252
1355
  // If the asset doesn't have static exports, should wrap, the namespace is used,
1253
1356
  // or we need default interop, then we need to synthesize a namespace object for
package/src/index.js CHANGED
@@ -17,7 +17,6 @@ import {ScopeHoistingPackager} from './ScopeHoistingPackager';
17
17
  type JSPackagerConfig = {|
18
18
  parcelRequireName: string,
19
19
  unstable_asyncBundleRuntime: boolean,
20
- unstable_forceSkipWrapAssets: Array<string>,
21
20
  |};
22
21
 
23
22
  const CONFIG_SCHEMA: SchemaEntity = {
@@ -26,12 +25,6 @@ const CONFIG_SCHEMA: SchemaEntity = {
26
25
  unstable_asyncBundleRuntime: {
27
26
  type: 'boolean',
28
27
  },
29
- unstable_forceSkipWrapAssets: {
30
- type: 'array',
31
- items: {
32
- type: 'string',
33
- },
34
- },
35
28
  },
36
29
  additionalProperties: false,
37
30
  };
@@ -73,8 +66,6 @@ export default (new Packager({
73
66
  unstable_asyncBundleRuntime: Boolean(
74
67
  conf?.contents?.unstable_asyncBundleRuntime,
75
68
  ),
76
- unstable_forceSkipWrapAssets:
77
- conf?.contents?.unstable_forceSkipWrapAssets ?? [],
78
69
  };
79
70
  },
80
71
  async package({
@@ -108,7 +99,6 @@ export default (new Packager({
108
99
  bundle,
109
100
  nullthrows(config).parcelRequireName,
110
101
  nullthrows(config).unstable_asyncBundleRuntime,
111
- nullthrows(config).unstable_forceSkipWrapAssets,
112
102
  logger,
113
103
  )
114
104
  : new DevPackager(