@atlaspack/runtime-js 2.14.5-canary.48 → 2.14.5-canary.481

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +580 -0
  2. package/dist/JSRuntime.js +963 -0
  3. package/lib/JSRuntime.js +425 -42
  4. package/lib/helpers/browser/analytics/analytics.d.js +1 -0
  5. package/lib/helpers/browser/css-loader.js +4 -3
  6. package/lib/helpers/browser/html-loader.js +1 -1
  7. package/lib/helpers/browser/import-polyfill.js +1 -1
  8. package/lib/helpers/browser/js-loader.js +4 -3
  9. package/lib/helpers/browser/prefetch-loader.js +1 -1
  10. package/lib/helpers/browser/preload-loader.js +1 -1
  11. package/lib/helpers/browser/sync-js-loader.js +32 -0
  12. package/lib/helpers/browser/wasm-loader.js +1 -1
  13. package/lib/helpers/bundle-manifest.js +1 -1
  14. package/lib/helpers/cacheLoader.js +1 -1
  15. package/lib/helpers/conditional-loader-dev.js +12 -3
  16. package/lib/helpers/conditional-loader.js +22 -2
  17. package/lib/helpers/get-worker-url.js +1 -1
  18. package/lib/helpers/node/css-loader.js +1 -1
  19. package/lib/helpers/node/html-loader.js +1 -1
  20. package/lib/helpers/node/js-loader.js +1 -1
  21. package/lib/helpers/node/wasm-loader.js +1 -1
  22. package/lib/helpers/worker/js-loader.js +1 -1
  23. package/lib/helpers/worker/wasm-loader.js +1 -1
  24. package/lib/types/JSRuntime.d.ts +9 -0
  25. package/package.json +15 -10
  26. package/src/{JSRuntime.js → JSRuntime.ts} +520 -113
  27. package/src/helpers/browser/preload-loader.js +1 -2
  28. package/src/helpers/browser/sync-js-loader.js +37 -0
  29. package/src/helpers/conditional-loader-dev.js +17 -3
  30. package/src/helpers/conditional-loader.js +24 -2
  31. package/test/analytics.test.ts +4 -1
  32. package/test/{bundle-url.test.js → bundle-url.test.ts} +1 -2
  33. package/test/esm-js-loader-retry.test.ts +4 -7
  34. package/tsconfig.json +27 -0
  35. package/tsconfig.tsbuildinfo +1 -0
  36. package/src/helpers/browser/analytics/analytics.js.flow +0 -10
@@ -1,4 +1,3 @@
1
- // @flow strict-local
2
1
  import type {
3
2
  BundleGraph,
4
3
  BundleGroup,
@@ -7,13 +6,13 @@ import type {
7
6
  PluginOptions,
8
7
  NamedBundle,
9
8
  RuntimeAsset,
10
- } from '@atlaspack/types';
9
+ } from '@atlaspack/types-internal';
11
10
 
12
11
  import {Runtime} from '@atlaspack/plugin';
13
12
  import {
14
13
  relativeBundlePath,
15
14
  validateSchema,
16
- type SchemaEntity,
15
+ SchemaEntity,
17
16
  } from '@atlaspack/utils';
18
17
  import {encodeJSONKeyComponent} from '@atlaspack/diagnostic';
19
18
  import path from 'path';
@@ -24,7 +23,7 @@ import {getFeatureFlag} from '@atlaspack/feature-flags';
24
23
  const TYPE_TO_RESOURCE_PRIORITY = {
25
24
  css: 'style',
26
25
  js: 'script',
27
- };
26
+ } as const;
28
27
 
29
28
  const BROWSER_PRELOAD_LOADER = './helpers/browser/preload-loader';
30
29
  const BROWSER_PREFETCH_LOADER = './helpers/browser/prefetch-loader';
@@ -49,13 +48,20 @@ const LOADERS = {
49
48
  wasm: './helpers/node/wasm-loader',
50
49
  IMPORT_POLYFILL: null,
51
50
  },
52
- };
51
+ } as const;
53
52
 
