@atlaspack/packager-js 2.14.5-dev.72 → 2.14.5-dev.93

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,52 @@
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
+
3
50
  ## 2.14.11
4
51
 
5
52
  ### 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
@@ -99,14 +99,12 @@ class ScopeHoistingPackager {
99
99
  needsPrelude = false;
100
100
  usedHelpers = new Set();
101
101
  externalAssets = new Set();
102
- forceSkipWrapAssets = [];
103
- constructor(options, bundleGraph, bundle, parcelRequireName, useAsyncBundleRuntime, forceSkipWrapAssets, logger) {
102
+ constructor(options, bundleGraph, bundle, parcelRequireName, useAsyncBundleRuntime, logger) {
104
103
  this.options = options;
105
104
  this.bundleGraph = bundleGraph;
106
105
  this.bundle = bundle;
107
106
  this.parcelRequireName = parcelRequireName;
108
107
  this.useAsyncBundleRuntime = useAsyncBundleRuntime;
109
- this.forceSkipWrapAssets = forceSkipWrapAssets ?? [];
110
108
  this.logger = logger;
111
109
  let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
112
110
  this.outputFormat = new OutputFormat(this);
@@ -115,7 +113,10 @@ class ScopeHoistingPackager {
115
113
  }
116
114
  async package() {
117
115
  var _sourceMap;
118
- let wrappedAssets = await this.loadAssets();
116
+ let {
117
+ wrapped: wrappedAssets,
118
+ constant: constantAssets
119
+ } = await this.loadAssets();
119
120
  this.buildExportedSymbols();
120
121
 
121
122
  // If building a library, the target is actually another bundler rather
@@ -127,12 +128,6 @@ class ScopeHoistingPackager {
127
128
  for (let b of this.bundleGraph.getReferencedBundles(this.bundle, {
128
129
  recursive: false
129
130
  })) {
130
- // If the referenced bundle is a native node bundle then don't require it as
131
- // an external as we don't want to require native node bundles from other
132
- // OS architectures
133
- if (process.env.ATLASPACK_SUPER_BUILD === 'true' && b.type === 'node') {
134
- continue;
135
- }
136
131
  this.externals.set((0, _utils().relativeBundlePath)(this.bundle, b), new Map());
137
132
  }
138
133
  }
@@ -149,6 +144,14 @@ class ScopeHoistingPackager {
149
144
  res += content + '\n';
150
145
  lineCount += lines + 1;
151
146
  };
147
+ if ((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix')) {
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
+ }
152
155
 
153
156
  // Hoist wrapped asset to the top of the bundle to ensure that they are registered
154
157
  // before they are used.
@@ -271,6 +274,7 @@ class ScopeHoistingPackager {
271
274
  maxConcurrent: 32
272
275
  });
273
276
  let wrapped = [];
277
+ let constant = [];
274
278
  this.bundle.traverseAssets(asset => {
275
279
  queue.add(async () => {
276
280
  let [code, map] = await Promise.all([asset.getCode(), this.bundle.env.sourceMap ? asset.getMapBuffer() : null]);
@@ -284,38 +288,64 @@ class ScopeHoistingPackager {
284
288
  if (!asset.meta.isConstantModule || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.priority === 'lazy')) {
285
289
  this.wrappedAssets.add(asset.id);
286
290
  wrapped.push(asset);
291
+ } else if ((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix') && asset.meta.isConstantModule) {
292
+ constant.push(asset);
287
293
  }
288
294
  }
289
295
  });
290
- for (let wrappedAssetRoot of [...wrapped]) {
291
- this.bundle.traverseAssets((asset, _, actions) => {
292
- if (asset === wrappedAssetRoot) {
293
- return;
294
- }
295
- if (this.wrappedAssets.has(asset.id)) {
296
- actions.skipChildren();
297
- return;
298
- }
299
- // This prevents children of a wrapped asset also being wrapped - it's an "unsafe" optimisation
300
- // that should only be used when you know (or think you know) what you're doing.
301
- //
302
- // In particular this can force an async bundle to be scope hoisted where it previously would not be
303
- // due to the entry asset being wrapped.
304
- if (this.forceSkipWrapAssets.length > 0 && this.forceSkipWrapAssets.some(p => p === _path().default.relative(this.options.projectRoot, asset.filePath))) {
305
- this.logger.verbose({
306
- message: `Force skipping wrapping of ${_path().default.relative(this.options.projectRoot, asset.filePath)}`
307
- });
308
- actions.skipChildren();
309
- return;
310
- }
311
- if (!asset.meta.isConstantModule) {
312
- this.wrappedAssets.add(asset.id);
313
- wrapped.push(asset);
314
- }
315
- }, 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 (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
+ }
316
333
  }
317
334
  this.assetOutputs = new Map(await queue.run());
318
- 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));
319
349
  }
320
350
  buildExportedSymbols() {
321
351
  if (!this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') {
@@ -495,13 +525,22 @@ class ScopeHoistingPackager {
495
525
  // outside our parcelRequire.register wrapper. This is safe because all
496
526
  // assets referenced by this asset will also be wrapped. Otherwise, inline the
497
527
  // asset content where the import statement was.
498
- if (shouldWrap) {
499
- depContent.push(this.visitAsset(resolved));
528
+ if ((0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovement')) {
529
+ if (!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
+ }
500
535
  } else {
501
- let [depCode, depMap, depLines] = this.visitAsset(resolved);
502
- res = depCode + '\n' + res;
503
- lines += 1 + depLines;
504
- 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
+ }
505
544
  }
506
545
  }
507
546
 
@@ -594,14 +633,6 @@ ${code}
594
633
  this.externalAssets.add(resolved);
595
634
  continue;
596
635
  }
597
-
598
- // If the referencedBundle is a native node import then require it
599
- // directly
600
- // Only enabled for internal builds for now
601
- if (process.env.ATLASPACK_SUPER_BUILD === 'true' && referencedBundle && referencedBundle.type === 'node') {
602
- replacements.set((0, _nullthrows().default)(dep.symbols.get('*')).local, `require('${(0, _utils().relativeBundlePath)(this.bundle, referencedBundle)}')`);
603
- continue;
604
- }
605
636
  }
606
637
  for (let [imported, {
607
638
  local
@@ -888,20 +919,26 @@ ${code}
888
919
  // If there's no __esModule flag, and default is a used symbol, we need
889
920
  // to insert an interop helper.
890
921
  let defaultInterop = asset.symbols.hasExportSymbol('*') && usedSymbols.has('default') && !asset.symbols.hasExportSymbol('__esModule');
891
- let usedNamespace =
892
- // If the asset has * in its used symbols, we might need the exports namespace.
893
- // The one case where this isn't true is in ESM library entries, where the only
894
- // dependency on * is the entry dependency. In this case, we will use ESM exports
895
- // instead of the namespace object.
896
- 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('*'))) ||
897
- // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
898
- // we fallback on the namespace object.
899
- asset.symbols.hasExportSymbol('*') && [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s)) ||
900
- // If the exports has this asset's namespace (e.g. ESM output from CJS input),
901
- // include the namespace object for the default export.
902
- this.exportedSymbols.has(`$${assetId}$exports`) ||
903
- // CommonJS library bundle entries always need a namespace.
904
- 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
+ }
905
942
 
906
943
  // If the asset doesn't have static exports, should wrap, the namespace is used,
907
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.72+9840480de",
3
+ "version": "2.14.5-dev.93+207d003c0",
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.140+9840480de",
19
- "@atlaspack/feature-flags": "2.14.1-dev.140+9840480de",
20
- "@atlaspack/plugin": "2.14.5-dev.72+9840480de",
21
- "@atlaspack/rust": "3.2.1-dev.72+9840480de",
22
- "@atlaspack/types": "2.14.5-dev.72+9840480de",
23
- "@atlaspack/utils": "2.14.5-dev.72+9840480de",
18
+ "@atlaspack/diagnostic": "2.14.1-dev.161+207d003c0",
19
+ "@atlaspack/feature-flags": "2.14.1-dev.161+207d003c0",
20
+ "@atlaspack/plugin": "2.14.5-dev.93+207d003c0",
21
+ "@atlaspack/rust": "3.2.1-dev.93+207d003c0",
22
+ "@atlaspack/types": "2.14.5-dev.93+207d003c0",
23
+ "@atlaspack/utils": "2.14.5-dev.93+207d003c0",
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": "9840480de27511f558d8f5b8cf82220de977b4fb"
29
+ "gitHead": "207d003c0f1d4ffa6a1c52d2f8841d998616c523"
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 +=
@@ -102,7 +102,6 @@ export class ScopeHoistingPackager {
102
102
  needsPrelude: boolean = false;
103
103
  usedHelpers: Set<string> = new Set();
104
104
  externalAssets: Set<Asset> = new Set();
105
- forceSkipWrapAssets: Array<string> = [];
106
105
  logger: PluginLogger;
107
106
 
108
107
  constructor(
@@ -111,7 +110,6 @@ export class ScopeHoistingPackager {
111
110
  bundle: NamedBundle,
112
111
  parcelRequireName: string,
113
112
  useAsyncBundleRuntime: boolean,
114
- forceSkipWrapAssets: Array<string>,
115
113
  logger: PluginLogger,
116
114
  ) {
117
115
  this.options = options;
@@ -119,7 +117,6 @@ export class ScopeHoistingPackager {
119
117
  this.bundle = bundle;
120
118
  this.parcelRequireName = parcelRequireName;
121
119
  this.useAsyncBundleRuntime = useAsyncBundleRuntime;
122
- this.forceSkipWrapAssets = forceSkipWrapAssets ?? [];
123
120
  this.logger = logger;
124
121
 
125
122
  let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
@@ -134,7 +131,8 @@ export class ScopeHoistingPackager {
134
131
  }
135
132
 
136
133
  async package(): Promise<{|contents: string, map: ?SourceMap|}> {
137
- let wrappedAssets = await this.loadAssets();
134
+ let {wrapped: wrappedAssets, constant: constantAssets} =
135
+ await this.loadAssets();
138
136
  this.buildExportedSymbols();
139
137
 
140
138
  // If building a library, the target is actually another bundler rather
@@ -149,13 +147,6 @@ export class ScopeHoistingPackager {
149
147
  for (let b of this.bundleGraph.getReferencedBundles(this.bundle, {
150
148
  recursive: false,
151
149
  })) {
152
- // If the referenced bundle is a native node bundle then don't require it as
153
- // an external as we don't want to require native node bundles from other
154
- // OS architectures
155
- if (process.env.ATLASPACK_SUPER_BUILD === 'true' && b.type === 'node') {
156
- continue;
157
- }
158
-
159
150
  this.externals.set(relativeBundlePath(this.bundle, b), new Map());
160
151
  }
161
152
  }
@@ -175,6 +166,15 @@ export class ScopeHoistingPackager {
175
166
  lineCount += lines + 1;
176
167
  };
177
168
 
169
+ if (getFeatureFlag('inlineConstOptimisationFix')) {
170
+ // Write out all constant modules used by this bundle
171
+ for (let asset of constantAssets) {
172
+ if (!this.seenAssets.has(asset.id)) {
173
+ processAsset(asset);
174
+ }
175
+ }
176
+ }
177
+
178
178
  // Hoist wrapped asset to the top of the bundle to ensure that they are registered
179
179
  // before they are used.
180
180
  for (let asset of wrappedAssets) {
@@ -361,15 +361,20 @@ export class ScopeHoistingPackager {
361
361
  return `$parcel$global.rwr(${params.join(', ')});`;
362
362
  }
363
363
 
364
- async loadAssets(): Promise<Array<Asset>> {
364
+ async loadAssets(): Promise<{|
365
+ wrapped: Array<Asset>,
366
+ constant: Array<Asset>,
367
+ |}> {
365
368
  let queue = new PromiseQueue({maxConcurrent: 32});
366
369
  let wrapped = [];
370
+ let constant = [];
367
371
  this.bundle.traverseAssets((asset) => {
368
372
  queue.add(async () => {
369
373
  let [code, map] = await Promise.all([
370
374
  asset.getCode(),
371
375
  this.bundle.env.sourceMap ? asset.getMapBuffer() : null,
372
376
  ]);
377
+
373
378
  return [asset.id, {code, map}];
374
379
  });
375
380
 
@@ -390,50 +395,83 @@ export class ScopeHoistingPackager {
390
395
  ) {
391
396
  this.wrappedAssets.add(asset.id);
392
397
  wrapped.push(asset);
398
+ } else if (
399
+ getFeatureFlag('inlineConstOptimisationFix') &&
400
+ asset.meta.isConstantModule
401
+ ) {
402
+ constant.push(asset);
393
403
  }
394
404
  }
395
405
  });
396
406
 
397
- for (let wrappedAssetRoot of [...wrapped]) {
398
- this.bundle.traverseAssets((asset, _, actions) => {
399
- if (asset === wrappedAssetRoot) {
400
- return;
401
- }
407
+ if (getFeatureFlag('applyScopeHoistingImprovement')) {
408
+ // Tracks which assets have been assigned to a wrap group
409
+ let assignedAssets = new Set<Asset>();
402
410
 
403
- if (this.wrappedAssets.has(asset.id)) {
404
- actions.skipChildren();
405
- return;
406
- }
407
- // This prevents children of a wrapped asset also being wrapped - it's an "unsafe" optimisation
408
- // that should only be used when you know (or think you know) what you're doing.
409
- //
410
- // In particular this can force an async bundle to be scope hoisted where it previously would not be
411
- // due to the entry asset being wrapped.
412
- if (
413
- this.forceSkipWrapAssets.length > 0 &&
414
- this.forceSkipWrapAssets.some(
415
- (p) =>
416
- p === path.relative(this.options.projectRoot, asset.filePath),
417
- )
418
- ) {
419
- this.logger.verbose({
420
- message: `Force skipping wrapping of ${path.relative(
421
- this.options.projectRoot,
422
- asset.filePath,
423
- )}`,
424
- });
425
- actions.skipChildren();
426
- return;
427
- }
428
- if (!asset.meta.isConstantModule) {
429
- this.wrappedAssets.add(asset.id);
430
- wrapped.push(asset);
431
- }
432
- }, wrappedAssetRoot);
411
+ for (let wrappedAsset of wrapped) {
412
+ this.bundle.traverseAssets((asset, _, actions) => {
413
+ if (asset === wrappedAsset) {
414
+ return;
415
+ }
416
+
417
+ if (this.wrappedAssets.has(asset.id)) {
418
+ actions.skipChildren();
419
+ return;
420
+ }
421
+
422
+ if (assignedAssets.has(asset) || this.isReExported(asset)) {
423
+ wrapped.push(asset);
424
+ this.wrappedAssets.add(asset.id);
425
+
426
+ actions.skipChildren();
427
+ return;
428
+ }
429
+
430
+ assignedAssets.add(asset);
431
+ }, wrappedAsset);
432
+ }
433
+ } else {
434
+ for (let wrappedAssetRoot of [...wrapped]) {
435
+ this.bundle.traverseAssets((asset, _, actions) => {
436
+ if (asset === wrappedAssetRoot) {
437
+ return;
438
+ }
439
+
440
+ if (this.wrappedAssets.has(asset.id)) {
441
+ actions.skipChildren();
442
+ return;
443
+ }
444
+
445
+ if (!asset.meta.isConstantModule) {
446
+ this.wrappedAssets.add(asset.id);
447
+ wrapped.push(asset);
448
+ }
449
+ }, wrappedAssetRoot);
450
+ }
433
451
  }
434
452
 
435
453
  this.assetOutputs = new Map(await queue.run());
436
- return wrapped;
454
+ return {wrapped, constant};
455
+ }
456
+
457
+ isReExported(asset: Asset): boolean {
458
+ let parentSymbols = this.bundleGraph
459
+ .getIncomingDependencies(asset)
460
+ .map((dep) => this.bundleGraph.getAssetWithDependency(dep))
461
+ .flatMap((parent) => {
462
+ if (parent == null) {
463
+ return [];
464
+ }
465
+ return this.bundleGraph.getExportedSymbols(parent, this.bundle);
466
+ });
467
+
468
+ let assetSymbols = this.bundleGraph.getExportedSymbols(asset, this.bundle);
469
+
470
+ return assetSymbols.some((assetSymbol) =>
471
+ parentSymbols.some(
472
+ (parentSymbol) => parentSymbol.symbol === assetSymbol.symbol,
473
+ ),
474
+ );
437
475
  }
438
476
 
439
477
  buildExportedSymbols() {
@@ -668,13 +706,24 @@ export class ScopeHoistingPackager {
668
706
  // outside our parcelRequire.register wrapper. This is safe because all
669
707
  // assets referenced by this asset will also be wrapped. Otherwise, inline the
670
708
  // asset content where the import statement was.
671
- if (shouldWrap) {
672
- depContent.push(this.visitAsset(resolved));
709
+ if (getFeatureFlag('applyScopeHoistingImprovement')) {
710
+ if (!this.wrappedAssets.has(resolved.id)) {
711
+ let [depCode, depMap, depLines] =
712
+ this.visitAsset(resolved);
713
+ res = depCode + '\n' + res;
714
+ lines += 1 + depLines;
715
+ map = depMap;
716
+ }
673
717
  } else {
674
- let [depCode, depMap, depLines] = this.visitAsset(resolved);
675
- res = depCode + '\n' + res;
676
- lines += 1 + depLines;
677
- map = depMap;
718
+ if (shouldWrap) {
719
+ depContent.push(this.visitAsset(resolved));
720
+ } else {
721
+ let [depCode, depMap, depLines] =
722
+ this.visitAsset(resolved);
723
+ res = depCode + '\n' + res;
724
+ lines += 1 + depLines;
725
+ map = depMap;
726
+ }
678
727
  }
679
728
  }
680
729
 
@@ -816,21 +865,6 @@ ${code}
816
865
  this.externalAssets.add(resolved);
817
866
  continue;
818
867
  }
819
-
820
- // If the referencedBundle is a native node import then require it
821
- // directly
822
- // Only enabled for internal builds for now
823
- if (
824
- process.env.ATLASPACK_SUPER_BUILD === 'true' &&
825
- referencedBundle &&
826
- referencedBundle.type === 'node'
827
- ) {
828
- replacements.set(
829
- nullthrows(dep.symbols.get('*')).local,
830
- `require('${relativeBundlePath(this.bundle, referencedBundle)}')`,
831
- );
832
- continue;
833
- }
834
868
  }
835
869
 
836
870
  for (let [imported, {local}] of dep.symbols) {
@@ -1242,34 +1276,49 @@ ${code}
1242
1276
  usedSymbols.has('default') &&
1243
1277
  !asset.symbols.hasExportSymbol('__esModule');
1244
1278
 
1245
- let usedNamespace =
1246
- // If the asset has * in its used symbols, we might need the exports namespace.
1247
- // The one case where this isn't true is in ESM library entries, where the only
1248
- // dependency on * is the entry dependency. In this case, we will use ESM exports
1249
- // instead of the namespace object.
1250
- (usedSymbols.has('*') &&
1251
- (this.bundle.env.outputFormat !== 'esmodule' ||
1252
- !this.bundle.env.isLibrary ||
1253
- asset !== this.bundle.getMainEntry() ||
1254
- this.bundleGraph
1255
- .getIncomingDependencies(asset)
1256
- .some(
1257
- (dep) =>
1258
- !dep.isEntry &&
1259
- this.bundle.hasDependency(dep) &&
1260
- nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1261
- ))) ||
1262
- // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
1263
- // we fallback on the namespace object.
1264
- (asset.symbols.hasExportSymbol('*') &&
1265
- [...usedSymbols].some((s) => !asset.symbols.hasExportSymbol(s))) ||
1266
- // If the exports has this asset's namespace (e.g. ESM output from CJS input),
1267
- // include the namespace object for the default export.
1268
- this.exportedSymbols.has(`$${assetId}$exports`) ||
1269
- // CommonJS library bundle entries always need a namespace.
1270
- (this.bundle.env.isLibrary &&
1271
- this.bundle.env.outputFormat === 'commonjs' &&
1272
- asset === this.bundle.getMainEntry());
1279
+ let usedNamespace;
1280
+ if (
1281
+ getFeatureFlag('inlineConstOptimisationFix') &&
1282
+ asset.meta.isConstantModule
1283
+ ) {
1284
+ // Only set usedNamespace if there is an incoming dependency in the current bundle that uses '*'
1285
+ usedNamespace = this.bundleGraph
1286
+ .getIncomingDependencies(asset)
1287
+ .some(
1288
+ (dep) =>
1289
+ this.bundle.hasDependency(dep) &&
1290
+ nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1291
+ );
1292
+ } else {
1293
+ usedNamespace =
1294
+ // If the asset has * in its used symbols, we might need the exports namespace.
1295
+ // The one case where this isn't true is in ESM library entries, where the only
1296
+ // dependency on * is the entry dependency. In this case, we will use ESM exports
1297
+ // instead of the namespace object.
1298
+ (usedSymbols.has('*') &&
1299
+ (this.bundle.env.outputFormat !== 'esmodule' ||
1300
+ !this.bundle.env.isLibrary ||
1301
+ asset !== this.bundle.getMainEntry() ||
1302
+ this.bundleGraph
1303
+ .getIncomingDependencies(asset)
1304
+ .some(
1305
+ (dep) =>
1306
+ !dep.isEntry &&
1307
+ this.bundle.hasDependency(dep) &&
1308
+ nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1309
+ ))) ||
1310
+ // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
1311
+ // we fallback on the namespace object.
1312
+ (asset.symbols.hasExportSymbol('*') &&
1313
+ [...usedSymbols].some((s) => !asset.symbols.hasExportSymbol(s))) ||
1314
+ // If the exports has this asset's namespace (e.g. ESM output from CJS input),
1315
+ // include the namespace object for the default export.
1316
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
1317
+ // CommonJS library bundle entries always need a namespace.
1318
+ (this.bundle.env.isLibrary &&
1319
+ this.bundle.env.outputFormat === 'commonjs' &&
1320
+ asset === this.bundle.getMainEntry());
1321
+ }
1273
1322
 
1274
1323
  // If the asset doesn't have static exports, should wrap, the namespace is used,
1275
1324
  // 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(