@atlaspack/packager-js 2.14.5-canary.32 → 2.14.5-canary.320

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.
@@ -12,7 +12,7 @@ function _utils() {
12
12
  return data;
13
13
  }
14
14
  function _sourceMap2() {
15
- const data = _interopRequireDefault(require("@parcel/source-map"));
15
+ const data = _interopRequireDefault(require("@atlaspack/source-map"));
16
16
  _sourceMap2 = function () {
17
17
  return data;
18
18
  };
@@ -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");
@@ -70,7 +77,6 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
70
77
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
71
78
  // General regex used to replace imports with the resolved code, references with resolutions,
72
79
  // and count the number of newlines in the file for source maps.
73
- //
74
80
  // For conditional bundling the only difference in this regex is adding `importCond` where we have `importAsync` etc..
75
81
  const REPLACEMENT_RE_CONDITIONAL = /\n|import\s+"([0-9a-f]{16,20}:.+?)";|(?:\$[0-9a-f]{16,20}\$exports)|(?:\$[0-9a-f]{16,20}\$(?:import|importAsync|require|importCond)\$[0-9a-f]+(?:\$[0-9a-f]+)?)/g;
76
82
  const REPLACEMENT_RE = /\n|import\s+"([0-9a-f]{16,20}:.+?)";|(?:\$[0-9a-f]{16,20}\$exports)|(?:\$[0-9a-f]{16,20}\$(?:import|importAsync|require)\$[0-9a-f]+(?:\$[0-9a-f]+)?)/g;
@@ -80,6 +86,7 @@ const GLOBALS_BY_CONTEXT = {
80
86
  'web-worker': new Set([...BUILTINS, ...Object.keys(_globals().default.worker)]),
81
87
  'service-worker': new Set([...BUILTINS, ...Object.keys(_globals().default.serviceworker)]),
82
88
  worklet: new Set([...BUILTINS]),
89
+ tesseract: new Set([...BUILTINS, ...Object.keys(_globals().default.worker)]),
83
90
  node: new Set([...BUILTINS, ...Object.keys(_globals().default.node)]),
84
91
  'electron-main': new Set([...BUILTINS, ...Object.keys(_globals().default.node)]),
85
92
  'electron-renderer': new Set([...BUILTINS, ...Object.keys(_globals().default.node), ...Object.keys(_globals().default.browser)])
@@ -90,32 +97,36 @@ const OUTPUT_FORMATS = {
90
97
  global: _GlobalOutputFormat.GlobalOutputFormat
91
98
  };
92
99
  class ScopeHoistingPackager {
100
+ assetOutputs = new Map();
93
101
  exportedSymbols = new Map();
94
102
  externals = new Map();
95
103
  topLevelNames = new Map();
96
104
  seenAssets = new Set();
97
105
  wrappedAssets = new Set();
106
+ constantAssets = new Set();
98
107
  hoistedRequires = new Map();
108
+ seenHoistedRequires = new Set();
99
109
  needsPrelude = false;
100
110
  usedHelpers = new Set();
101
111
  externalAssets = new Set();
102
- forceSkipWrapAssets = [];
103
- constructor(options, bundleGraph, bundle, parcelRequireName, useAsyncBundleRuntime, forceSkipWrapAssets, logger) {
112
+ useBothScopeHoistingImprovements = (0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovementV2') || (0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovement');
113
+ referencedAssetsCache = new Map();
114
+ constructor(options, bundleGraph, bundle, parcelRequireName, useAsyncBundleRuntime, manualStaticBindingExports, logger) {
104
115
  this.options = options;
105
116
  this.bundleGraph = bundleGraph;
106
117
  this.bundle = bundle;
107
118
  this.parcelRequireName = parcelRequireName;
108
119
  this.useAsyncBundleRuntime = useAsyncBundleRuntime;
109
- this.forceSkipWrapAssets = forceSkipWrapAssets ?? [];
120
+ this.manualStaticBindingExports = (manualStaticBindingExports === null || manualStaticBindingExports === void 0 ? void 0 : manualStaticBindingExports.map(glob => (0, _utils().globToRegex)(glob))) ?? null;
110
121
  this.logger = logger;
111
122
  let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
112
123
  this.outputFormat = new OutputFormat(this);
113
- this.isAsyncBundle = this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') && !this.bundle.env.isIsolated() && this.bundle.bundleBehavior !== 'isolated';
124
+ this.isAsyncBundle = this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') && !this.bundle.env.isIsolated() && this.bundle.bundleBehavior !== 'isolated' && this.bundle.bundleBehavior !== 'inlineIsolated';
114
125
  this.globalNames = GLOBALS_BY_CONTEXT[bundle.env.context];
115
126
  }
116
127
  async package() {
117
128
  var _sourceMap;
118
- let wrappedAssets = await this.loadAssets();
129
+ await this.loadAssets();
119
130
  this.buildExportedSymbols();
120
131
 
121
132
  // If building a library, the target is actually another bundler rather
@@ -134,6 +145,7 @@ class ScopeHoistingPackager {
134
145
  let lineCount = 0;
135
146
  let sourceMap = null;
136
147
  let processAsset = asset => {
148
+ this.seenHoistedRequires.clear();
137
149
  let [content, map, lines] = this.visitAsset(asset);
138
150
  if (sourceMap && map) {
139
151
  sourceMap.addSourceMap(map, lineCount);
@@ -143,11 +155,19 @@ class ScopeHoistingPackager {
143
155
  res += content + '\n';
144
156
  lineCount += lines + 1;
145
157
  };
158
+ if ((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix') || this.useBothScopeHoistingImprovements) {
159
+ // Write out all constant modules used by this bundle
160
+ for (let asset of this.constantAssets) {
161
+ if (!this.seenAssets.has(asset)) {
162
+ processAsset(asset);
163
+ }
164
+ }
165
+ }
146
166
 
147
167
  // Hoist wrapped asset to the top of the bundle to ensure that they are registered
148
168
  // before they are used.
149
- for (let asset of wrappedAssets) {
150
- if (!this.seenAssets.has(asset.id)) {
169
+ for (let asset of this.wrappedAssets) {
170
+ if (!this.seenAssets.has(asset)) {
151
171
  processAsset(asset);
152
172
  }
153
173
  }
@@ -155,7 +175,7 @@ class ScopeHoistingPackager {
155
175
  // Add each asset that is directly connected to the bundle. Dependencies will be handled
156
176
  // by replacing `import` statements in the code.
157
177
  this.bundle.traverseAssets((asset, _, actions) => {
158
- if (this.seenAssets.has(asset.id)) {
178
+ if (this.seenAssets.has(asset)) {
159
179
  actions.skipChildren();
160
180
  return;
161
181
  }
@@ -165,23 +185,35 @@ class ScopeHoistingPackager {
165
185
  let [prelude, preludeLines] = this.buildBundlePrelude();
166
186
  res = prelude + res;
167
187
  lineCount += preludeLines;
188
+ // @ts-expect-error TS2339 - offsetLines method exists but missing from @parcel/source-map type definitions
168
189
  (_sourceMap = sourceMap) === null || _sourceMap === void 0 || _sourceMap.offsetLines(1, preludeLines);
169
190
  let entries = this.bundle.getEntryAssets();
170
191
  let mainEntry = this.bundle.getMainEntry();
171
192
  if (this.isAsyncBundle) {
172
- // In async bundles we don't want the main entry to execute until we require it
173
- // as there might be dependencies in a sibling bundle that hasn't loaded yet.
174
- entries = entries.filter(a => {
175
- var _mainEntry;
176
- return a.id !== ((_mainEntry = mainEntry) === null || _mainEntry === void 0 ? void 0 : _mainEntry.id);
177
- });
193
+ if (this.useBothScopeHoistingImprovements || (0, _featureFlags().getFeatureFlag)('supportWebpackChunkName')) {
194
+ // Generally speaking, async bundles should not be executed on load, as
195
+ // they're just collections of assets that other assets require.
196
+ // However, there are some special cases where a runtime asset needs to be
197
+ // injected, but no other asset will require it (mostly the bundle
198
+ // manifest).
199
+ // In this case, those assets need to be required on load.
200
+ entries = entries.filter(a => {
201
+ var _a$meta;
202
+ return (_a$meta = a.meta) === null || _a$meta === void 0 ? void 0 : _a$meta.runtimeAssetRequiringExecutionOnLoad;
203
+ });
204
+ } else {
205
+ entries = entries.filter(a => {
206
+ var _mainEntry;
207
+ return a.id !== ((_mainEntry = mainEntry) === null || _mainEntry === void 0 ? void 0 : _mainEntry.id);
208
+ });
209
+ }
178
210
  mainEntry = null;
179
211
  }
180
212
  let needsBundleQueue = this.shouldBundleQueue(this.bundle);
181
213
 
182
214
  // If any of the entry assets are wrapped, call parcelRequire so they are executed.
183
215
  for (let entry of entries) {
184
- if (this.wrappedAssets.has(entry.id) && !this.isScriptEntry(entry)) {
216
+ if (this.wrappedAssets.has(entry) && !this.isScriptEntry(entry)) {
185
217
  var _entry$symbols$get;
186
218
  let parcelRequire = `parcelRequire(${JSON.stringify(this.bundleGraph.getAssetPublicId(entry))});\n`;
187
219
  let entryExports = (_entry$symbols$get = entry.symbols.get('*')) === null || _entry$symbols$get === void 0 ? void 0 : _entry$symbols$get.local;
@@ -211,38 +243,46 @@ class ScopeHoistingPackager {
211
243
  let {
212
244
  code,
213
245
  map: mapBuffer
214
- } = (0, _nullthrows().default)(this.assetOutputs.get(mainEntry.id));
246
+ } = (0, _nullthrows().default)(this.assetOutputs.get(mainEntry));
215
247
  let map;
216
248
  if (mapBuffer) {
217
249
  map = new (_sourceMap2().default)(this.options.projectRoot, mapBuffer);
218
250
  }
219
251
  res += (0, _utils2.replaceScriptDependencies)(this.bundleGraph, this.bundle, code, map, this.parcelRequireName);
220
252
  if (sourceMap && map) {
253
+ // @ts-expect-error TS2339 - addSourceMap method exists but missing from @parcel/source-map type definitions
221
254
  sourceMap.addSourceMap(map, lineCount);
222
255
  }
223
256
  }
224
- return {
257
+ const result = {
225
258
  contents: res,
226
259
  map: sourceMap
227
260
  };
261
+ if (_utils().debugTools['scope-hoisting-stats']) {
262
+ result.scopeHoistingStats = {
263
+ totalAssets: this.assetOutputs.size,
264
+ wrappedAssets: this.wrappedAssets.size
265
+ };
266
+ }
267
+ return result;
228
268
  }
229
269
  shouldBundleQueue(bundle) {
230
270
  let referencingBundles = this.bundleGraph.getReferencingBundles(bundle);
231
271
  let hasHtmlReference = referencingBundles.some(b => b.type === 'html');
232
272
  let hasConditionalReference = false;
233
273
  let isConditionalBundle = false;
234
- if ((0, _featureFlags().getFeatureFlag)('conditionalBundlingApi') && (0, _featureFlags().getFeatureFlag)('conditionalBundlingAsyncRuntime')) {
274
+ if ((0, _featureFlags().getFeatureFlag)('conditionalBundlingApi')) {
235
275
  // If the bundle has a conditional bundle reference (has an importCond)
236
276
  hasConditionalReference = this.bundleGraph.getReferencedConditionalBundles(bundle).length > 0;
237
277
  // If the bundle is a conditional bundle
238
278
  isConditionalBundle = this.hasConditionalDependency();
239
279
  }
240
- return this.useAsyncBundleRuntime && bundle.type === 'js' && bundle.bundleBehavior !== 'inline' && bundle.env.outputFormat === 'esmodule' && !bundle.env.isIsolated() && bundle.bundleBehavior !== 'isolated' && (hasHtmlReference || hasConditionalReference || isConditionalBundle);
280
+ return this.useAsyncBundleRuntime && bundle.type === 'js' && bundle.bundleBehavior !== 'inline' && bundle.bundleBehavior !== 'inlineIsolated' && bundle.env.outputFormat === 'esmodule' && !bundle.env.isIsolated() && bundle.bundleBehavior !== 'isolated' && (hasHtmlReference || hasConditionalReference || isConditionalBundle);
241
281
  }
242
282
  runWhenReady(bundle, codeToRun) {
243
283
  let deps = this.bundleGraph.getReferencedBundles(bundle).filter(b => this.shouldBundleQueue(b)).map(b => b.publicId);
244
284
  const conditions = [];
245
- if ((0, _featureFlags().getFeatureFlag)('conditionalBundlingApi') && (0, _featureFlags().getFeatureFlag)('conditionalBundlingAsyncRuntime')) {
285
+ if ((0, _featureFlags().getFeatureFlag)('conditionalBundlingApi')) {
246
286
  const conditionSet = this.bundleGraph.getConditionalBundleMapping().get(bundle.id);
247
287
  for (const [key, {
248
288
  ifTrueBundles,
@@ -260,56 +300,133 @@ class ScopeHoistingPackager {
260
300
  let params = [JSON.stringify(this.bundle.publicId), (0, _helpers.fnExpr)(this.bundle.env, [], [codeToRun]), `${JSON.stringify(deps)}${conditions.length > 0 ? `.concat([${conditions.map(conditions => `...${conditions}`).join(',')}])` : ''}`];
261
301
  return `$parcel$global.rwr(${params.join(', ')});`;
262
302
  }
303
+
304
+ // Helper to check if an asset is referenced, with cache-first + fast-check hybrid approach
305
+ isAssetReferencedInBundle(bundle, asset) {
306
+ // STEP 1: Check expensive computation cache first (fastest when it hits)
307
+ if ((0, _featureFlags().getFeatureFlag)('precomputeReferencedAssets')) {
308
+ let bundleId = bundle.id;
309
+ let referencedAssets = this.referencedAssetsCache.get(bundleId);
310
+ if (referencedAssets) {
311
+ // Cache hit - fastest path (~0.001ms)
312
+ return referencedAssets.has(asset);
313
+ }
314
+ }
315
+
316
+ // STEP 2: Cache miss - try fast checks (~0.01ms)
317
+ let fastCheckResult = this.bundleGraph.isAssetReferencedFastCheck(bundle, asset);
318
+ if (fastCheckResult === true) {
319
+ // Fast check succeeded - asset is referenced
320
+ return true;
321
+ }
322
+
323
+ // STEP 3: Need expensive computation (~20-2000ms)
324
+ if ((0, _featureFlags().getFeatureFlag)('precomputeReferencedAssets')) {
325
+ // Compute and cache expensive results for this bundle
326
+ let bundleId = bundle.id;
327
+ let referencedAssets = this.bundleGraph.getReferencedAssets(bundle);
328
+ this.referencedAssetsCache.set(bundleId, referencedAssets);
329
+ return referencedAssets.has(asset);
330
+ } else {
331
+ // No caching - fall back to original expensive method
332
+ return this.bundleGraph.isAssetReferenced(bundle, asset);
333
+ }
334
+ }
263
335
  async loadAssets() {
264
336
  let queue = new (_utils().PromiseQueue)({
265
337
  maxConcurrent: 32
266
338
  });
267
- let wrapped = [];
268
339
  this.bundle.traverseAssets(asset => {
269
340
  queue.add(async () => {
270
341
  let [code, map] = await Promise.all([asset.getCode(), this.bundle.env.sourceMap ? asset.getMapBuffer() : null]);
271
- return [asset.id, {
342
+ return [asset, {
272
343
  code,
273
344
  map
274
345
  }];
275
346
  });
276
- 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')) {
347
+ if (asset.meta.shouldWrap || this.bundle.env.sourceType === 'script' || this.isAssetReferencedInBundle(this.bundle, asset) || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.meta.shouldWrap && dep.specifierType !== 'url')) {
277
348
  // Don't wrap constant "entry" modules _except_ if they are referenced by any lazy dependency
278
349
  if (!asset.meta.isConstantModule || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.priority === 'lazy')) {
279
- this.wrappedAssets.add(asset.id);
280
- wrapped.push(asset);
350
+ this.wrappedAssets.add(asset);
351
+ } else if (((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix') || this.useBothScopeHoistingImprovements) && asset.meta.isConstantModule) {
352
+ this.constantAssets.add(asset);
281
353
  }
282
354
  }
283
355
  });
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;
356
+ if (this.useBothScopeHoistingImprovements) {
357
+ // Tracks which assets have been assigned to a wrap group
358
+ let assignedAssets = new Set();
359
+
360
+ // In V2 scope hoisting, we iterate from the main entry, rather than
361
+ // wrapping the entry assets
362
+ if (!(0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovementV2')) {
363
+ // Make all entry assets wrapped, to avoid any top level hoisting
364
+ for (let entryAsset of this.bundle.getEntryAssets()) {
365
+ if (!this.wrappedAssets.has(entryAsset)) {
366
+ this.wrappedAssets.add(entryAsset);
367
+ }
304
368
  }
305
- if (!asset.meta.isConstantModule) {
306
- this.wrappedAssets.add(asset.id);
307
- wrapped.push(asset);
369
+ }
370
+
371
+ // We need to make a new copy here so that we can add to the list and
372
+ // iterate the newly added items, without mutating the wrappedAssets set
373
+ let moduleGroupParents = [...this.wrappedAssets.values()];
374
+ if ((0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovementV2')) {
375
+ // The main entry needs to be check to find assets that would have gone in
376
+ // the top level scope
377
+ let mainEntry = this.bundle.getMainEntry();
378
+ if (mainEntry && !this.wrappedAssets.has(mainEntry)) {
379
+ moduleGroupParents.unshift(mainEntry);
308
380
  }
309
- }, wrappedAssetRoot);
381
+ }
382
+ for (let moduleGroupParentAsset of moduleGroupParents) {
383
+ this.bundle.traverseAssets((asset, _, actions) => {
384
+ if (asset === moduleGroupParentAsset) {
385
+ return;
386
+ }
387
+ if (this.wrappedAssets.has(asset)) {
388
+ actions.skipChildren();
389
+ return;
390
+ }
391
+ if (!asset.meta.isConstantModule && (assignedAssets.has(asset) || this.isReExported(asset))) {
392
+ this.wrappedAssets.add(asset);
393
+
394
+ // This also needs to be added to the traversal so that we iterate
395
+ // it during this check.
396
+ moduleGroupParents.push(asset);
397
+ actions.skipChildren();
398
+ return;
399
+ }
400
+ assignedAssets.add(asset);
401
+ }, moduleGroupParentAsset);
402
+ }
403
+ } else {
404
+ for (let wrappedAssetRoot of this.wrappedAssets) {
405
+ this.bundle.traverseAssets((asset, _, actions) => {
406
+ if (asset === wrappedAssetRoot) {
407
+ return;
408
+ }
409
+ if (this.wrappedAssets.has(asset)) {
410
+ actions.skipChildren();
411
+ return;
412
+ }
413
+ if (!asset.meta.isConstantModule) {
414
+ this.wrappedAssets.add(asset);
415
+ }
416
+ }, wrappedAssetRoot);
417
+ }
310
418
  }
311
419
  this.assetOutputs = new Map(await queue.run());
312
- return wrapped;
420
+ }
421
+ isReExported(asset) {
422
+ let parentSymbols = this.bundleGraph.getIncomingDependencies(asset).map(dep => this.bundleGraph.getAssetWithDependency(dep)).flatMap(parent => {
423
+ if (parent == null) {
424
+ return [];
425
+ }
426
+ return this.bundleGraph.getExportedSymbols(parent, this.bundle);
427
+ });
428
+ let assetSymbols = this.bundleGraph.getExportedSymbols(asset, this.bundle);
429
+ return assetSymbols.some(assetSymbol => parentSymbols.some(parentSymbol => parentSymbol.symbol === assetSymbol.symbol));
313
430
  }
314
431
  buildExportedSymbols() {
315
432
  if (!this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') {
@@ -318,7 +435,7 @@ class ScopeHoistingPackager {
318
435
 
319
436
  // TODO: handle ESM exports of wrapped entry assets...
320
437
  let entry = this.bundle.getMainEntry();
321
- if (entry && !this.wrappedAssets.has(entry.id)) {
438
+ if (entry && !this.wrappedAssets.has(entry)) {
322
439
  let hasNamespace = entry.symbols.hasExportSymbol('*');
323
440
  for (let {
324
441
  asset,
@@ -387,16 +504,19 @@ class ScopeHoistingPackager {
387
504
  return `${obj}[${JSON.stringify(property)}]`;
388
505
  }
389
506
  visitAsset(asset) {
390
- (0, _assert().default)(!this.seenAssets.has(asset.id), 'Already visited asset');
391
- this.seenAssets.add(asset.id);
507
+ (0, _assert().default)(!this.seenAssets.has(asset), 'Already visited asset');
508
+ this.seenAssets.add(asset);
392
509
  let {
393
510
  code,
394
511
  map
395
- } = (0, _nullthrows().default)(this.assetOutputs.get(asset.id));
512
+ } = (0, _nullthrows().default)(this.assetOutputs.get(asset));
396
513
  return this.buildAsset(asset, code, map);
397
514
  }
515
+ getAssetFilePath(asset) {
516
+ return _path().default.relative(this.options.projectRoot, asset.filePath);
517
+ }
398
518
  buildAsset(asset, code, map) {
399
- let shouldWrap = this.wrappedAssets.has(asset.id);
519
+ let shouldWrap = this.wrappedAssets.has(asset);
400
520
  let deps = this.bundleGraph.getDependencies(asset);
401
521
  let sourceMap = this.bundle.env.sourceMap && map ? new (_sourceMap2().default)(this.options.projectRoot, map) : null;
402
522
 
@@ -416,13 +536,26 @@ class ScopeHoistingPackager {
416
536
  }
417
537
  continue;
418
538
  }
419
- if (this.bundle.hasAsset(resolved) && !this.seenAssets.has(resolved.id)) {
420
- let [code, map, lines] = this.visitAsset(resolved);
421
- depCode += code + '\n';
422
- if (sourceMap && map) {
423
- sourceMap.addSourceMap(map, lineCount);
539
+ if (this.bundle.hasAsset(resolved) && !this.seenAssets.has(resolved)) {
540
+ if (this.useBothScopeHoistingImprovements && this.wrappedAssets.has(resolved)) {
541
+ if (this.wrappedAssets.has(asset)) {
542
+ // If both the asset and the dep are wrapped there's no need to
543
+ // drop a side-effect require. This is an extremely rare case.
544
+ continue;
545
+ }
546
+
547
+ // When the dep is wrapped then we just need to drop a side effect
548
+ // require instead of inlining
549
+ depCode += `parcelRequire("${this.bundleGraph.getAssetPublicId(resolved)}");\n`;
550
+ lineCount += 1;
551
+ } else {
552
+ let [code, map, lines] = this.visitAsset(resolved);
553
+ depCode += code + '\n';
554
+ if (sourceMap && map) {
555
+ sourceMap.addSourceMap(map, lineCount);
556
+ }
557
+ lineCount += lines + 1;
424
558
  }
425
- lineCount += lines + 1;
426
559
  }
427
560
  }
428
561
  return [depCode, sourceMap, lineCount];
@@ -482,20 +615,51 @@ class ScopeHoistingPackager {
482
615
  // after the dependency is declared. This handles the case where the resulting asset
483
616
  // is wrapped, but the dependency in this asset is not marked as wrapped. This means
484
617
  // that it was imported/required at the top-level, so its side effects should run immediately.
485
- let [res, lines] = this.getHoistedParcelRequires(asset, dep, resolved);
618
+ let res = '';
619
+ let lines = 0;
486
620
  let map;
487
- if (this.bundle.hasAsset(resolved) && !this.seenAssets.has(resolved.id)) {
621
+ if (!(0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovementV2')) {
622
+ [res, lines] = this.getHoistedParcelRequires(asset, dep, resolved);
623
+ }
624
+ if (this.bundle.hasAsset(resolved) && !this.seenAssets.has(resolved)) {
488
625
  // If this asset is wrapped, we need to hoist the code for the dependency
489
626
  // outside our parcelRequire.register wrapper. This is safe because all
490
627
  // assets referenced by this asset will also be wrapped. Otherwise, inline the
491
628
  // asset content where the import statement was.
492
- if (shouldWrap) {
493
- depContent.push(this.visitAsset(resolved));
629
+ if (this.useBothScopeHoistingImprovements) {
630
+ if (!resolved.meta.isConstantModule && !this.wrappedAssets.has(resolved)) {
631
+ let [depCode, depMap, depLines] = this.visitAsset(resolved);
632
+ if (_utils().debugTools['asset-file-names-in-output']) {
633
+ let resolvedPath = this.getAssetFilePath(resolved);
634
+ res = (0, _outdent().outdent)`
635
+ /* Scope hoisted asset: ${resolvedPath} */
636
+ ${depCode}
637
+ /* End: ${resolvedPath} */
638
+ ${res}
639
+ `;
640
+ lines += 3 + depLines;
641
+ } else {
642
+ res = depCode + '\n' + res;
643
+ lines += 1 + depLines;
644
+ }
645
+ map = depMap;
646
+ }
494
647
  } else {
495
- let [depCode, depMap, depLines] = this.visitAsset(resolved);
496
- res = depCode + '\n' + res;
497
- lines += 1 + depLines;
498
- map = depMap;
648
+ if (shouldWrap) {
649
+ depContent.push(this.visitAsset(resolved));
650
+ } else {
651
+ let [depCode, depMap, depLines] = this.visitAsset(resolved);
652
+ res = depCode + '\n' + res;
653
+ lines += 1 + depLines;
654
+ map = depMap;
655
+ }
656
+ }
657
+ }
658
+ if ((0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovementV2')) {
659
+ let [requiresCode, requiresLines] = this.getHoistedParcelRequires(asset, dep, resolved);
660
+ if (requiresCode) {
661
+ res = requiresCode + '\n' + res;
662
+ lines += requiresLines + 1;
499
663
  }
500
664
  }
501
665
 
@@ -542,6 +706,10 @@ ${code}
542
706
  });
543
707
  `;
544
708
  lineCount += 2;
709
+ if (_utils().debugTools['asset-file-names-in-output']) {
710
+ code = `/* ${this.getAssetFilePath(asset)} */\n` + code;
711
+ lineCount += 1;
712
+ }
545
713
  for (let [depCode, map, lines] of depContent) {
546
714
  if (!depCode) continue;
547
715
  code += depCode + '\n';
@@ -583,7 +751,7 @@ ${code}
583
751
  // Handle imports from other bundles in libraries.
584
752
  if (this.bundle.env.isLibrary && !this.bundle.hasAsset(resolved)) {
585
753
  let referencedBundle = this.bundleGraph.getReferencedBundle(dep, this.bundle);
586
- if (referencedBundle && referencedBundle.getMainEntry() === resolved && referencedBundle.type === 'js' && !this.bundleGraph.isAssetReferenced(referencedBundle, resolved)) {
754
+ if (referencedBundle && referencedBundle.getMainEntry() === resolved && referencedBundle.type === 'js' && !this.isAssetReferencedInBundle(referencedBundle, resolved)) {
587
755
  this.addExternal(dep, replacements, referencedBundle);
588
756
  this.externalAssets.add(resolved);
589
757
  continue;
@@ -614,7 +782,7 @@ ${code}
614
782
 
615
783
  // If this asset is wrapped, we need to replace the exports namespace with `module.exports`,
616
784
  // which will be provided to us by the wrapper.
617
- if (this.wrappedAssets.has(asset.id) || this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry()) {
785
+ if (this.wrappedAssets.has(asset) || this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry()) {
618
786
  var _asset$symbols$get;
619
787
  let exportsName = ((_asset$symbols$get = asset.symbols.get('*')) === null || _asset$symbols$get === void 0 ? void 0 : _asset$symbols$get.local) || `$${assetId}$exports`;
620
788
  replacements.set(exportsName, 'module.exports');
@@ -648,6 +816,7 @@ ${code}
648
816
  local
649
817
  }] of dep.symbols) {
650
818
  // If already imported, just add the already renamed variable to the mapping.
819
+
651
820
  let renamed = external.get(imported);
652
821
  if (renamed && local !== '*' && replacements) {
653
822
  replacements.set(local, renamed);
@@ -711,7 +880,7 @@ ${code}
711
880
  continue;
712
881
  }
713
882
  }
714
- renamed = this.bundleGraph.getSymbolResolution(entry, imported, this.bundle).symbol;
883
+ renamed = this.bundleGraph.getSymbolResolution(entry, imported, this.bundle).symbol || undefined;
715
884
  }
716
885
  }
717
886
 
@@ -752,7 +921,7 @@ ${code}
752
921
  }
753
922
  return false;
754
923
  }
755
- return !this.bundle.hasAsset(resolved) && !this.externalAssets.has(resolved) || this.wrappedAssets.has(resolved.id) && resolved !== parentAsset;
924
+ return !this.bundle.hasAsset(resolved) && !this.externalAssets.has(resolved) || this.wrappedAssets.has(resolved) && resolved !== parentAsset;
756
925
  }
757
926
  getSymbolResolution(parentAsset, resolved, imported, dep, replacements) {
758
927
  let {
@@ -779,12 +948,12 @@ ${code}
779
948
  // Only do this if the asset is part of a different bundle (so it was definitely
780
949
  // parcelRequire.register'ed there), or if it is indeed registered in this bundle.
781
950
  !this.bundle.hasAsset(resolvedAsset) || !this.shouldSkipAsset(resolvedAsset))) {
782
- let hoisted = this.hoistedRequires.get(dep.id);
951
+ let hoisted = this.hoistedRequires.get(dep);
783
952
  if (!hoisted) {
784
953
  hoisted = new Map();
785
- this.hoistedRequires.set(dep.id, hoisted);
954
+ this.hoistedRequires.set(dep, hoisted);
786
955
  }
787
- hoisted.set(resolvedAsset.id, `var $${publicId} = parcelRequire(${JSON.stringify(publicId)});`);
956
+ hoisted.set(resolvedAsset, `var $${publicId} = parcelRequire(${JSON.stringify(publicId)});`);
788
957
  }
789
958
  if (isWrapped) {
790
959
  this.needsPrelude = true;
@@ -813,7 +982,7 @@ ${code}
813
982
  }
814
983
  if (imported === '*' || exportSymbol === '*' || isDefaultInterop) {
815
984
  // Resolve to the namespace object if requested or this is a CJS default interop reqiure.
816
- if (parentAsset === resolvedAsset && this.wrappedAssets.has(resolvedAsset.id)) {
985
+ if (parentAsset === resolvedAsset && this.wrappedAssets.has(resolvedAsset)) {
817
986
  // Directly use module.exports for wrapped assets importing themselves.
818
987
  return 'module.exports';
819
988
  } else {
@@ -841,7 +1010,7 @@ ${code}
841
1010
  if (resolved.type !== 'js') {
842
1011
  return ['', 0];
843
1012
  }
844
- let hoisted = this.hoistedRequires.get(dep.id);
1013
+ let hoisted = this.hoistedRequires.get(dep);
845
1014
  let res = '';
846
1015
  let lineCount = 0;
847
1016
  let isWrapped = this.isWrapped(resolved, parentAsset);
@@ -850,14 +1019,23 @@ ${code}
850
1019
  // we need to run side effects when this asset runs. If the resolved asset is not
851
1020
  // the first one in the hoisted requires, we need to insert a parcelRequire here
852
1021
  // so it runs first.
853
- if (isWrapped && !dep.meta.shouldWrap && (!hoisted || hoisted.keys().next().value !== resolved.id) && !this.bundleGraph.isDependencySkipped(dep) && !this.shouldSkipAsset(resolved)) {
1022
+ if (isWrapped && !dep.meta.shouldWrap && (!hoisted || hoisted.keys().next().value !== resolved) && !this.bundleGraph.isDependencySkipped(dep) && !this.shouldSkipAsset(resolved)) {
854
1023
  this.needsPrelude = true;
855
1024
  res += `parcelRequire(${JSON.stringify(this.bundleGraph.getAssetPublicId(resolved))});`;
856
1025
  }
857
1026
  if (hoisted) {
858
1027
  this.needsPrelude = true;
859
- res += '\n' + [...hoisted.values()].join('\n');
860
- lineCount += hoisted.size;
1028
+ if ((0, _featureFlags().getFeatureFlag)('applyScopeHoistingImprovementV2')) {
1029
+ let hoistedValues = [...hoisted.values()].filter(val => !this.seenHoistedRequires.has(val));
1030
+ for (let val of hoistedValues) {
1031
+ this.seenHoistedRequires.add(val);
1032
+ }
1033
+ res += '\n' + hoistedValues.join('\n');
1034
+ lineCount += hoisted.size;
1035
+ } else {
1036
+ res += '\n' + [...hoisted.values()].join('\n');
1037
+ lineCount += hoisted.size;
1038
+ }
861
1039
  }
862
1040
  return [res, lineCount];
863
1041
  }
@@ -865,7 +1043,7 @@ ${code}
865
1043
  let prepend = '';
866
1044
  let prependLineCount = 0;
867
1045
  let append = '';
868
- let shouldWrap = this.wrappedAssets.has(asset.id);
1046
+ let shouldWrap = this.wrappedAssets.has(asset);
869
1047
  let usedSymbols = (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(asset));
870
1048
  let assetId = asset.meta.id;
871
1049
  (0, _assert().default)(typeof assetId === 'string');
@@ -874,20 +1052,28 @@ ${code}
874
1052
  // If there's no __esModule flag, and default is a used symbol, we need
875
1053
  // to insert an interop helper.
876
1054
  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();
1055
+ let usedNamespace;
1056
+ if ((0, _featureFlags().getFeatureFlag)('inlineConstOptimisationFix') && asset.meta.isConstantModule) {
1057
+ // Only set usedNamespace if there is an incoming dependency in the current bundle that uses '*'
1058
+ usedNamespace = this.bundleGraph.getIncomingDependencies(asset).some(dep => this.bundle.hasDependency(dep) && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep)).has('*'));
1059
+ } else {
1060
+ usedNamespace =
1061
+ // If the asset has * in its used symbols, we might need the exports namespace.
1062
+ // The one case where this isn't true is in ESM library entries, where the only
1063
+ // dependency on * is the entry dependency. In this case, we will use ESM exports
1064
+ // instead of the namespace object.
1065
+
1066
+ 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('*'))) ||
1067
+ // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
1068
+ // we fallback on the namespace object.
1069
+
1070
+ asset.symbols.hasExportSymbol('*') && [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s)) ||
1071
+ // If the exports has this asset's namespace (e.g. ESM output from CJS input),
1072
+ // include the namespace object for the default export.
1073
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
1074
+ // CommonJS library bundle entries always need a namespace.
1075
+ this.bundle.env.isLibrary && this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry();
1076
+ }
891
1077
 
892
1078
  // If the asset doesn't have static exports, should wrap, the namespace is used,
893
1079
  // or we need default interop, then we need to synthesize a namespace object for
@@ -905,6 +1091,7 @@ ${code}
905
1091
  // Insert the __esModule interop flag for this module if it has a `default` export
906
1092
  // and the namespace symbol is used.
907
1093
  // TODO: only if required by CJS?
1094
+
908
1095
  if (asset.symbols.hasExportSymbol('default') && usedSymbols.has('*')) {
909
1096
  prepend += `\n$parcel$defineInteropFlag($${assetId}$exports);\n`;
910
1097
  prependLineCount += 2;
@@ -988,16 +1175,22 @@ ${code}
988
1175
  // for the symbol so that when the value changes the object property also changes. This is
989
1176
  // required to simulate ESM live bindings. It's easier to do it this way rather than inserting
990
1177
  // additional assignments after each mutation of the original binding.
991
- prepend += `\n${usedExports.map(exp => {
992
- var _asset$symbols$get2;
1178
+ for (let exp of usedExports) {
1179
+ var _asset$symbols$get2, _this$manualStaticBin;
993
1180
  let resolved = this.getSymbolResolution(asset, asset, exp, undefined, replacements);
994
- let get = this.buildFunctionExpression([], resolved);
995
- let isEsmExport = !!((_asset$symbols$get2 = asset.symbols.get(exp)) !== null && _asset$symbols$get2 !== void 0 && (_asset$symbols$get2 = _asset$symbols$get2.meta) !== null && _asset$symbols$get2 !== void 0 && _asset$symbols$get2.isEsm);
996
- let set = !isEsmExport && asset.meta.hasCJSExports ? ', ' + this.buildFunctionExpression(['v'], `${resolved} = v`) : '';
997
- return `$parcel$export($${assetId}$exports, ${JSON.stringify(exp)}, ${get}${set});`;
998
- }).join('\n')}\n`;
999
- this.usedHelpers.add('$parcel$export');
1000
- prependLineCount += 1 + usedExports.length;
1181
+ const meta = (_asset$symbols$get2 = asset.symbols.get(exp)) === null || _asset$symbols$get2 === void 0 ? void 0 : _asset$symbols$get2.meta;
1182
+ if ((0, _featureFlags().getFeatureFlag)('exportsRebindingOptimisation') && (meta !== null && meta !== void 0 && meta.isStaticBindingSafe || (_this$manualStaticBin = this.manualStaticBindingExports) !== null && _this$manualStaticBin !== void 0 && _this$manualStaticBin.some(regex => regex.test(asset.filePath)))) {
1183
+ append += `$${assetId}$exports[${JSON.stringify(exp)}] = ${resolved};\n`;
1184
+ } else {
1185
+ var _asset$symbols$get3;
1186
+ let get = this.buildFunctionExpression([], resolved);
1187
+ let isEsmExport = !!((_asset$symbols$get3 = asset.symbols.get(exp)) !== null && _asset$symbols$get3 !== void 0 && (_asset$symbols$get3 = _asset$symbols$get3.meta) !== null && _asset$symbols$get3 !== void 0 && _asset$symbols$get3.isEsm);
1188
+ let set = !isEsmExport && asset.meta.hasCJSExports ? ', ' + this.buildFunctionExpression(['v'], `${resolved} = v`) : '';
1189
+ prepend += `$parcel$export($${assetId}$exports, ${JSON.stringify(exp)}, ${get}${set});\n`;
1190
+ this.usedHelpers.add('$parcel$export');
1191
+ prependLineCount += 1 + usedExports.length;
1192
+ }
1193
+ }
1001
1194
  }
1002
1195
  }
1003
1196
  return [prepend, prependLineCount, append];
@@ -1041,11 +1234,11 @@ ${code}
1041
1234
  // Add the prelude if this is potentially the first JS bundle to load in a
1042
1235
  // particular context (e.g. entry scripts in HTML, workers, etc.).
1043
1236
  let parentBundles = this.bundleGraph.getParentBundles(this.bundle);
1044
- let mightBeFirstJS = parentBundles.length === 0 || parentBundles.some(b => b.type !== 'js') || this.bundleGraph.getBundleGroupsContainingBundle(this.bundle).some(g => this.bundleGraph.isEntryBundleGroup(g)) || this.bundle.env.isIsolated() || this.bundle.bundleBehavior === 'isolated' ||
1237
+ let mightBeFirstJS = parentBundles.length === 0 || parentBundles.some(b => b.type !== 'js') || this.bundleGraph.getBundleGroupsContainingBundle(this.bundle).some(g => this.bundleGraph.isEntryBundleGroup(g)) || this.bundle.env.isIsolated() || this.bundle.bundleBehavior === 'isolated' || this.bundle.bundleBehavior === 'inlineIsolated' ||
1045
1238
  // Conditional deps may be loaded before entrypoints on the server
1046
1239
  this.hasConditionalDependency();
1047
1240
  if (mightBeFirstJS) {
1048
- let preludeCode = (0, _helpers.prelude)(this.parcelRequireName);
1241
+ let preludeCode = ((0, _featureFlags().getFeatureFlag)('useNewPrelude') ? _helpers.preludeNew : _helpers.preludeOld)(this.parcelRequireName);
1049
1242
  res += preludeCode;
1050
1243
  if (enableSourceMaps) {
1051
1244
  lines += (0, _utils().countLines)(preludeCode) - 1;
@@ -1068,7 +1261,7 @@ ${code}
1068
1261
  }
1069
1262
 
1070
1263
  // Add importScripts for sibling bundles in workers.
1071
- if (this.bundle.env.isWorker() || this.bundle.env.isWorklet()) {
1264
+ if (this.bundle.env.isWorker() || this.bundle.env.isTesseract() || this.bundle.env.isWorklet()) {
1072
1265
  let importScripts = '';
1073
1266
  let bundles = this.bundleGraph.getReferencedBundles(this.bundle);
1074
1267
  for (let b of bundles) {
@@ -1094,7 +1287,7 @@ ${code}
1094
1287
  if (this.isScriptEntry(asset)) {
1095
1288
  return true;
1096
1289
  }
1097
- return asset.sideEffects === false && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(asset)).size == 0 && !this.bundleGraph.isAssetReferenced(this.bundle, asset);
1290
+ return asset.sideEffects === false && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(asset)).size == 0 && !this.isAssetReferencedInBundle(this.bundle, asset);
1098
1291
  }
1099
1292
  isScriptEntry(asset) {
1100
1293
  return this.bundle.env.outputFormat === 'global' && this.bundle.env.sourceType === 'script' && asset === this.bundle.getMainEntry();