@atlaspack/packager-js 2.14.5-dev.14 → 2.14.5-dev.1c70d50f9.99

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,116 @@
1
1
  # @atlaspack/packager-js
2
2
 
3
+ ## 2.16.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`644b157`](https://github.com/atlassian-labs/atlaspack/commit/644b157dee72a871acc2d0facf0b87b8eea51956)]:
8
+ - @atlaspack/feature-flags@2.18.2
9
+ - @atlaspack/utils@2.15.2
10
+ - @atlaspack/types@2.15.4
11
+ - @atlaspack/plugin@2.14.14
12
+
13
+ ## 2.16.0
14
+
15
+ ### Minor Changes
16
+
17
+ - [#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
18
+
19
+ ### Patch Changes
20
+
21
+ - [#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
22
+
23
+ - Updated dependencies [[`26aa9c5`](https://github.com/atlassian-labs/atlaspack/commit/26aa9c599d2be45ce1438a74c5fa22f39b9b554b), [`0501255`](https://github.com/atlassian-labs/atlaspack/commit/05012550da35b05ce7d356a8cc29311e7f9afdca)]:
24
+ - @atlaspack/feature-flags@2.18.1
25
+ - @atlaspack/types@2.15.3
26
+ - @atlaspack/utils@2.15.1
27
+ - @atlaspack/plugin@2.14.13
28
+
29
+ ## 2.15.0
30
+
31
+ ### Minor Changes
32
+
33
+ - [#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.
34
+
35
+ Can be enabled with the `applyScopeHoistingImprovement` feature flag.
36
+
37
+ ### Patch Changes
38
+
39
+ - [#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:
40
+
41
+ - 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.
42
+ - 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.
43
+
44
+ - 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)]:
45
+ - @atlaspack/feature-flags@2.18.0
46
+ - @atlaspack/utils@2.15.0
47
+ - @atlaspack/types@2.15.2
48
+ - @atlaspack/plugin@2.14.12
49
+
50
+ ## 2.14.11
51
+
52
+ ### Patch Changes
53
+
54
+ - Updated dependencies [[`73ea3c4`](https://github.com/atlassian-labs/atlaspack/commit/73ea3c4d85d4401fdd15abcbf988237e890e7ad3), [`b1b3693`](https://github.com/atlassian-labs/atlaspack/commit/b1b369317c66f8a431c170df2ebba4fa5b2e38ef)]:
55
+ - @atlaspack/feature-flags@2.17.0
56
+ - @atlaspack/utils@2.14.11
57
+ - @atlaspack/types@2.15.1
58
+ - @atlaspack/plugin@2.14.11
59
+
60
+ ## 2.14.10
61
+
62
+ ### Patch Changes
63
+
64
+ - 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)]:
65
+ - @atlaspack/types@2.15.0
66
+ - @atlaspack/rust@3.3.5
67
+ - @atlaspack/plugin@2.14.10
68
+ - @atlaspack/utils@2.14.10
69
+
70
+ ## 2.14.9
71
+
72
+ ### Patch Changes
73
+
74
+ - 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)]:
75
+ - @atlaspack/rust@3.3.4
76
+ - @atlaspack/feature-flags@2.16.0
77
+ - @atlaspack/utils@2.14.9
78
+ - @atlaspack/types@2.14.9
79
+ - @atlaspack/plugin@2.14.9
80
+
81
+ ## 2.14.8
82
+
83
+ ### Patch Changes
84
+
85
+ - 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)]:
86
+ - @atlaspack/feature-flags@2.15.1
87
+ - @atlaspack/rust@3.3.3
88
+ - @atlaspack/utils@2.14.8
89
+ - @atlaspack/types@2.14.8
90
+ - @atlaspack/plugin@2.14.8
91
+
92
+ ## 2.14.7
93
+
94
+ ### Patch Changes
95
+
96
+ - Updated dependencies [[`a1773d2`](https://github.com/atlassian-labs/atlaspack/commit/a1773d2a62d0ef7805ac7524621dcabcc1afe929), [`556d6ab`](https://github.com/atlassian-labs/atlaspack/commit/556d6ab8ede759fa7f37fcd3f4da336ef1c55e8f)]:
97
+ - @atlaspack/feature-flags@2.15.0
98
+ - @atlaspack/rust@3.3.2
99
+ - @atlaspack/utils@2.14.7
100
+ - @atlaspack/types@2.14.7
101
+ - @atlaspack/plugin@2.14.7
102
+
103
+ ## 2.14.6
104
+
105
+ ### Patch Changes
106
+
107
+ - Updated dependencies [[`e0f5337`](https://github.com/atlassian-labs/atlaspack/commit/e0f533757bd1019dbd108a04952c87da15286e09)]:
108
+ - @atlaspack/feature-flags@2.14.4
109
+ - @atlaspack/rust@3.3.1
110
+ - @atlaspack/utils@2.14.6
111
+ - @atlaspack/types@2.14.6
112
+ - @atlaspack/plugin@2.14.6
113
+
3
114
  ## 2.14.5
4
115
 
5
116
  ### 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,13 +60,6 @@ function _featureFlags() {
60
60
  };
61
61
  return data;
62
62
  }
63
- function _buildCache() {
64
- const data = require("@atlaspack/build-cache");
65
- _buildCache = function () {
66
- return data;
67
- };
68
- return data;
69
- }
70
63
  var _ESMOutputFormat = require("./ESMOutputFormat");
71
64
  var _CJSOutputFormat = require("./CJSOutputFormat");
72
65
  var _GlobalOutputFormat = require("./GlobalOutputFormat");
@@ -96,7 +89,6 @@ const OUTPUT_FORMATS = {
96
89
  commonjs: _CJSOutputFormat.CJSOutputFormat,
97
90
  global: _GlobalOutputFormat.GlobalOutputFormat
98
91
  };
99
- const bundleDirectReferences = (0, _buildCache().createBuildCache)();
100
92
  class ScopeHoistingPackager {
101
93
  exportedSymbols = new Map();
102
94
  externals = new Map();
@@ -107,14 +99,12 @@ class ScopeHoistingPackager {
107
99
  needsPrelude = false;
108
100
  usedHelpers = new Set();
109
101
  externalAssets = new Set();
110
- forceSkipWrapAssets = [];
111
- constructor(options, bundleGraph, bundle, parcelRequireName, useAsyncBundleRuntime, forceSkipWrapAssets, logger) {
102
+ constructor(options, bundleGraph, bundle, parcelRequireName, useAsyncBundleRuntime, logger) {
112
103
  this.options = options;
113
104
  this.bundleGraph = bundleGraph;
114
105
  this.bundle = bundle;
115
106
  this.parcelRequireName = parcelRequireName;
116
107
  this.useAsyncBundleRuntime = useAsyncBundleRuntime;
117
- this.forceSkipWrapAssets = forceSkipWrapAssets ?? [];
118
108
  this.logger = logger;
119
109
  let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
120
110
  this.outputFormat = new OutputFormat(this);
@@ -123,7 +113,10 @@ class ScopeHoistingPackager {
123
113
  }
124
114
  async package() {
125
115
  var _sourceMap;
126
- let wrappedAssets = await this.loadAssets();
116
+ let {
117
+ wrapped: wrappedAssets,
118
+ constant: constantAssets
119
+ } = await this.loadAssets();
127
120
  this.buildExportedSymbols();
128
121
 
129
122
  // If building a library, the target is actually another bundler rather
@@ -151,6 +144,14 @@ class ScopeHoistingPackager {
151
144
  res += content + '\n';
152
145
  lineCount += lines + 1;
153
146
  };
147
+ if ((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix') || (0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovement')) {
148
+ // Write out all constant modules used by this bundle
149
+ for (let asset of constantAssets) {
150
+ if (!this.seenAssets.has(asset.id)) {
151
+ processAsset(asset);
152
+ }
153
+ }
154
+ }
154
155
 
155
156
  // Hoist wrapped asset to the top of the bundle to ensure that they are registered
156
157
  // before they are used.
@@ -273,7 +274,7 @@ class ScopeHoistingPackager {
273
274
  maxConcurrent: 32
274
275
  });
275
276
  let wrapped = [];
276
- const referencedAssets = this.bundleGraph.getReferencedAssets(this.bundle, bundleDirectReferences);
277
+ let constant = [];
277
278
  this.bundle.traverseAssets(asset => {
278
279
  queue.add(async () => {
279
280
  let [code, map] = await Promise.all([asset.getCode(), this.bundle.env.sourceMap ? asset.getMapBuffer() : null]);
@@ -282,43 +283,69 @@ class ScopeHoistingPackager {
282
283
  map
283
284
  }];
284
285
  });
285
- if (asset.meta.shouldWrap || this.bundle.env.sourceType === 'script' || referencedAssets.has(asset.id) || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.meta.shouldWrap && dep.specifierType !== 'url')) {
286
+ if (asset.meta.shouldWrap || this.bundle.env.sourceType === 'script' || this.bundleGraph.isAssetReferenced(this.bundle, asset) || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.meta.shouldWrap && dep.specifierType !== 'url')) {
286
287
  // Don't wrap constant "entry" modules _except_ if they are referenced by any lazy dependency
287
288
  if (!asset.meta.isConstantModule || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.priority === 'lazy')) {
288
289
  this.wrappedAssets.add(asset.id);
289
290
  wrapped.push(asset);
291
+ } else if (((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix') || (0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovement')) && asset.meta.isConstantModule) {
292
+ constant.push(asset);
290
293
  }
291
294
  }
292
295
  });
293
- for (let wrappedAssetRoot of [...wrapped]) {
294
- this.bundle.traverseAssets((asset, _, actions) => {
295
- if (asset === wrappedAssetRoot) {
296
- return;
297
- }
298
- if (this.wrappedAssets.has(asset.id)) {
299
- actions.skipChildren();
300
- return;
301
- }
302
- // This prevents children of a wrapped asset also being wrapped - it's an "unsafe" optimisation
303
- // that should only be used when you know (or think you know) what you're doing.
304
- //
305
- // In particular this can force an async bundle to be scope hoisted where it previously would not be
306
- // due to the entry asset being wrapped.
307
- if (this.forceSkipWrapAssets.length > 0 && this.forceSkipWrapAssets.some(p => p === _path().default.relative(this.options.projectRoot, asset.filePath))) {
308
- this.logger.verbose({
309
- message: `Force skipping wrapping of ${_path().default.relative(this.options.projectRoot, asset.filePath)}`
310
- });
311
- actions.skipChildren();
312
- return;
313
- }
314
- if (!asset.meta.isConstantModule) {
315
- this.wrappedAssets.add(asset.id);
316
- wrapped.push(asset);
317
- }
318
- }, wrappedAssetRoot);
296
+ if ((0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovement')) {
297
+ // Tracks which assets have been assigned to a wrap group
298
+ let assignedAssets = new Set();
299
+ for (let wrappedAsset of wrapped) {
300
+ this.bundle.traverseAssets((asset, _, actions) => {
301
+ if (asset === wrappedAsset) {
302
+ return;
303
+ }
304
+ if (this.wrappedAssets.has(asset.id)) {
305
+ actions.skipChildren();
306
+ return;
307
+ }
308
+ if (!asset.meta.isConstantModule && (assignedAssets.has(asset) || this.isReExported(asset))) {
309
+ wrapped.push(asset);
310
+ this.wrappedAssets.add(asset.id);
311
+ actions.skipChildren();
312
+ return;
313
+ }
314
+ assignedAssets.add(asset);
315
+ }, wrappedAsset);
316
+ }
317
+ } else {
318
+ for (let wrappedAssetRoot of [...wrapped]) {
319
+ this.bundle.traverseAssets((asset, _, actions) => {
320
+ if (asset === wrappedAssetRoot) {
321
+ return;
322
+ }
323
+ if (this.wrappedAssets.has(asset.id)) {
324
+ actions.skipChildren();
325
+ return;
326
+ }
327
+ if (!asset.meta.isConstantModule) {
328
+ this.wrappedAssets.add(asset.id);
329
+ wrapped.push(asset);
330
+ }
331
+ }, wrappedAssetRoot);
332
+ }
319
333
  }
320
334
  this.assetOutputs = new Map(await queue.run());
321
- return wrapped;
335
+ return {
336
+ wrapped,
337
+ constant
338
+ };
339
+ }
340
+ isReExported(asset) {
341
+ let parentSymbols = this.bundleGraph.getIncomingDependencies(asset).map(dep => this.bundleGraph.getAssetWithDependency(dep)).flatMap(parent => {
342
+ if (parent == null) {
343
+ return [];
344
+ }
345
+ return this.bundleGraph.getExportedSymbols(parent, this.bundle);
346
+ });
347
+ let assetSymbols = this.bundleGraph.getExportedSymbols(asset, this.bundle);
348
+ return assetSymbols.some(assetSymbol => parentSymbols.some(parentSymbol => parentSymbol.symbol === assetSymbol.symbol));
322
349
  }
323
350
  buildExportedSymbols() {
324
351
  if (!this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') {
@@ -498,13 +525,22 @@ class ScopeHoistingPackager {
498
525
  // outside our parcelRequire.register wrapper. This is safe because all
499
526
  // assets referenced by this asset will also be wrapped. Otherwise, inline the
500
527
  // asset content where the import statement was.
501
- if (shouldWrap) {
502
- depContent.push(this.visitAsset(resolved));
528
+ if ((0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovement')) {
529
+ if (!resolved.meta.isConstantModule && !this.wrappedAssets.has(resolved.id)) {
530
+ let [depCode, depMap, depLines] = this.visitAsset(resolved);
531
+ res = depCode + '\n' + res;
532
+ lines += 1 + depLines;
533
+ map = depMap;
534
+ }
503
535
  } else {
504
- let [depCode, depMap, depLines] = this.visitAsset(resolved);
505
- res = depCode + '\n' + res;
506
- lines += 1 + depLines;
507
- map = depMap;
536
+ if (shouldWrap) {
537
+ depContent.push(this.visitAsset(resolved));
538
+ } else {
539
+ let [depCode, depMap, depLines] = this.visitAsset(resolved);
540
+ res = depCode + '\n' + res;
541
+ lines += 1 + depLines;
542
+ map = depMap;
543
+ }
508
544
  }
509
545
  }
510
546
 
@@ -883,20 +919,26 @@ ${code}
883
919
  // If there's no __esModule flag, and default is a used symbol, we need
884
920
  // to insert an interop helper.
885
921
  let defaultInterop = asset.symbols.hasExportSymbol('*') && usedSymbols.has('default') && !asset.symbols.hasExportSymbol('__esModule');
886
- let usedNamespace =
887
- // If the asset has * in its used symbols, we might need the exports namespace.
888
- // The one case where this isn't true is in ESM library entries, where the only
889
- // dependency on * is the entry dependency. In this case, we will use ESM exports
890
- // instead of the namespace object.
891
- 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('*'))) ||
892
- // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
893
- // we fallback on the namespace object.
894
- asset.symbols.hasExportSymbol('*') && [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s)) ||
895
- // If the exports has this asset's namespace (e.g. ESM output from CJS input),
896
- // include the namespace object for the default export.
897
- this.exportedSymbols.has(`$${assetId}$exports`) ||
898
- // CommonJS library bundle entries always need a namespace.
899
- this.bundle.env.isLibrary && this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry();
922
+ let usedNamespace;
923
+ if ((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix') && asset.meta.isConstantModule) {
924
+ // Only set usedNamespace if there is an incoming dependency in the current bundle that uses '*'
925
+ usedNamespace = this.bundleGraph.getIncomingDependencies(asset).some(dep => this.bundle.hasDependency(dep) && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep)).has('*'));
926
+ } else {
927
+ usedNamespace =
928
+ // If the asset has * in its used symbols, we might need the exports namespace.
929
+ // The one case where this isn't true is in ESM library entries, where the only
930
+ // dependency on * is the entry dependency. In this case, we will use ESM exports
931
+ // instead of the namespace object.
932
+ 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('*'))) ||
933
+ // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
934
+ // we fallback on the namespace object.
935
+ asset.symbols.hasExportSymbol('*') && [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s)) ||
936
+ // If the exports has this asset's namespace (e.g. ESM output from CJS input),
937
+ // include the namespace object for the default export.
938
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
939
+ // CommonJS library bundle entries always need a namespace.
940
+ this.bundle.env.isLibrary && this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry();
941
+ }
900
942
 
901
943
  // If the asset doesn't have static exports, should wrap, the namespace is used,
902
944
  // 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-dev.14+8c369e38c",
3
+ "version": "2.14.5-dev.1c70d50f9.99+1c70d50f9",
4
4
  "license": "(MIT OR Apache-2.0)",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -15,16 +15,16 @@
15
15
  "node": ">= 16.0.0"
16
16
  },