54
- function getLoaders(
55
- ctx: Environment,
56
- ): ?{[string]: string, IMPORT_POLYFILL: null | false | string, ...} {
57
- if (ctx.isWorker()) return LOADERS.worker;
53
+ function getLoaders(ctx: Environment):
54
+ | {
55
+ // @ts-expect-error TS2411
56
+ IMPORT_POLYFILL: null | false | string;
57
+ [key: string]: string;
58
+ }
59
+ | null
60
+ | undefined {
61
+ // @ts-expect-error TS2322
62
+ if (ctx.isWorker() || ctx.isTesseract()) return LOADERS.worker;
58
63
  if (ctx.isBrowser()) return LOADERS.browser;
64
+ // @ts-expect-error TS2322
59
65
  if (ctx.isNode()) return LOADERS.node;
60
66
  return null;
61
67
  }
@@ -64,19 +70,19 @@ function getLoaders(
64
70
  // This can happen when we reuse the BundleGraph between subsequent builds
65
71
  let bundleDependencies = new WeakMap<
66
72
  NamedBundle,
67
- {|
68
- asyncDependencies: Array<Dependency>,
69
- conditionalDependencies: Array<Dependency>,
70
- otherDependencies: Array<Dependency>,
71
- |},
73
+ {
74
+ asyncDependencies: Array<Dependency>;
75
+ conditionalDependencies: Array<Dependency>;
76
+ otherDependencies: Array<Dependency>;
77
+ }
72
78
  >();
73
79
 
74
- type JSRuntimeConfig = {|
75
- splitManifestThreshold: number,
76
- domainSharding?: {|
77
- maxShards: number,
78
- |},
79
- |};
80
+ type JSRuntimeConfig = {
81
+ splitManifestThreshold: number;
82
+ domainSharding?: {
83
+ maxShards: number;
84
+ };
85
+ };
80
86
 
81
87
  let defaultConfig: JSRuntimeConfig = {
82
88
  splitManifestThreshold: 100000,
@@ -102,7 +108,7 @@ const CONFIG_SCHEMA: SchemaEntity = {
102
108
  additionalProperties: false,
103
109
  };
104
110
 
105
- export default (new Runtime({
111
+ export default new Runtime({
106
112
  async loadConfig({config, options}): Promise<JSRuntimeConfig> {
107
113
  let packageKey = '@atlaspack/runtime-js';
108
114
  let conf = await config.getConfig<JSRuntimeConfig>([], {
@@ -144,7 +150,7 @@ export default (new Runtime({
144
150
  let {asyncDependencies, conditionalDependencies, otherDependencies} =
145
151
  getDependencies(bundle);
146
152
 
147
- let assets = [];
153
+ let assets: Array<RuntimeAsset> = [];
148
154
  for (let dependency of asyncDependencies) {
149
155
  let resolved = bundleGraph.resolveAsyncDependency(dependency, bundle);
150
156
  if (resolved == null) {
@@ -156,13 +162,25 @@ export default (new Runtime({
156
162
  // If this bundle already has the asset this dependency references,
157
163
  // return a simple runtime of `Promise.resolve(internalRequire(assetId))`.
158
164
  // The linker handles this for scope-hoisting.
165
+
166
+ const requireName = getFeatureFlag('hmrImprovements')
167
+ ? 'parcelRequire'
168
+ : 'module.bundle.root';
169
+
159
170
  assets.push({
160
171
  filePath: __filename,
161
- code: `module.exports = Promise.resolve(module.bundle.root(${JSON.stringify(
172
+ code: `module.exports = Promise.resolve(${requireName}(${JSON.stringify(
162
173
  bundleGraph.getAssetPublicId(resolved.value),
163
174
  )}))`,
164
175
  dependency,
165
176
  env: {sourceType: 'module'},
177
+ // Pre-computed symbols: exports Promise, no external dependencies (uses global)
178
+ symbolData: {
179
+ symbols: new Map([
180
+ ['default', {local: 'module.exports', loc: null}],
181
+ ]),
182
+ dependencies: [],
183
+ },
166
184
  });
167
185
  }
168
186
  } else {
@@ -172,7 +190,10 @@ export default (new Runtime({
172
190
  dependency,
173
191
  bundle,
174
192
  );
175
- if (referencedBundle?.bundleBehavior === 'inline') {
193
+ if (
194
+ referencedBundle?.bundleBehavior === 'inline' ||
195
+ referencedBundle?.bundleBehavior === 'inlineIsolated'
196
+ ) {
176
197
  assets.push({
177
198
  filePath: path.join(
178
199
  __dirname,
@@ -183,6 +204,13 @@ export default (new Runtime({
183
204
  )});`,
184
205
  dependency,
185
206
  env: {sourceType: 'module'},
207
+ // Pre-computed symbols: exports Promise, no external dependencies
208
+ symbolData: {
209
+ symbols: new Map([
210
+ ['default', {local: 'module.exports', loc: null}],
211
+ ]),
212
+ dependencies: [],
213
+ },
186
214
  });
187
215
  continue;
188
216
  }
@@ -211,24 +239,98 @@ export default (new Runtime({
211
239
  bundle,
212
240
  );
213
241
  for (const cond of conditions) {
214
- const requireName = bundle.env.shouldScopeHoist
215
- ? 'parcelRequire'
216
- : '__parcel__require__';
217
-
218
- const assetCode = `module.exports = require('../helpers/conditional-loader${
242
+ const requireName =
243
+ getFeatureFlag('hmrImprovements') || bundle.env.shouldScopeHoist
244
+ ? 'parcelRequire'
245
+ : '__parcel__require__';
246
+
247
+ // We have fallback behaviour that can be used in development mode, so we need to handle both types of packagers
248
+ const getFallbackArgs = (cond: {
249
+ ifTrueBundles: NamedBundle[];
250
+ ifFalseBundles: NamedBundle[];
251
+ }) => {
252
+ const fallbackUrls = () => {
253
+ return `urls: [${[...cond.ifTrueBundles, ...cond.ifFalseBundles]
254
+ .map((target) => {
255
+ let relativePathExpr = getRelativePathExpr(
256
+ bundle,
257
+ target,
258
+ options,
259
+ );
260
+ return getAbsoluteUrlExpr(
261
+ relativePathExpr,
262
+ bundle,
263
+ config.domainSharding,
264
+ );
265
+ })
266
+ .join(',')}]`;
267
+ };
268
+
269
+ const fallbackBundleIds = () => {
270
+ return `i: [${[...cond.ifTrueBundles, ...cond.ifFalseBundles]
271
+ .map((target) => `"${target.publicId}"`)
272
+ .join(',')}]`;
273
+ };
274
+
275
+ return `, {l: require('./helpers/browser/sync-js-loader'), ${
276
+ options.mode === 'development'
277
+ ? fallbackUrls()
278
+ : fallbackBundleIds()
279
+ }}`;
280
+ };
281
+
282
+ const shouldUseFallback =
283
+ options.mode === 'development'
284
+ ? getFeatureFlag('condbDevFallbackDev')
285
+ : getFeatureFlag('condbDevFallbackProd');
286
+
287
+ const loaderPath = `./helpers/conditional-loader${
219
288
  options.mode === 'development' ? '-dev' : ''
220
- }')('${cond.key}', function (){return ${requireName}('${
221
- cond.ifTrueAssetId
222
- }')}, function (){return ${requireName}('${cond.ifFalseAssetId}')})`;
289
+ }`;
290
+
291
+ const ifTrue = `function (){return ${requireName}('${cond.ifTrueAssetId}')}`;
292
+ const ifFalse = `function (){return ${requireName}('${cond.ifFalseAssetId}')}`;
293
+
294
+ const assetCode = `module.exports = require('${loaderPath}')('${
295
+ cond.key
296
+ }', ${ifTrue}, ${ifFalse}${
297
+ shouldUseFallback ? getFallbackArgs(cond) : ''
298
+ })`;
223
299
 
224
300
  assets.push({
225
- filePath: path.join(__dirname, `/conditions/${cond.publicId}.js`),
301
+ filePath: path.join(__dirname, `/conditions-${cond.publicId}.js`),
226
302
  code: assetCode,
227
303
  // This dependency is important, as it's the last symbol handled in scope hoisting.
228
304
  // That means that scope hoisting will use the module id for this asset to replace the symbol
229
305
  // (rather than the actual conditional deps)
230
306
  dependency: cond.ifFalseDependency,
231
307
  env: {sourceType: 'module'},
308
+ // Pre-computed symbols: conditional loader with potential sync-js-loader fallback
309
+ symbolData: {
310
+ symbols: new Map([
311
+ ['default', {local: 'module.exports', loc: null}],
312
+ ]),
313
+ dependencies: [
314
+ {
315
+ specifier: loaderPath,
316
+ symbols: new Map([
317
+ ['default', {local: 'default', loc: null, isWeak: false}],
318
+ ]),
319
+ usedSymbols: new Set(['default']),
320
+ },
321
+ ...(shouldUseFallback
322
+ ? [
323
+ {
324
+ specifier: './helpers/browser/sync-js-loader',
325
+ symbols: new Map([
326
+ ['default', {local: 'l', loc: null, isWeak: false}],
327
+ ]),
328
+ usedSymbols: new Set(['default']),
329
+ },
330
+ ]
331
+ : []),
332
+ ],
333
+ },
232
334
  });
233
335
  }
234
336
  }
@@ -240,12 +342,22 @@ export default (new Runtime({
240
342
  dependency,
241
343
  bundle,
242
344
  );
243
- if (referencedBundle?.bundleBehavior === 'inline') {
345
+ if (
346
+ referencedBundle?.bundleBehavior === 'inline' ||
347
+ referencedBundle?.bundleBehavior === 'inlineIsolated'
348
+ ) {
244
349
  assets.push({
245
350
  filePath: path.join(__dirname, `/bundles/${referencedBundle.id}.js`),
246
351
  code: `module.exports = ${JSON.stringify(dependency.id)};`,
247
352
  dependency,
248
353
  env: {sourceType: 'module'},
354
+ // Pre-computed symbols: simple export with no dependencies
355
+ symbolData: {
356
+ symbols: new Map([
357
+ ['default', {local: 'module.exports', loc: null}],
358
+ ]),
359
+ dependencies: [],
360
+ },
249
361
  });
250
362
  continue;
251
363
  }
@@ -261,6 +373,13 @@ export default (new Runtime({
261
373
  code: `module.exports = ${JSON.stringify(dependency.specifier)}`,
262
374
  dependency,
263
375
  env: {sourceType: 'module'},
376
+ // Pre-computed symbols: simple export with no dependencies
377
+ symbolData: {
378
+ symbols: new Map([
379
+ ['default', {local: 'module.exports', loc: null}],
380
+ ]),
381
+ dependencies: [],
382
+ },
264
383
  });
265
384
  continue;
266
385
  }
@@ -279,7 +398,11 @@ export default (new Runtime({
279
398
 
280
399
  // Skip URL runtimes for library builds. This is handled in packaging so that
281
400
  // the url is inlined and statically analyzable.
282
- if (bundle.env.isLibrary && mainBundle.bundleBehavior !== 'isolated') {
401
+ if (
402
+ bundle.env.isLibrary &&
403
+ mainBundle.bundleBehavior !== 'isolated' &&
404
+ mainBundle.bundleBehavior !== 'inlineIsolated'
405
+ ) {
283
406
  continue;
284
407
  }
285
408
 
@@ -328,6 +451,19 @@ export default (new Runtime({
328
451
  code: loaderCode,
329
452
  isEntry: true,
330
453
  env: {sourceType: 'module'},
454
+ // Pre-computed symbols: lazy bundle loader, requires specific loader helper
455
+ symbolData: {
456
+ symbols: new Map(), // No exports, just side effects
457
+ dependencies: [
458
+ {
459
+ specifier: loader,
460
+ symbols: new Map([
461
+ ['default', {local: 'default', loc: null, isWeak: false}],
462
+ ]),
463
+ usedSymbols: new Set(['default']),
464
+ },
465
+ ],
466
+ },
331
467
  });
332
468
  }
333
469
  }
@@ -336,7 +472,11 @@ export default (new Runtime({
336
472
  shouldUseRuntimeManifest(bundle, options) &&
337
473
  bundleGraph
338
474
  .getChildBundles(bundle)
339
- .some((b) => b.bundleBehavior !== 'inline') &&
475
+ .some(
476
+ (b) =>
477
+ b.bundleBehavior !== 'inline' &&
478
+ b.bundleBehavior !== 'inlineIsolated',
479
+ ) &&
340
480
  isNewContext(bundle, bundleGraph)
341
481
  ) {
342
482
  assets.push({
@@ -344,31 +484,45 @@ export default (new Runtime({
344
484
  code: getRegisterCode(bundle, bundleGraph),
345
485
  isEntry: true,
346
486
  env: {sourceType: 'module'},
487
+ runtimeAssetRequiringExecutionOnLoad: true,
347
488
  priority: getManifestBundlePriority(
348
489
  bundleGraph,
349
490
  bundle,
350
491
  config.splitManifestThreshold,
351
492
  ),
493
+ // Pre-computed symbols: requires bundle-manifest helper
494
+ symbolData: {
495
+ symbols: new Map(), // No exports, just executes
496
+ dependencies: [
497
+ {
498
+ specifier: './helpers/bundle-manifest',
499
+ symbols: new Map([
500
+ ['register', {local: 'register', loc: null, isWeak: false}],
501
+ ]),
502
+ usedSymbols: new Set(['register']),
503
+ },
504
+ ],
505
+ },
352
506
  });
353
507
  }
354
508
 
355
509
  return assets;
356
510
  },
357
- }): Runtime);
511
+ }) as Runtime<JSRuntimeConfig>;
358
512
 
359
- function getDependencies(bundle: NamedBundle): {|
360
- asyncDependencies: Array<Dependency>,
361
- conditionalDependencies: Array<Dependency>,
362
- otherDependencies: Array<Dependency>,
363
- |} {
513
+ function getDependencies(bundle: NamedBundle): {
514
+ asyncDependencies: Array<Dependency>;
515
+ conditionalDependencies: Array<Dependency>;
516
+ otherDependencies: Array<Dependency>;
517
+ } {
364
518
  let cachedDependencies = bundleDependencies.get(bundle);
365
519
 
366
520
  if (cachedDependencies) {
367
521
  return cachedDependencies;
368
522
  } else {
369
- let asyncDependencies = [];
370
- let otherDependencies = [];
371
- let conditionalDependencies = [];
523
+ let asyncDependencies: Array<Dependency> = [];
524
+ let otherDependencies: Array<Dependency> = [];
525
+ let conditionalDependencies: Array<Dependency> = [];
372
526
  bundle.traverse((node) => {
373
527
  if (node.type !== 'dependency') {
374
528
  return;
@@ -402,25 +556,35 @@ function getLoaderRuntime({
402
556
  bundleGraph,
403
557
  options,
404
558
  shardingConfig,
405
- }: {|
406
- bundle: NamedBundle,
407
- dependency: Dependency,
408
- bundleGroup: BundleGroup,
409
- bundleGraph: BundleGraph<NamedBundle>,
410
- options: PluginOptions,
411
- shardingConfig: JSRuntimeConfig['domainSharding'],
412
- |}): ?RuntimeAsset {
559
+ }: {
560
+ bundle: NamedBundle;
561
+ dependency: Dependency;
562
+ bundleGroup: BundleGroup;
563
+ bundleGraph: BundleGraph<NamedBundle>;
564
+ options: PluginOptions;
565
+ shardingConfig: JSRuntimeConfig['domainSharding'];
566
+ }): RuntimeAsset | null | undefined {
413
567
  let loaders = getLoaders(bundle.env);
414
568
  if (loaders == null) {
415
569
  return;
416
570
  }
417
571
 
418
572
  let externalBundles = bundleGraph.getBundlesInBundleGroup(bundleGroup);
419
- let mainBundle = nullthrows(
420
- externalBundles.find(
573
+ let potentialMainBundle;
574
+
575
+ if (getFeatureFlag('supportWebpackChunkName')) {
576
+ potentialMainBundle = externalBundles.find((bundle) =>
577
+ bundle
578
+ .getEntryAssets()
579
+ .some((asset) => asset.id === bundleGroup.entryAssetId),
580
+ );
581
+ } else {
582
+ potentialMainBundle = externalBundles.find(
421
583
  (bundle) => bundle.getMainEntry()?.id === bundleGroup.entryAssetId,
422
- ),
423
- );
584
+ );
585
+ }
586
+
587
+ let mainBundle = nullthrows(potentialMainBundle);
424
588
 
425
589
  // CommonJS is a synchronous module system, so there is no need to load bundles in parallel.
426
590
  // Importing of the other bundles will be handled by the bundle group entry.
@@ -451,7 +615,8 @@ function getLoaderRuntime({
451
615
  bundle: NamedBundle,
452
616
  to: NamedBundle,
453
617
  shardingConfig: JSRuntimeConfig['domainSharding'],
454
- ): string | void {
618
+ ): string | undefined {
619
+ // @ts-expect-error TS18049
455
620
  let loader = loaders[to.type];
456
621
  if (!loader) {
457
622
  return;
@@ -475,7 +640,9 @@ function getLoaderRuntime({
475
640
  return `__parcel__import__("./" + ${relativePathExpr})`;
476
641
  }
477
642
 
643
+ // @ts-expect-error TS2322
478
644
  loader = nullthrows(
645
+ // @ts-expect-error TS18049
479
646
  loaders.IMPORT_POLYFILL,
480
647
  `No import() polyfill available for context '${bundle.env.context}'`,
481
648
  );
@@ -528,7 +695,7 @@ function getLoaderRuntime({
528
695
  sourceBundle,
529
696
  );
530
697
 
531
- const loaders = [];
698
+ const loaders: Array<string> = [];
532
699
  for (const cond of conditions) {
533
700
  // This bundle has a conditional dependency, we need to load the bundle group
534
701
  const ifTrueLoaders = cond.ifTrueBundles
@@ -539,7 +706,9 @@ function getLoaderRuntime({
539
706
  ),
540
707
  )
541
708
  .concat(
709
+ // @ts-expect-error TS2769
542
710
  cond.ifTrueBundles.map((targetBundle) =>
711
+ // @ts-expect-error TS2554
543
712
  getLoaderForBundle(sourceBundle, targetBundle),
544
713
  ),
545
714
  );
@@ -552,7 +721,9 @@ function getLoaderRuntime({
552
721
  ),
553
722
  )
554
723
  .concat(
724
+ // @ts-expect-error TS2769
555
725
  cond.ifFalseBundles.map((targetBundle) =>
726
+ // @ts-expect-error TS2554
556
727
  getLoaderForBundle(sourceBundle, targetBundle),
557
728
  ),
558
729
  );
@@ -577,46 +748,13 @@ function getLoaderRuntime({
577
748
  }
578
749
 
579
750
  if (getFeatureFlag('conditionalBundlingApi')) {
580
- if (getFeatureFlag('conditionalBundlingNestedRuntime')) {
581
- let conditionalDependencies = externalBundles.flatMap(
582
- (to) => getDependencies(to).conditionalDependencies,
583
- );
584
-
585
- loaderModules.push(
586
- ...getConditionalLoadersForCondition(conditionalDependencies, bundle),
587
- );
588
- } else {
589
- let conditionalDependencies = externalBundles.flatMap(
590
- (to) => getDependencies(to).conditionalDependencies,
591
- );
592
- for (const cond of bundleGraph.getConditionsForDependencies(
593
- conditionalDependencies,
594
- bundle,
595
- )) {
596
- // This bundle has a conditional dependency, we need to load the bundle group
597
- const ifTrueLoaders = cond.ifTrueBundles.map((targetBundle) =>
598
- getLoaderForBundle(bundle, targetBundle),
599
- );
600
- const ifFalseLoaders = cond.ifFalseBundles.map((targetBundle) =>
601
- getLoaderForBundle(bundle, targetBundle),
602
- );
751
+ let conditionalDependencies = externalBundles.flatMap(
752
+ (to) => getDependencies(to).conditionalDependencies,
753
+ );
603
754
 
604
- if (ifTrueLoaders.length > 0 || ifFalseLoaders.length > 0) {
605
- // Load conditional bundles with helper (and a dev mode with additional hints)
606
- loaderModules.push(
607
- `require('./helpers/conditional-loader${
608
- options.mode === 'development' ? '-dev' : ''
609
- }')('${
610
- cond.key
611
- }', function (){return Promise.all([${ifTrueLoaders.join(
612
- ',',
613
- )}]);}, function (){return Promise.all([${ifFalseLoaders.join(
614
- ',',
615
- )}]);})`,
616
- );
617
- }
618
- }
619
- }
755
+ loaderModules.push(
756
+ ...getConditionalLoadersForCondition(conditionalDependencies, bundle),
757
+ );
620
758
  }
621
759
 
622
760
  for (let to of externalBundles) {
@@ -666,9 +804,11 @@ function getLoaderRuntime({
666
804
  }
667
805
 
668
806
  if (mainBundle.type === 'js') {
669
- let parcelRequire = bundle.env.shouldScopeHoist
670
- ? 'parcelRequire'
671
- : 'module.bundle.root';
807
+ let parcelRequire =
808
+ getFeatureFlag('hmrImprovements') || bundle.env.shouldScopeHoist
809
+ ? 'parcelRequire'
810
+ : 'module.bundle.root';
811
+
672
812
  loaderCode += `.then(() => ${parcelRequire}('${bundleGraph.getAssetPublicId(
673
813
  bundleGraph.getAssetById(bundleGroup.entryAssetId),
674
814
  )}'))`;
@@ -689,10 +829,23 @@ function getLoaderRuntime({
689
829
  code: loaderCode,
690
830
  dependency,
691
831
  env: {sourceType: 'module'},
832
+ // Pre-computed symbols: ESM loader with retry, requires esm-js-loader-retry helper
833
+ symbolData: {
834
+ symbols: new Map([['default', {local: 'module.exports', loc: null}]]),
835
+ dependencies: [
836
+ {
837
+ specifier: './helpers/browser/esm-js-loader-retry',
838
+ symbols: new Map([
839
+ ['default', {local: 'default', loc: null, isWeak: false}],
840
+ ]),
841
+ usedSymbols: new Set(['default']),
842
+ },
843
+ ],
844
+ },
692
845
  };
693
846
  }
694
847
 
695
- let code = [];
848
+ let code: Array<string> = [];
696
849
 
697
850
  if (needsEsmLoadPrelude) {
698
851
  let preludeLoad = shardingConfig
@@ -704,35 +857,174 @@ function getLoaderRuntime({
704
857
 
705
858
  code.push(`module.exports = ${loaderCode};`);
706
859
 
860
+ // Collect all potential helper dependencies used in loader runtime
861
+ let helperDependencies: Array<{
862
+ specifier: string;
863
+ symbols: Map<string, {local: string; loc: null; isWeak: boolean}>;
864
+ usedSymbols: Set<string>;
865
+ }> = [];
866
+
867
+ // Always potential dependencies based on the code patterns
868
+ if (needsEsmLoadPrelude) {
869
+ if (shardingConfig) {
870
+ helperDependencies.push({
871
+ specifier: './helpers/browser/esm-js-loader-shards',
872
+ symbols: new Map([
873
+ ['default', {local: 'default', loc: null, isWeak: false}],
874
+ ]),
875
+ usedSymbols: new Set(['default']),
876
+ });
877
+ } else {
878
+ helperDependencies.push({
879
+ specifier: './helpers/browser/esm-js-loader',
880
+ symbols: new Map([
881
+ ['default', {local: 'default', loc: null, isWeak: false}],
882
+ ]),
883
+ usedSymbols: new Set(['default']),
884
+ });
885
+ }
886
+ }
887
+
888
+ // Bundle manifest dependency if using runtime manifest
889
+ if (shouldUseRuntimeManifest(bundle, options)) {
890
+ helperDependencies.push({
891
+ specifier: './helpers/bundle-manifest',
892
+ symbols: new Map([
893
+ ['resolve', {local: 'resolve', loc: null, isWeak: false}],
894
+ ]),
895
+ usedSymbols: new Set(['resolve']),
896
+ });
897
+ }
898
+
899
+ // Domain sharding dependency if configured
900
+ if (shardingConfig) {
901
+ helperDependencies.push({
902
+ specifier: '@atlaspack/domain-sharding',
903
+ symbols: new Map([
904
+ ['shardUrl', {local: 'shardUrl', loc: null, isWeak: false}],
905
+ ]),
906
+ usedSymbols: new Set(['shardUrl']),
907
+ });
908
+ }
909
+
910
+ // Various loader dependencies based on bundle types in externalBundles
911
+ for (let to of externalBundles) {
912
+ let loader = loaders[to.type];
913
+ if (loader && typeof loader === 'string') {
914
+ helperDependencies.push({
915
+ specifier: loader,
916
+ symbols: new Map([
917
+ ['default', {local: 'default', loc: null, isWeak: false}],
918
+ ]),
919
+ usedSymbols: new Set(['default']),
920
+ });
921
+ }
922
+ }
923
+
924
+ // Import polyfill if needed
925
+ if (needsDynamicImportPolyfill && loaders?.IMPORT_POLYFILL) {
926
+ helperDependencies.push({
927
+ specifier: loaders.IMPORT_POLYFILL,
928
+ symbols: new Map([
929
+ ['default', {local: 'default', loc: null, isWeak: false}],
930
+ ]),
931
+ usedSymbols: new Set(['default']),
932
+ });
933
+ }
934
+
935
+ // Conditional loaders if using conditional bundling
936
+ if (getFeatureFlag('conditionalBundlingApi')) {
937
+ const loaderPath = `./helpers/conditional-loader${
938
+ options.mode === 'development' ? '-dev' : ''
939
+ }`;
940
+ helperDependencies.push({
941
+ specifier: loaderPath,
942
+ symbols: new Map([
943
+ ['default', {local: 'default', loc: null, isWeak: false}],
944
+ ]),
945
+ usedSymbols: new Set(['default']),
946
+ });
947
+
948
+ // Sync loader for fallback
949
+ if (options.mode === 'development') {
950
+ helperDependencies.push({
951
+ specifier: './helpers/browser/sync-js-loader',
952
+ symbols: new Map([
953
+ ['default', {local: 'default', loc: null, isWeak: false}],
954
+ ]),
955
+ usedSymbols: new Set(['default']),
956
+ });
957
+ }
958
+ }
959
+
960
+ // Preload/prefetch loaders for browser context
961
+ if (bundle.env.context === 'browser') {
962
+ helperDependencies.push({
963
+ specifier: BROWSER_PRELOAD_LOADER,
964
+ symbols: new Map([
965
+ ['default', {local: 'default', loc: null, isWeak: false}],
966
+ ]),
967
+ usedSymbols: new Set(['default']),
968
+ });
969
+ helperDependencies.push({
970
+ specifier: BROWSER_PREFETCH_LOADER,
971
+ symbols: new Map([
972
+ ['default', {local: 'default', loc: null, isWeak: false}],
973
+ ]),
974
+ usedSymbols: new Set(['default']),
975
+ });
976
+ }
977
+
978
+ // ESM loader retry if using import retry feature
979
+ if (needsEsmLoadPrelude && options.featureFlags.importRetry) {
980
+ helperDependencies.push({
981
+ specifier: './helpers/browser/esm-js-loader-retry',
982
+ symbols: new Map([
983
+ ['default', {local: 'default', loc: null, isWeak: false}],
984
+ ]),
985
+ usedSymbols: new Set(['default']),
986
+ });
987
+ }
988
+
707
989
  return {
708
990
  filePath: __filename,
709
991
  code: code.join('\n'),
710
992
  dependency,
711
993
  env: {sourceType: 'module'},
994
+ // Pre-computed symbols: loader runtime with comprehensive helper dependencies
995
+ symbolData: {
996
+ symbols: new Map([['default', {local: 'module.exports', loc: null}]]),
997
+ dependencies: helperDependencies,
998
+ },
712
999
  };
713
1000
  }
714
1001
 
715
1002
  function getHintedBundleGroups(
716
1003
  bundleGraph: BundleGraph<NamedBundle>,
717
1004
  bundle: NamedBundle,
718
- ): {|preload: Array<BundleGroup>, prefetch: Array<BundleGroup>|} {
719
- let preload = [];
720
- let prefetch = [];
1005
+ ): {
1006
+ preload: Array<BundleGroup>;
1007
+ prefetch: Array<BundleGroup>;
1008
+ } {
1009
+ let preload: Array<BundleGroup> = [];
1010
+ let prefetch: Array<BundleGroup> = [];
721
1011
  let {asyncDependencies} = getDependencies(bundle);
722
1012
  for (let dependency of asyncDependencies) {
723
1013
  let attributes = dependency.meta?.importAttributes;
724
1014
  if (
725
1015
  typeof attributes === 'object' &&
726
1016
  attributes != null &&
727
- // $FlowFixMe
1017
+ // @ts-expect-error TS2339
728
1018
  (attributes.preload || attributes.prefetch)
729
1019
  ) {
730
1020
  let resolved = bundleGraph.resolveAsyncDependency(dependency, bundle);
731
1021
  if (resolved?.type === 'bundle_group') {
732
1022
  // === true for flow
1023
+ // @ts-expect-error TS2339
733
1024
  if (attributes.preload === true) {
734
1025
  preload.push(resolved.value);
735
1026
  }
1027
+ // @ts-expect-error TS2339
736
1028
  if (attributes.prefetch === true) {
737
1029
  prefetch.push(resolved.value);
738
1030
  }
@@ -750,7 +1042,7 @@ function getHintLoaders(
750
1042
  loader: string,
751
1043
  options: PluginOptions,
752
1044
  ): Array<string> {
753
- let hintLoaders = [];
1045
+ let hintLoaders: Array<string> = [];
754
1046
  for (let bundleGroupToPreload of bundleGroups) {
755
1047
  let bundlesToPreload =
756
1048
  bundleGraph.getBundlesInBundleGroup(bundleGroupToPreload);
@@ -761,8 +1053,10 @@ function getHintLoaders(
761
1053
  bundleToPreload,
762
1054
  options,
763
1055
  );
1056
+ // @ts-expect-error TS7053
764
1057
  let priority = TYPE_TO_RESOURCE_PRIORITY[bundleToPreload.type];
765
1058
  hintLoaders.push(
1059
+ // @ts-expect-error TS2554
766
1060
  `require(${JSON.stringify(loader)})(${getAbsoluteUrlExpr(
767
1061
  relativePathExpr,
768
1062
  from,
@@ -801,7 +1095,12 @@ function getURLRuntime(
801
1095
  options: PluginOptions,
802
1096
  shardingConfig: JSRuntimeConfig['domainSharding'],
803
1097
  ): RuntimeAsset {
804
- let relativePathExpr = getRelativePathExpr(from, to, options);
1098
+ let relativePathExpr;
1099
+ if (getFeatureFlag('hmrImprovements')) {
1100
+ relativePathExpr = getRelativePathExpr(from, to, options, true);
1101
+ } else {
1102
+ relativePathExpr = getRelativePathExpr(from, to, options);
1103
+ }
805
1104
  let code;
806
1105
 
807
1106
  if (dependency.meta.webworker === true && !from.env.isLibrary) {
@@ -832,11 +1131,89 @@ function getURLRuntime(
832
1131
  )};`;
833
1132
  }
834
1133
 
1134
+ // Collect dependencies based on the URL runtime code patterns
1135
+ let urlRuntimeDependencies: Array<{
1136
+ specifier: string;
1137
+ symbols: Map<string, {local: string; loc: null; isWeak: boolean}>;
1138
+ usedSymbols: Set<string>;
1139
+ }> = [];
1140
+
1141
+ if (dependency.meta.webworker === true && !from.env.isLibrary) {
1142
+ // Web worker runtime requires get-worker-url helper
1143
+ urlRuntimeDependencies.push({
1144
+ specifier: './helpers/get-worker-url',
1145
+ symbols: new Map([
1146
+ ['default', {local: 'workerURL', loc: null, isWeak: false}],
1147
+ ]),
1148
+ usedSymbols: new Set(['default']),
1149
+ });
1150
+
1151
+ if (
1152
+ !(
1153
+ from.env.outputFormat === 'esmodule' &&
1154
+ from.env.supports('import-meta-url')
1155
+ )
1156
+ ) {
1157
+ // Also requires bundle-url helper in non-ESM environments
1158
+ urlRuntimeDependencies.push({
1159
+ specifier: './helpers/bundle-url',
1160
+ symbols: new Map([
1161
+ ['getBundleURL', {local: 'getBundleURL', loc: null, isWeak: false}],
1162
+ ['getOrigin', {local: 'getOrigin', loc: null, isWeak: false}],
1163
+ ]),
1164
+ usedSymbols: new Set(['getBundleURL', 'getOrigin']),
1165
+ });
1166
+
1167
+ // Domain sharding if configured
1168
+ if (shardingConfig) {
1169
+ urlRuntimeDependencies.push({
1170
+ specifier: '@atlaspack/domain-sharding',
1171
+ symbols: new Map([
1172
+ ['shardUrl', {local: 'shardUrl', loc: null, isWeak: false}],
1173
+ ]),
1174
+ usedSymbols: new Set(['shardUrl']),
1175
+ });
1176
+ }
1177
+ }
1178
+ } else {
1179
+ // Regular URL runtime may use bundle-url helper
1180
+ if (
1181
+ !(
1182
+ from.env.outputFormat === 'esmodule' &&
1183
+ from.env.supports('import-meta-url')
1184
+ ) &&
1185
+ !(from.env.outputFormat === 'commonjs')
1186
+ ) {
1187
+ urlRuntimeDependencies.push({
1188
+ specifier: './helpers/bundle-url',
1189
+ symbols: new Map([
1190
+ ['getBundleURL', {local: 'getBundleURL', loc: null, isWeak: false}],
1191
+ ]),
1192
+ usedSymbols: new Set(['getBundleURL']),
1193
+ });
1194
+
1195
+ if (shardingConfig) {
1196
+ urlRuntimeDependencies.push({
1197
+ specifier: '@atlaspack/domain-sharding',
1198
+ symbols: new Map([
1199
+ ['shardUrl', {local: 'shardUrl', loc: null, isWeak: false}],
1200
+ ]),
1201
+ usedSymbols: new Set(['shardUrl']),
1202
+ });
1203
+ }
1204
+ }
1205
+ }
1206
+
835
1207
  return {
836
1208
  filePath: __filename,
837
1209
  code,
838
1210
  dependency,
839
1211
  env: {sourceType: 'module'},
1212
+ // Pre-computed symbols: URL runtime with helper dependencies
1213
+ symbolData: {
1214
+ symbols: new Map([['default', {local: 'module.exports', loc: null}]]),
1215
+ dependencies: urlRuntimeDependencies,
1216
+ },
840
1217
  };
841
1218
  }
842
1219
 
@@ -844,9 +1221,13 @@ function getRegisterCode(
844
1221
  entryBundle: NamedBundle,
845
1222
  bundleGraph: BundleGraph<NamedBundle>,
846
1223
  ): string {
847
- let mappings = [];
1224
+ // @ts-expect-error TS2304
1225
+ let mappings: Array<FilePath | string> = [];
848
1226
  bundleGraph.traverseBundles((bundle, _, actions) => {
849
- if (bundle.bundleBehavior === 'inline') {
1227
+ if (
1228
+ bundle.bundleBehavior === 'inline' ||
1229
+ bundle.bundleBehavior === 'inlineIsolated'
1230
+ ) {
850
1231
  return;
851
1232
  }
852
1233
 
@@ -889,11 +1270,36 @@ function getRelativePathExpr(
889
1270
  from: NamedBundle,
890
1271
  to: NamedBundle,
891
1272
  options: PluginOptions,
1273
+ isURL = to.type !== 'js',
892
1274
  ): string {
893
1275
  let relativePath = relativeBundlePath(from, to, {leadingDotSlash: false});
894
1276
  let res = JSON.stringify(relativePath);
895
- if (options.hmrOptions) {
896
- res += ' + "?" + Date.now()';
1277
+ if (getFeatureFlag('hmrImprovements')) {
1278
+ if (isURL && options.hmrOptions) {
1279
+ if (getFeatureFlag('hmrBundleVersioning')) {
1280
+ res +=
1281
+ ' + (globalThis.__parcel__hmrBundleVersion == null' +
1282
+ ' ? ""' +
1283
+ ' : (' +
1284
+ JSON.stringify(relativePath) +
1285
+ '.includes("?") ? "&" : "?") + "t=" + globalThis.__parcel__hmrBundleVersion)';
1286
+ } else {
1287
+ res += ' + "?" + Date.now()';
1288
+ }
1289
+ }
1290
+ } else {
1291
+ if (options.hmrOptions) {
1292
+ if (getFeatureFlag('hmrBundleVersioning')) {
1293
+ res +=
1294
+ ' + (globalThis.__parcel__hmrBundleVersion == null' +
1295
+ ' ? ""' +
1296
+ ' : (' +
1297
+ JSON.stringify(relativePath) +
1298
+ '.includes("?") ? "&" : "?") + "t=" + globalThis.__parcel__hmrBundleVersion)';
1299
+ } else {
1300
+ res += ' + "?" + Date.now()';
1301
+ }
1302
+ }
897
1303
  }
898
1304
 
899
1305
  return res;
@@ -930,6 +1336,7 @@ function shouldUseRuntimeManifest(
930
1336
  return (
931
1337
  !env.isLibrary &&
932
1338
  bundle.bundleBehavior !== 'inline' &&
1339
+ bundle.bundleBehavior !== 'inlineIsolated' &&
933
1340
  env.isBrowser() &&
934
1341
  options.mode === 'production'
935
1342
  );
@@ -939,7 +1346,7 @@ function getManifestBundlePriority(
939
1346
  bundleGraph: BundleGraph<NamedBundle>,
940
1347
  bundle: NamedBundle,
941
1348
  threshold: number,
942
- ): $PropertyType<RuntimeAsset, 'priority'> {
1349
+ ): RuntimeAsset['priority'] {
943
1350
  let bundleSize = 0;
944
1351
 
945
1352
  bundle.traverseAssets((asset, _, actions) => {