17
17
  "dependencies": {
18
- "@atlaspack/diagnostic": "2.14.1-dev.82+8c369e38c",
19
- "@atlaspack/feature-flags": "2.14.1-dev.82+8c369e38c",
20
- "@atlaspack/plugin": "2.14.5-dev.14+8c369e38c",
21
- "@atlaspack/rust": "3.2.1-dev.14+8c369e38c",
22
- "@atlaspack/types": "2.14.5-dev.14+8c369e38c",
23
- "@atlaspack/utils": "2.14.5-dev.14+8c369e38c",
18
+ "@atlaspack/diagnostic": "2.14.1-dev.1c70d50f9.167+1c70d50f9",
19
+ "@atlaspack/feature-flags": "2.14.1-dev.1c70d50f9.167+1c70d50f9",
20
+ "@atlaspack/plugin": "2.14.5-dev.1c70d50f9.99+1c70d50f9",
21
+ "@atlaspack/rust": "3.2.1-dev.1c70d50f9.99+1c70d50f9",
22
+ "@atlaspack/types": "2.14.5-dev.1c70d50f9.99+1c70d50f9",
23
+ "@atlaspack/utils": "2.14.5-dev.1c70d50f9.99+1c70d50f9",
24
24
  "@parcel/source-map": "^2.1.1",
25
25
  "globals": "^13.2.0",
26
26
  "nullthrows": "^1.1.1"
27
27
  },
28
28
  "type": "commonjs",
29
- "gitHead": "8c369e38ccd428409811114aebd6044c27f90705"
29
+ "gitHead": "1c70d50f914cb662515b0b61053e51a06f3af234"
30
30
  }
@@ -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 +=
@@ -25,7 +25,6 @@ import ThrowableDiagnostic, {
25
25
  import globals from 'globals';
26
26
  import path from 'path';
27
27
  import {getFeatureFlag} from '@atlaspack/feature-flags';
28
- import {createBuildCache} from '@atlaspack/build-cache';
29
28
 
30
29
  import {ESMOutputFormat} from './ESMOutputFormat';
31
30
  import {CJSOutputFormat} from './CJSOutputFormat';
@@ -76,8 +75,6 @@ export interface OutputFormat {
76
75
  buildBundlePostlude(): [string, number];
77
76
  }
78
77
 
79
- const bundleDirectReferences = createBuildCache();
80
-
81
78
  export class ScopeHoistingPackager {
82
79
  options: PluginOptions;
83
80
  bundleGraph: BundleGraph<NamedBundle>;
@@ -105,7 +102,6 @@ export class ScopeHoistingPackager {
105
102
  needsPrelude: boolean = false;
106
103
  usedHelpers: Set<string> = new Set();
107
104
  externalAssets: Set<Asset> = new Set();
108
- forceSkipWrapAssets: Array<string> = [];
109
105
  logger: PluginLogger;
110
106
 
111
107
  constructor(
@@ -114,7 +110,6 @@ export class ScopeHoistingPackager {
114
110
  bundle: NamedBundle,
115
111
  parcelRequireName: string,
116
112
  useAsyncBundleRuntime: boolean,
117
- forceSkipWrapAssets: Array<string>,
118
113
  logger: PluginLogger,
119
114
  ) {
120
115
  this.options = options;
@@ -122,7 +117,6 @@ export class ScopeHoistingPackager {
122
117
  this.bundle = bundle;
123
118
  this.parcelRequireName = parcelRequireName;
124
119
  this.useAsyncBundleRuntime = useAsyncBundleRuntime;
125
- this.forceSkipWrapAssets = forceSkipWrapAssets ?? [];
126
120
  this.logger = logger;
127
121
 
128
122
  let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
@@ -137,7 +131,8 @@ export class ScopeHoistingPackager {
137
131
  }
138
132
 
139
133
  async package(): Promise<{|contents: string, map: ?SourceMap|}> {
140
- let wrappedAssets = await this.loadAssets();
134
+ let {wrapped: wrappedAssets, constant: constantAssets} =
135
+ await this.loadAssets();
141
136
  this.buildExportedSymbols();
142
137
 
143
138
  // If building a library, the target is actually another bundler rather
@@ -171,6 +166,18 @@ export class ScopeHoistingPackager {
171
166
  lineCount += lines + 1;
172
167
  };
173
168
 
169
+ if (
170
+ getFeatureFlag('inlineConstOptimisationFix') ||
171
+ getFeatureFlag('applyScopeHoistingImprovement')
172
+ ) {
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
+
174
181
  // Hoist wrapped asset to the top of the bundle to ensure that they are registered
175
182
  // before they are used.
176
183
  for (let asset of wrappedAssets) {
@@ -357,28 +364,27 @@ export class ScopeHoistingPackager {
357
364
  return `$parcel$global.rwr(${params.join(', ')});`;
358
365
  }
359
366
 
360
- async loadAssets(): Promise<Array<Asset>> {
367
+ async loadAssets(): Promise<{|
368
+ wrapped: Array<Asset>,
369
+ constant: Array<Asset>,
370
+ |}> {
361
371
  let queue = new PromiseQueue({maxConcurrent: 32});
362
372
  let wrapped = [];
363
-
364
- const referencedAssets = this.bundleGraph.getReferencedAssets(
365
- this.bundle,
366
- bundleDirectReferences,
367
- );
368
-
373
+ let constant = [];
369
374
  this.bundle.traverseAssets((asset) => {
370
375
  queue.add(async () => {
371
376
  let [code, map] = await Promise.all([
372
377
  asset.getCode(),
373
378
  this.bundle.env.sourceMap ? asset.getMapBuffer() : null,
374
379
  ]);
380
+
375
381
  return [asset.id, {code, map}];
376
382
  });
377
383
 
378
384
  if (
379
385
  asset.meta.shouldWrap ||
380
386
  this.bundle.env.sourceType === 'script' ||
381
- referencedAssets.has(asset.id) ||
387
+ this.bundleGraph.isAssetReferenced(this.bundle, asset) ||
382
388
  this.bundleGraph
383
389
  .getIncomingDependencies(asset)
384
390
  .some((dep) => dep.meta.shouldWrap && dep.specifierType !== 'url')
@@ -392,50 +398,87 @@ export class ScopeHoistingPackager {
392
398
  ) {
393
399
  this.wrappedAssets.add(asset.id);
394
400
  wrapped.push(asset);
401
+ } else if (
402
+ (getFeatureFlag('inlineConstOptimisationFix') ||
403
+ getFeatureFlag('applyScopeHoistingImprovement')) &&
404
+ asset.meta.isConstantModule
405
+ ) {
406
+ constant.push(asset);
395
407
  }
396
408
  }
397
409
  });
398
410
 
399
- for (let wrappedAssetRoot of [...wrapped]) {
400
- this.bundle.traverseAssets((asset, _, actions) => {
401
- if (asset === wrappedAssetRoot) {
402
- return;
403
- }
411
+ if (getFeatureFlag('applyScopeHoistingImprovement')) {
412
+ // Tracks which assets have been assigned to a wrap group
413
+ let assignedAssets = new Set<Asset>();
404
414
 
405
- if (this.wrappedAssets.has(asset.id)) {
406
- actions.skipChildren();
407
- return;
408
- }
409
- // This prevents children of a wrapped asset also being wrapped - it's an "unsafe" optimisation
410
- // that should only be used when you know (or think you know) what you're doing.
411
- //
412
- // In particular this can force an async bundle to be scope hoisted where it previously would not be
413
- // due to the entry asset being wrapped.
414
- if (
415
- this.forceSkipWrapAssets.length > 0 &&
416
- this.forceSkipWrapAssets.some(
417
- (p) =>
418
- p === path.relative(this.options.projectRoot, asset.filePath),
419
- )
420
- ) {
421
- this.logger.verbose({
422
- message: `Force skipping wrapping of ${path.relative(
423
- this.options.projectRoot,
424
- asset.filePath,
425
- )}`,
426
- });
427
- actions.skipChildren();
428
- return;
429
- }
430
- if (!asset.meta.isConstantModule) {
431
- this.wrappedAssets.add(asset.id);
432
- wrapped.push(asset);
433
- }
434
- }, wrappedAssetRoot);
415
+ for (let wrappedAsset of wrapped) {
416
+ this.bundle.traverseAssets((asset, _, actions) => {
417
+ if (asset === wrappedAsset) {
418
+ return;
419
+ }
420
+
421
+ if (this.wrappedAssets.has(asset.id)) {
422
+ actions.skipChildren();
423
+ return;
424
+ }
425
+
426
+ if (
427
+ !asset.meta.isConstantModule &&
428
+ (assignedAssets.has(asset) || this.isReExported(asset))
429
+ ) {
430
+ wrapped.push(asset);
431
+ this.wrappedAssets.add(asset.id);
432
+
433
+ actions.skipChildren();
434
+ return;
435
+ }
436
+
437
+ assignedAssets.add(asset);
438
+ }, wrappedAsset);
439
+ }
440
+ } else {
441
+ for (let wrappedAssetRoot of [...wrapped]) {
442
+ this.bundle.traverseAssets((asset, _, actions) => {
443
+ if (asset === wrappedAssetRoot) {
444
+ return;
445
+ }
446
+
447
+ if (this.wrappedAssets.has(asset.id)) {
448
+ actions.skipChildren();
449
+ return;
450
+ }
451
+
452
+ if (!asset.meta.isConstantModule) {
453
+ this.wrappedAssets.add(asset.id);
454
+ wrapped.push(asset);
455
+ }
456
+ }, wrappedAssetRoot);
457
+ }
435
458
  }
436
459
 
437
460
  this.assetOutputs = new Map(await queue.run());
438
- return wrapped;
461
+ return {wrapped, constant};
462
+ }
463
+
464
+ isReExported(asset: Asset): boolean {
465
+ let parentSymbols = this.bundleGraph
466
+ .getIncomingDependencies(asset)
467
+ .map((dep) => this.bundleGraph.getAssetWithDependency(dep))
468
+ .flatMap((parent) => {
469
+ if (parent == null) {
470
+ return [];
471
+ }
472
+ return this.bundleGraph.getExportedSymbols(parent, this.bundle);
473
+ });
474
+
475
+ let assetSymbols = this.bundleGraph.getExportedSymbols(asset, this.bundle);
476
+
477
+ return assetSymbols.some((assetSymbol) =>
478
+ parentSymbols.some(
479
+ (parentSymbol) => parentSymbol.symbol === assetSymbol.symbol,
480
+ ),
481
+ );
439
482
  }
440
483
 
441
484
  buildExportedSymbols() {
@@ -670,13 +713,27 @@ export class ScopeHoistingPackager {
670
713
  // outside our parcelRequire.register wrapper. This is safe because all
671
714
  // assets referenced by this asset will also be wrapped. Otherwise, inline the
672
715
  // asset content where the import statement was.
673
- if (shouldWrap) {
674
- depContent.push(this.visitAsset(resolved));
716
+ if (getFeatureFlag('applyScopeHoistingImprovement')) {
717
+ if (
718
+ !resolved.meta.isConstantModule &&
719
+ !this.wrappedAssets.has(resolved.id)
720
+ ) {
721
+ let [depCode, depMap, depLines] =
722
+ this.visitAsset(resolved);
723
+ res = depCode + '\n' + res;
724
+ lines += 1 + depLines;
725
+ map = depMap;
726
+ }
675
727
  } else {
676
- let [depCode, depMap, depLines] = this.visitAsset(resolved);
677
- res = depCode + '\n' + res;
678
- lines += 1 + depLines;
679
- map = depMap;
728
+ if (shouldWrap) {
729
+ depContent.push(this.visitAsset(resolved));
730
+ } else {
731
+ let [depCode, depMap, depLines] =
732
+ this.visitAsset(resolved);
733
+ res = depCode + '\n' + res;
734
+ lines += 1 + depLines;
735
+ map = depMap;
736
+ }
680
737
  }
681
738
  }
682
739
 
@@ -1229,34 +1286,49 @@ ${code}
1229
1286
  usedSymbols.has('default') &&
1230
1287
  !asset.symbols.hasExportSymbol('__esModule');
1231
1288
 
1232
- let usedNamespace =
1233
- // If the asset has * in its used symbols, we might need the exports namespace.
1234
- // The one case where this isn't true is in ESM library entries, where the only
1235
- // dependency on * is the entry dependency. In this case, we will use ESM exports
1236
- // instead of the namespace object.
1237
- (usedSymbols.has('*') &&
1238
- (this.bundle.env.outputFormat !== 'esmodule' ||
1239
- !this.bundle.env.isLibrary ||
1240
- asset !== this.bundle.getMainEntry() ||
1241
- this.bundleGraph
1242
- .getIncomingDependencies(asset)
1243
- .some(
1244
- (dep) =>
1245
- !dep.isEntry &&
1246
- this.bundle.hasDependency(dep) &&
1247
- nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1248
- ))) ||
1249
- // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
1250
- // we fallback on the namespace object.
1251
- (asset.symbols.hasExportSymbol('*') &&
1252
- [...usedSymbols].some((s) => !asset.symbols.hasExportSymbol(s))) ||
1253
- // If the exports has this asset's namespace (e.g. ESM output from CJS input),
1254
- // include the namespace object for the default export.
1255
- this.exportedSymbols.has(`$${assetId}$exports`) ||
1256
- // CommonJS library bundle entries always need a namespace.
1257
- (this.bundle.env.isLibrary &&
1258
- this.bundle.env.outputFormat === 'commonjs' &&
1259
- asset === this.bundle.getMainEntry());
1289
+ let usedNamespace;
1290
+ if (
1291
+ getFeatureFlag('inlineConstOptimisationFix') &&
1292
+ asset.meta.isConstantModule
1293
+ ) {
1294
+ // Only set usedNamespace if there is an incoming dependency in the current bundle that uses '*'
1295
+ usedNamespace = this.bundleGraph
1296
+ .getIncomingDependencies(asset)
1297
+ .some(
1298
+ (dep) =>
1299
+ this.bundle.hasDependency(dep) &&
1300
+ nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1301
+ );
1302
+ } else {
1303
+ usedNamespace =
1304
+ // If the asset has * in its used symbols, we might need the exports namespace.
1305
+ // The one case where this isn't true is in ESM library entries, where the only
1306
+ // dependency on * is the entry dependency. In this case, we will use ESM exports
1307
+ // instead of the namespace object.
1308
+ (usedSymbols.has('*') &&
1309
+ (this.bundle.env.outputFormat !== 'esmodule' ||
1310
+ !this.bundle.env.isLibrary ||
1311
+ asset !== this.bundle.getMainEntry() ||
1312
+ this.bundleGraph
1313
+ .getIncomingDependencies(asset)
1314
+ .some(
1315
+ (dep) =>
1316
+ !dep.isEntry &&
1317
+ this.bundle.hasDependency(dep) &&
1318
+ nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1319
+ ))) ||
1320
+ // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
1321
+ // we fallback on the namespace object.
1322
+ (asset.symbols.hasExportSymbol('*') &&
1323
+ [...usedSymbols].some((s) => !asset.symbols.hasExportSymbol(s))) ||
1324
+ // If the exports has this asset's namespace (e.g. ESM output from CJS input),
1325
+ // include the namespace object for the default export.
1326
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
1327
+ // CommonJS library bundle entries always need a namespace.
1328
+ (this.bundle.env.isLibrary &&
1329
+ this.bundle.env.outputFormat === 'commonjs' &&
1330
+ asset === this.bundle.getMainEntry());
1331
+ }
1260
1332
 
1261
1333
  // If the asset doesn't have static exports, should wrap, the namespace is used,
1262
1334
  // 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(