@atlaspack/runtime-js 2.14.5-canary.49 → 2.14.5-canary.491

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 +589 -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
@@ -0,0 +1,963 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const plugin_1 = require("@atlaspack/plugin");
7
+ const utils_1 = require("@atlaspack/utils");
8
+ const diagnostic_1 = require("@atlaspack/diagnostic");
9
+ const path_1 = __importDefault(require("path"));
10
+ const nullthrows_1 = __importDefault(require("nullthrows"));
11
+ const feature_flags_1 = require("@atlaspack/feature-flags");
12
+ // Used for as="" in preload/prefetch
13
+ const TYPE_TO_RESOURCE_PRIORITY = {
14
+ css: 'style',
15
+ js: 'script',
16
+ };
17
+ const BROWSER_PRELOAD_LOADER = './helpers/browser/preload-loader';
18
+ const BROWSER_PREFETCH_LOADER = './helpers/browser/prefetch-loader';
19
+ const LOADERS = {
20
+ browser: {
21
+ css: './helpers/browser/css-loader',
22
+ html: './helpers/browser/html-loader',
23
+ js: './helpers/browser/js-loader',
24
+ wasm: './helpers/browser/wasm-loader',
25
+ IMPORT_POLYFILL: './helpers/browser/import-polyfill',
26
+ },
27
+ worker: {
28
+ js: './helpers/worker/js-loader',
29
+ wasm: './helpers/worker/wasm-loader',
30
+ IMPORT_POLYFILL: false,
31
+ },
32
+ node: {
33
+ css: './helpers/node/css-loader',
34
+ html: './helpers/node/html-loader',
35
+ js: './helpers/node/js-loader',
36
+ wasm: './helpers/node/wasm-loader',
37
+ IMPORT_POLYFILL: null,
38
+ },
39
+ };
40
+ function getLoaders(ctx) {
41
+ // @ts-expect-error TS2322
42
+ if (ctx.isWorker() || ctx.isTesseract())
43
+ return LOADERS.worker;
44
+ if (ctx.isBrowser())
45
+ return LOADERS.browser;
46
+ // @ts-expect-error TS2322
47
+ if (ctx.isNode())
48
+ return LOADERS.node;
49
+ return null;
50
+ }
51
+ // This cache should be invalidated if new dependencies get added to the bundle without the bundle objects changing
52
+ // This can happen when we reuse the BundleGraph between subsequent builds
53
+ let bundleDependencies = new WeakMap();
54
+ let defaultConfig = {
55
+ splitManifestThreshold: 100000,
56
+ };
57
+ const CONFIG_SCHEMA = {
58
+ type: 'object',
59
+ properties: {
60
+ splitManifestThreshold: {
61
+ type: 'number',
62
+ },
63
+ domainSharding: {
64
+ type: 'object',
65
+ properties: {
66
+ maxShards: {
67
+ type: 'number',
68
+ },
69
+ },
70
+ additionalProperties: false,
71
+ required: ['maxShards'],
72
+ },
73
+ },
74
+ additionalProperties: false,
75
+ };
76
+ exports.default = new plugin_1.Runtime({
77
+ async loadConfig({ config, options }) {
78
+ let packageKey = '@atlaspack/runtime-js';
79
+ let conf = await config.getConfig([], {
80
+ packageKey,
81
+ });
82
+ if (!conf) {
83
+ return defaultConfig;
84
+ }
85
+ utils_1.validateSchema.diagnostic(CONFIG_SCHEMA, {
86
+ data: conf?.contents,
87
+ source: await options.inputFS.readFile(conf.filePath, 'utf8'),
88
+ filePath: conf.filePath,
89
+ prependKey: `/${(0, diagnostic_1.encodeJSONKeyComponent)(packageKey)}`,
90
+ }, packageKey, `Invalid config for ${packageKey}`);
91
+ return {
92
+ ...defaultConfig,
93
+ ...conf?.contents,
94
+ };
95
+ },
96
+ apply({ bundle, bundleGraph, options, config }) {
97
+ // Dependency ids in code replaced with referenced bundle names
98
+ // Loader runtime added for bundle groups that don't have a native loader (e.g. HTML/CSS/Worker - isURL?),
99
+ // and which are not loaded by a parent bundle.
100
+ // Loaders also added for modules that were moved to a separate bundle because they are a different type
101
+ // (e.g. WASM, HTML). These should be preloaded prior to the bundle being executed. Replace the entry asset(s)
102
+ // with the preload module.
103
+ if (bundle.type !== 'js') {
104
+ return;
105
+ }
106
+ let { asyncDependencies, conditionalDependencies, otherDependencies } = getDependencies(bundle);
107
+ let assets = [];
108
+ for (let dependency of asyncDependencies) {
109
+ let resolved = bundleGraph.resolveAsyncDependency(dependency, bundle);
110
+ if (resolved == null) {
111
+ continue;
112
+ }
113
+ if (resolved.type === 'asset') {
114
+ if (!bundle.env.shouldScopeHoist) {
115
+ // If this bundle already has the asset this dependency references,
116
+ // return a simple runtime of `Promise.resolve(internalRequire(assetId))`.
117
+ // The linker handles this for scope-hoisting.
118
+ const requireName = (0, feature_flags_1.getFeatureFlag)('hmrImprovements')
119
+ ? 'parcelRequire'
120
+ : 'module.bundle.root';
121
+ assets.push({
122
+ filePath: __filename,
123
+ code: `module.exports = Promise.resolve(${requireName}(${JSON.stringify(bundleGraph.getAssetPublicId(resolved.value))}))`,
124
+ dependency,
125
+ env: { sourceType: 'module' },
126
+ // Pre-computed symbols: exports Promise, no external dependencies (uses global)
127
+ symbolData: {
128
+ symbols: new Map([
129
+ ['default', { local: 'module.exports', loc: null }],
130
+ ]),
131
+ dependencies: [],
132
+ },
133
+ });
134
+ }
135
+ }
136
+ else {
137
+ // Resolve the dependency to a bundle. If inline, export the dependency id,
138
+ // which will be replaced with the contents of that bundle later.
139
+ let referencedBundle = bundleGraph.getReferencedBundle(dependency, bundle);
140
+ if (referencedBundle?.bundleBehavior === 'inline' ||
141
+ referencedBundle?.bundleBehavior === 'inlineIsolated') {
142
+ assets.push({
143
+ filePath: path_1.default.join(__dirname, `/bundles/${referencedBundle.id}.js`),
144
+ code: `module.exports = Promise.resolve(${JSON.stringify(dependency.id)});`,
145
+ dependency,
146
+ env: { sourceType: 'module' },
147
+ // Pre-computed symbols: exports Promise, no external dependencies
148
+ symbolData: {
149
+ symbols: new Map([
150
+ ['default', { local: 'module.exports', loc: null }],
151
+ ]),
152
+ dependencies: [],
153
+ },
154
+ });
155
+ continue;
156
+ }
157
+ let loaderRuntime = getLoaderRuntime({
158
+ bundle,
159
+ dependency,
160
+ bundleGraph,
161
+ bundleGroup: resolved.value,
162
+ options,
163
+ shardingConfig: config.domainSharding,
164
+ });
165
+ if (loaderRuntime != null) {
166
+ assets.push(loaderRuntime);
167
+ }
168
+ }
169
+ }
170
+ if ((0, feature_flags_1.getFeatureFlag)('conditionalBundlingApi')) {
171
+ // For any conditions that are used in this bundle, we want to produce a runtime asset that is used to
172
+ // select the correct dependency that condition maps to at runtime - the conditions in the bundle will then be
173
+ // replaced with a reference to this asset to implement the selection.
174
+ const conditions = bundleGraph.getConditionsForDependencies(conditionalDependencies, bundle);
175
+ for (const cond of conditions) {
176
+ const requireName = (0, feature_flags_1.getFeatureFlag)('hmrImprovements') || bundle.env.shouldScopeHoist
177
+ ? 'parcelRequire'
178
+ : '__parcel__require__';
179
+ // We have fallback behaviour that can be used in development mode, so we need to handle both types of packagers
180
+ const getFallbackArgs = (cond) => {
181
+ const fallbackUrls = () => {
182
+ return `urls: [${[...cond.ifTrueBundles, ...cond.ifFalseBundles]
183
+ .map((target) => {
184
+ let relativePathExpr = getRelativePathExpr(bundle, target, options);
185
+ return getAbsoluteUrlExpr(relativePathExpr, bundle, config.domainSharding);
186
+ })
187
+ .join(',')}]`;
188
+ };
189
+ const fallbackBundleIds = () => {
190
+ return `i: [${[...cond.ifTrueBundles, ...cond.ifFalseBundles]
191
+ .map((target) => `"${target.publicId}"`)
192
+ .join(',')}]`;
193
+ };
194
+ return `, {l: require('./helpers/browser/sync-js-loader'), ${options.mode === 'development'
195
+ ? fallbackUrls()
196
+ : fallbackBundleIds()}}`;
197
+ };
198
+ const shouldUseFallback = options.mode === 'development'
199
+ ? (0, feature_flags_1.getFeatureFlag)('condbDevFallbackDev')
200
+ : (0, feature_flags_1.getFeatureFlag)('condbDevFallbackProd');
201
+ const loaderPath = `./helpers/conditional-loader${options.mode === 'development' ? '-dev' : ''}`;
202
+ const ifTrue = `function (){return ${requireName}('${cond.ifTrueAssetId}')}`;
203
+ const ifFalse = `function (){return ${requireName}('${cond.ifFalseAssetId}')}`;
204
+ const assetCode = `module.exports = require('${loaderPath}')('${cond.key}', ${ifTrue}, ${ifFalse}${shouldUseFallback ? getFallbackArgs(cond) : ''})`;
205
+ assets.push({
206
+ filePath: path_1.default.join(__dirname, `/conditions-${cond.publicId}.js`),
207
+ code: assetCode,
208
+ // This dependency is important, as it's the last symbol handled in scope hoisting.
209
+ // That means that scope hoisting will use the module id for this asset to replace the symbol
210
+ // (rather than the actual conditional deps)
211
+ dependency: cond.ifFalseDependency,
212
+ env: { sourceType: 'module' },
213
+ // Pre-computed symbols: conditional loader with potential sync-js-loader fallback
214
+ symbolData: {
215
+ symbols: new Map([
216
+ ['default', { local: 'module.exports', loc: null }],
217
+ ]),
218
+ dependencies: [
219
+ {
220
+ specifier: loaderPath,
221
+ symbols: new Map([
222
+ ['default', { local: 'default', loc: null, isWeak: false }],
223
+ ]),
224
+ usedSymbols: new Set(['default']),
225
+ },
226
+ ...(shouldUseFallback
227
+ ? [
228
+ {
229
+ specifier: './helpers/browser/sync-js-loader',
230
+ symbols: new Map([
231
+ ['default', { local: 'l', loc: null, isWeak: false }],
232
+ ]),
233
+ usedSymbols: new Set(['default']),
234
+ },
235
+ ]
236
+ : []),
237
+ ],
238
+ },
239
+ });
240
+ }
241
+ }
242
+ for (let dependency of otherDependencies) {
243
+ // Resolve the dependency to a bundle. If inline, export the dependency id,
244
+ // which will be replaced with the contents of that bundle later.
245
+ let referencedBundle = bundleGraph.getReferencedBundle(dependency, bundle);
246
+ if (referencedBundle?.bundleBehavior === 'inline' ||
247
+ referencedBundle?.bundleBehavior === 'inlineIsolated') {
248
+ assets.push({
249
+ filePath: path_1.default.join(__dirname, `/bundles/${referencedBundle.id}.js`),
250
+ code: `module.exports = ${JSON.stringify(dependency.id)};`,
251
+ dependency,
252
+ env: { sourceType: 'module' },
253
+ // Pre-computed symbols: simple export with no dependencies
254
+ symbolData: {
255
+ symbols: new Map([
256
+ ['default', { local: 'module.exports', loc: null }],
257
+ ]),
258
+ dependencies: [],
259
+ },
260
+ });
261
+ continue;
262
+ }
263
+ // Otherwise, try to resolve the dependency to an external bundle group
264
+ // and insert a URL to that bundle.
265
+ let resolved = bundleGraph.resolveAsyncDependency(dependency, bundle);
266
+ if (dependency.specifierType === 'url' && resolved == null) {
267
+ // If a URL dependency was not able to be resolved, add a runtime that
268
+ // exports the original specifier.
269
+ assets.push({
270
+ filePath: __filename,
271
+ code: `module.exports = ${JSON.stringify(dependency.specifier)}`,
272
+ dependency,
273
+ env: { sourceType: 'module' },
274
+ // Pre-computed symbols: simple export with no dependencies
275
+ symbolData: {
276
+ symbols: new Map([
277
+ ['default', { local: 'module.exports', loc: null }],
278
+ ]),
279
+ dependencies: [],
280
+ },
281
+ });
282
+ continue;
283
+ }
284
+ if (resolved == null || resolved.type !== 'bundle_group') {
285
+ continue;
286
+ }
287
+ let bundleGroup = resolved.value;
288
+ let mainBundle = (0, nullthrows_1.default)(bundleGraph.getBundlesInBundleGroup(bundleGroup).find((b) => {
289
+ let entries = b.getEntryAssets();
290
+ return entries.some((e) => bundleGroup.entryAssetId === e.id);
291
+ }));
292
+ // Skip URL runtimes for library builds. This is handled in packaging so that
293
+ // the url is inlined and statically analyzable.
294
+ if (bundle.env.isLibrary &&
295
+ mainBundle.bundleBehavior !== 'isolated' &&
296
+ mainBundle.bundleBehavior !== 'inlineIsolated') {
297
+ continue;
298
+ }
299
+ // URL dependency or not, fall back to including a runtime that exports the url
300
+ assets.push(getURLRuntime(dependency, bundle, mainBundle, options, config.domainSharding));
301
+ }
302
+ // In development, bundles can be created lazily. This means that the parent bundle may not
303
+ // know about all of the sibling bundles of a child when it is written for the first time.
304
+ // Therefore, we need to also ensure that the siblings are loaded when the child loads.
305
+ if (options.shouldBuildLazily && bundle.env.outputFormat === 'global') {
306
+ let referenced = bundleGraph.getReferencedBundles(bundle);
307
+ for (let referencedBundle of referenced) {
308
+ let loaders = getLoaders(bundle.env);
309
+ if (!loaders) {
310
+ continue;
311
+ }
312
+ let loader = loaders[referencedBundle.type];
313
+ if (!loader) {
314
+ continue;
315
+ }
316
+ let relativePathExpr = getRelativePathExpr(bundle, referencedBundle, options);
317
+ let loaderCode = `require(${JSON.stringify(loader)})(${getAbsoluteUrlExpr(relativePathExpr, bundle, config.domainSharding)})`;
318
+ assets.push({
319
+ filePath: __filename,
320
+ code: loaderCode,
321
+ isEntry: true,
322
+ env: { sourceType: 'module' },
323
+ // Pre-computed symbols: lazy bundle loader, requires specific loader helper
324
+ symbolData: {
325
+ symbols: new Map(), // No exports, just side effects
326
+ dependencies: [
327
+ {
328
+ specifier: loader,
329
+ symbols: new Map([
330
+ ['default', { local: 'default', loc: null, isWeak: false }],
331
+ ]),
332
+ usedSymbols: new Set(['default']),
333
+ },
334
+ ],
335
+ },
336
+ });
337
+ }
338
+ }
339
+ if (shouldUseRuntimeManifest(bundle, options) &&
340
+ bundleGraph
341
+ .getChildBundles(bundle)
342
+ .some((b) => b.bundleBehavior !== 'inline' &&
343
+ b.bundleBehavior !== 'inlineIsolated') &&
344
+ isNewContext(bundle, bundleGraph)) {
345
+ assets.push({
346
+ filePath: __filename,
347
+ code: getRegisterCode(bundle, bundleGraph),
348
+ isEntry: true,
349
+ env: { sourceType: 'module' },
350
+ runtimeAssetRequiringExecutionOnLoad: true,
351
+ priority: getManifestBundlePriority(bundleGraph, bundle, config.splitManifestThreshold),
352
+ // Pre-computed symbols: requires bundle-manifest helper
353
+ symbolData: {
354
+ symbols: new Map(), // No exports, just executes
355
+ dependencies: [
356
+ {
357
+ specifier: './helpers/bundle-manifest',
358
+ symbols: new Map([
359
+ ['register', { local: 'register', loc: null, isWeak: false }],
360
+ ]),
361
+ usedSymbols: new Set(['register']),
362
+ },
363
+ ],
364
+ },
365
+ });
366
+ }
367
+ return assets;
368
+ },
369
+ });
370
+ function getDependencies(bundle) {
371
+ let cachedDependencies = bundleDependencies.get(bundle);
372
+ if (cachedDependencies) {
373
+ return cachedDependencies;
374
+ }
375
+ else {
376
+ let asyncDependencies = [];
377
+ let otherDependencies = [];
378
+ let conditionalDependencies = [];
379
+ bundle.traverse((node) => {
380
+ if (node.type !== 'dependency') {
381
+ return;
382
+ }
383
+ let dependency = node.value;
384
+ if (dependency.priority === 'lazy' &&
385
+ dependency.specifierType !== 'url') {
386
+ asyncDependencies.push(dependency);
387
+ }
388
+ else if (dependency.priority === 'conditional') {
389
+ conditionalDependencies.push(dependency);
390
+ }
391
+ else {
392
+ otherDependencies.push(dependency);
393
+ }
394
+ });
395
+ bundleDependencies.set(bundle, {
396
+ asyncDependencies,
397
+ conditionalDependencies,
398
+ otherDependencies,
399
+ });
400
+ return { asyncDependencies, conditionalDependencies, otherDependencies };
401
+ }
402
+ }
403
+ function getLoaderRuntime({ bundle, dependency, bundleGroup, bundleGraph, options, shardingConfig, }) {
404
+ let loaders = getLoaders(bundle.env);
405
+ if (loaders == null) {
406
+ return;
407
+ }
408
+ let externalBundles = bundleGraph.getBundlesInBundleGroup(bundleGroup);
409
+ let potentialMainBundle;
410
+ if ((0, feature_flags_1.getFeatureFlag)('supportWebpackChunkName')) {
411
+ potentialMainBundle = externalBundles.find((bundle) => bundle
412
+ .getEntryAssets()
413
+ .some((asset) => asset.id === bundleGroup.entryAssetId));
414
+ }
415
+ else {
416
+ potentialMainBundle = externalBundles.find((bundle) => bundle.getMainEntry()?.id === bundleGroup.entryAssetId);
417
+ }
418
+ let mainBundle = (0, nullthrows_1.default)(potentialMainBundle);
419
+ // CommonJS is a synchronous module system, so there is no need to load bundles in parallel.
420
+ // Importing of the other bundles will be handled by the bundle group entry.
421
+ // Do the same thing in library mode for ES modules, as we are building for another bundler
422
+ // and the imports for sibling bundles will be in the target bundle.
423
+ // Previously we also did this when building lazily, however it seemed to cause issues in some cases.
424
+ // The original comment as to why is left here, in case a future traveller is trying to fix that issue:
425
+ // > [...] the runtime itself could get deduplicated and only exist in the parent. This causes errors if an
426
+ // > old version of the parent without the runtime
427
+ // > is already loaded.
428
+ if (bundle.env.outputFormat === 'commonjs' || bundle.env.isLibrary) {
429
+ externalBundles = [mainBundle];
430
+ }
431
+ else {
432
+ // Otherwise, load the bundle group entry after the others.
433
+ externalBundles.splice(externalBundles.indexOf(mainBundle), 1);
434
+ externalBundles.reverse().push(mainBundle);
435
+ }
436
+ // Determine if we need to add a dynamic import() polyfill, or if all target browsers support it natively.
437
+ let needsDynamicImportPolyfill = !bundle.env.isLibrary && !bundle.env.supports('dynamic-import', true);
438
+ let needsEsmLoadPrelude = false;
439
+ let loaderModules = [];
440
+ function getLoaderForBundle(bundle, to, shardingConfig) {
441
+ // @ts-expect-error TS18049
442
+ let loader = loaders[to.type];
443
+ if (!loader) {
444
+ return;
445
+ }
446
+ if (to.type === 'js' &&
447
+ to.env.outputFormat === 'esmodule' &&
448
+ !needsDynamicImportPolyfill &&
449
+ shouldUseRuntimeManifest(bundle, options)) {
450
+ needsEsmLoadPrelude = true;
451
+ return `load(${JSON.stringify(to.publicId)})`;
452
+ }
453
+ let relativePathExpr = getRelativePathExpr(bundle, to, options);
454
+ // Use esmodule loader if possible
455
+ if (to.type === 'js' && to.env.outputFormat === 'esmodule') {
456
+ if (!needsDynamicImportPolyfill) {
457
+ return `__parcel__import__("./" + ${relativePathExpr})`;
458
+ }
459
+ // @ts-expect-error TS2322
460
+ loader = (0, nullthrows_1.default)(
461
+ // @ts-expect-error TS18049
462
+ loaders.IMPORT_POLYFILL, `No import() polyfill available for context '${bundle.env.context}'`);
463
+ }
464
+ else if (to.type === 'js' && to.env.outputFormat === 'commonjs') {
465
+ return `Promise.resolve(__parcel__require__("./" + ${relativePathExpr}))`;
466
+ }
467
+ let absoluteUrlExpr;
468
+ if (shouldUseRuntimeManifest(bundle, options)) {
469
+ let publicId = JSON.stringify(to.publicId);
470
+ absoluteUrlExpr = `require('./helpers/bundle-manifest').resolve(${publicId})`;
471
+ if (shardingConfig) {
472
+ absoluteUrlExpr = `require('@atlaspack/domain-sharding').shardUrl(${absoluteUrlExpr}, ${shardingConfig.maxShards})`;
473
+ }
474
+ }
475
+ else {
476
+ absoluteUrlExpr = getAbsoluteUrlExpr(relativePathExpr, bundle, shardingConfig);
477
+ }
478
+ let code = `require(${JSON.stringify(loader)})(${absoluteUrlExpr})`;
479
+ // In development, clear the require cache when an error occurs so the
480
+ // user can try again (e.g. after fixing a build error).
481
+ if (options.mode === 'development' &&
482
+ bundle.env.outputFormat === 'global') {
483
+ code +=
484
+ '.catch(err => {delete module.bundle.cache[module.id]; throw err;})';
485
+ }
486
+ return code;
487
+ }
488
+ function getConditionalLoadersForCondition(dependencies, sourceBundle) {
489
+ if (dependencies.length === 0) {
490
+ // Avoid extra work if there are no dependencies, so we don't have to traverse conditions
491
+ return [];
492
+ }
493
+ // Get all the condition objects for the conditional dependencies
494
+ const conditions = bundleGraph.getConditionsForDependencies(dependencies, sourceBundle);
495
+ const loaders = [];
496
+ for (const cond of conditions) {
497
+ // This bundle has a conditional dependency, we need to load the bundle group
498
+ const ifTrueLoaders = cond.ifTrueBundles
499
+ .flatMap((targetBundle) => getConditionalLoadersForCondition(getDependencies(targetBundle).conditionalDependencies, targetBundle))
500
+ .concat(
501
+ // @ts-expect-error TS2769
502
+ cond.ifTrueBundles.map((targetBundle) =>
503
+ // @ts-expect-error TS2554
504
+ getLoaderForBundle(sourceBundle, targetBundle)));
505
+ const ifFalseLoaders = cond.ifFalseBundles
506
+ .flatMap((targetBundle) => getConditionalLoadersForCondition(getDependencies(targetBundle).conditionalDependencies, targetBundle))
507
+ .concat(
508
+ // @ts-expect-error TS2769
509
+ cond.ifFalseBundles.map((targetBundle) =>
510
+ // @ts-expect-error TS2554
511
+ getLoaderForBundle(sourceBundle, targetBundle)));
512
+ if (ifTrueLoaders.length > 0 || ifFalseLoaders.length > 0) {
513
+ // Load conditional bundles with helper (and a dev mode with additional hints)
514
+ loaders.push(`require('./helpers/conditional-loader${options.mode === 'development' ? '-dev' : ''}')('${cond.key}', function (){return Promise.all([${ifTrueLoaders.join(',')}]);}, function (){return Promise.all([${ifFalseLoaders.join(',')}]);})`);
515
+ }
516
+ }
517
+ return loaders;
518
+ }
519
+ if ((0, feature_flags_1.getFeatureFlag)('conditionalBundlingApi')) {
520
+ let conditionalDependencies = externalBundles.flatMap((to) => getDependencies(to).conditionalDependencies);
521
+ loaderModules.push(...getConditionalLoadersForCondition(conditionalDependencies, bundle));
522
+ }
523
+ for (let to of externalBundles) {
524
+ let loaderModule = getLoaderForBundle(bundle, to, shardingConfig);
525
+ if (loaderModule !== undefined)
526
+ loaderModules.push(loaderModule);
527
+ }
528
+ // Similar to the comment above, this also used to be skipped when shouldBuildLazily was true,
529
+ // however it caused issues where a bundle group contained multiple bundles.
530
+ if (bundle.env.context === 'browser') {
531
+ loaderModules.push(...externalBundles
532
+ // TODO: Allow css to preload resources as well
533
+ .filter((to) => to.type === 'js')
534
+ .flatMap((from) => {
535
+ let { preload, prefetch } = getHintedBundleGroups(bundleGraph, from);
536
+ return [
537
+ ...getHintLoaders(bundleGraph, bundle, preload, BROWSER_PRELOAD_LOADER, options),
538
+ ...getHintLoaders(bundleGraph, bundle, prefetch, BROWSER_PREFETCH_LOADER, options),
539
+ ];
540
+ }));
541
+ }
542
+ if (loaderModules.length === 0) {
543
+ return;
544
+ }
545
+ let loaderCode = loaderModules.join(', ');
546
+ if (loaderModules.length > 1) {
547
+ loaderCode = `Promise.all([${loaderCode}])`;
548
+ }
549
+ else {
550
+ loaderCode = `(${loaderCode})`;
551
+ }
552
+ if (mainBundle.type === 'js') {
553
+ let parcelRequire = (0, feature_flags_1.getFeatureFlag)('hmrImprovements') || bundle.env.shouldScopeHoist
554
+ ? 'parcelRequire'
555
+ : 'module.bundle.root';
556
+ loaderCode += `.then(() => ${parcelRequire}('${bundleGraph.getAssetPublicId(bundleGraph.getAssetById(bundleGroup.entryAssetId))}'))`;
557
+ }
558
+ if (needsEsmLoadPrelude && options.featureFlags.importRetry) {
559
+ loaderCode = `
560
+ Object.defineProperty(module, 'exports', { get: () => {
561
+ let load = require('./helpers/browser/esm-js-loader-retry');
562
+ return ${loaderCode}.then((v) => {
563
+ Object.defineProperty(module, "exports", { value: Promise.resolve(v) })
564
+ return v
565
+ });
566
+ }})`;
567
+ return {
568
+ filePath: __filename,
569
+ code: loaderCode,
570
+ dependency,
571
+ env: { sourceType: 'module' },
572
+ // Pre-computed symbols: ESM loader with retry, requires esm-js-loader-retry helper
573
+ symbolData: {
574
+ symbols: new Map([['default', { local: 'module.exports', loc: null }]]),
575
+ dependencies: [
576
+ {
577
+ specifier: './helpers/browser/esm-js-loader-retry',
578
+ symbols: new Map([
579
+ ['default', { local: 'default', loc: null, isWeak: false }],
580
+ ]),
581
+ usedSymbols: new Set(['default']),
582
+ },
583
+ ],
584
+ },
585
+ };
586
+ }
587
+ let code = [];
588
+ if (needsEsmLoadPrelude) {
589
+ let preludeLoad = shardingConfig
590
+ ? `let load = require('./helpers/browser/esm-js-loader-shards')(${shardingConfig.maxShards});`
591
+ : `let load = require('./helpers/browser/esm-js-loader');`;
592
+ code.push(preludeLoad);
593
+ }
594
+ code.push(`module.exports = ${loaderCode};`);
595
+ // Collect all potential helper dependencies used in loader runtime
596
+ let helperDependencies = [];
597
+ // Always potential dependencies based on the code patterns
598
+ if (needsEsmLoadPrelude) {
599
+ if (shardingConfig) {
600
+ helperDependencies.push({
601
+ specifier: './helpers/browser/esm-js-loader-shards',
602
+ symbols: new Map([
603
+ ['default', { local: 'default', loc: null, isWeak: false }],
604
+ ]),
605
+ usedSymbols: new Set(['default']),
606
+ });
607
+ }
608
+ else {
609
+ helperDependencies.push({
610
+ specifier: './helpers/browser/esm-js-loader',
611
+ symbols: new Map([
612
+ ['default', { local: 'default', loc: null, isWeak: false }],
613
+ ]),
614
+ usedSymbols: new Set(['default']),
615
+ });
616
+ }
617
+ }
618
+ // Bundle manifest dependency if using runtime manifest
619
+ if (shouldUseRuntimeManifest(bundle, options)) {
620
+ helperDependencies.push({
621
+ specifier: './helpers/bundle-manifest',
622
+ symbols: new Map([
623
+ ['resolve', { local: 'resolve', loc: null, isWeak: false }],
624
+ ]),
625
+ usedSymbols: new Set(['resolve']),
626
+ });
627
+ }
628
+ // Domain sharding dependency if configured
629
+ if (shardingConfig) {
630
+ helperDependencies.push({
631
+ specifier: '@atlaspack/domain-sharding',
632
+ symbols: new Map([
633
+ ['shardUrl', { local: 'shardUrl', loc: null, isWeak: false }],
634
+ ]),
635
+ usedSymbols: new Set(['shardUrl']),
636
+ });
637
+ }
638
+ // Various loader dependencies based on bundle types in externalBundles
639
+ for (let to of externalBundles) {
640
+ let loader = loaders[to.type];
641
+ if (loader && typeof loader === 'string') {
642
+ helperDependencies.push({
643
+ specifier: loader,
644
+ symbols: new Map([
645
+ ['default', { local: 'default', loc: null, isWeak: false }],
646
+ ]),
647
+ usedSymbols: new Set(['default']),
648
+ });
649
+ }
650
+ }
651
+ // Import polyfill if needed
652
+ if (needsDynamicImportPolyfill && loaders?.IMPORT_POLYFILL) {
653
+ helperDependencies.push({
654
+ specifier: loaders.IMPORT_POLYFILL,
655
+ symbols: new Map([
656
+ ['default', { local: 'default', loc: null, isWeak: false }],
657
+ ]),
658
+ usedSymbols: new Set(['default']),
659
+ });
660
+ }
661
+ // Conditional loaders if using conditional bundling
662
+ if ((0, feature_flags_1.getFeatureFlag)('conditionalBundlingApi')) {
663
+ const loaderPath = `./helpers/conditional-loader${options.mode === 'development' ? '-dev' : ''}`;
664
+ helperDependencies.push({
665
+ specifier: loaderPath,
666
+ symbols: new Map([
667
+ ['default', { local: 'default', loc: null, isWeak: false }],
668
+ ]),
669
+ usedSymbols: new Set(['default']),
670
+ });
671
+ // Sync loader for fallback
672
+ if (options.mode === 'development') {
673
+ helperDependencies.push({
674
+ specifier: './helpers/browser/sync-js-loader',
675
+ symbols: new Map([
676
+ ['default', { local: 'default', loc: null, isWeak: false }],
677
+ ]),
678
+ usedSymbols: new Set(['default']),
679
+ });
680
+ }
681
+ }
682
+ // Preload/prefetch loaders for browser context
683
+ if (bundle.env.context === 'browser') {
684
+ helperDependencies.push({
685
+ specifier: BROWSER_PRELOAD_LOADER,
686
+ symbols: new Map([
687
+ ['default', { local: 'default', loc: null, isWeak: false }],
688
+ ]),
689
+ usedSymbols: new Set(['default']),
690
+ });
691
+ helperDependencies.push({
692
+ specifier: BROWSER_PREFETCH_LOADER,
693
+ symbols: new Map([
694
+ ['default', { local: 'default', loc: null, isWeak: false }],
695
+ ]),
696
+ usedSymbols: new Set(['default']),
697
+ });
698
+ }
699
+ // ESM loader retry if using import retry feature
700
+ if (needsEsmLoadPrelude && options.featureFlags.importRetry) {
701
+ helperDependencies.push({
702
+ specifier: './helpers/browser/esm-js-loader-retry',
703
+ symbols: new Map([
704
+ ['default', { local: 'default', loc: null, isWeak: false }],
705
+ ]),
706
+ usedSymbols: new Set(['default']),
707
+ });
708
+ }
709
+ return {
710
+ filePath: __filename,
711
+ code: code.join('\n'),
712
+ dependency,
713
+ env: { sourceType: 'module' },
714
+ // Pre-computed symbols: loader runtime with comprehensive helper dependencies
715
+ symbolData: {
716
+ symbols: new Map([['default', { local: 'module.exports', loc: null }]]),
717
+ dependencies: helperDependencies,
718
+ },
719
+ };
720
+ }
721
+ function getHintedBundleGroups(bundleGraph, bundle) {
722
+ let preload = [];
723
+ let prefetch = [];
724
+ let { asyncDependencies } = getDependencies(bundle);
725
+ for (let dependency of asyncDependencies) {
726
+ let attributes = dependency.meta?.importAttributes;
727
+ if (typeof attributes === 'object' &&
728
+ attributes != null &&
729
+ // @ts-expect-error TS2339
730
+ (attributes.preload || attributes.prefetch)) {
731
+ let resolved = bundleGraph.resolveAsyncDependency(dependency, bundle);
732
+ if (resolved?.type === 'bundle_group') {
733
+ // === true for flow
734
+ // @ts-expect-error TS2339
735
+ if (attributes.preload === true) {
736
+ preload.push(resolved.value);
737
+ }
738
+ // @ts-expect-error TS2339
739
+ if (attributes.prefetch === true) {
740
+ prefetch.push(resolved.value);
741
+ }
742
+ }
743
+ }
744
+ }
745
+ return { preload, prefetch };
746
+ }
747
+ function getHintLoaders(bundleGraph, from, bundleGroups, loader, options) {
748
+ let hintLoaders = [];
749
+ for (let bundleGroupToPreload of bundleGroups) {
750
+ let bundlesToPreload = bundleGraph.getBundlesInBundleGroup(bundleGroupToPreload);
751
+ for (let bundleToPreload of bundlesToPreload) {
752
+ let relativePathExpr = getRelativePathExpr(from, bundleToPreload, options);
753
+ // @ts-expect-error TS7053
754
+ let priority = TYPE_TO_RESOURCE_PRIORITY[bundleToPreload.type];
755
+ hintLoaders.push(
756
+ // @ts-expect-error TS2554
757
+ `require(${JSON.stringify(loader)})(${getAbsoluteUrlExpr(relativePathExpr, from)}, ${priority ? JSON.stringify(priority) : 'null'}, ${JSON.stringify(bundleToPreload.target.env.outputFormat === 'esmodule')})`);
758
+ }
759
+ }
760
+ return hintLoaders;
761
+ }
762
+ function isNewContext(bundle, bundleGraph) {
763
+ let parents = bundleGraph.getParentBundles(bundle);
764
+ let isInEntryBundleGroup = bundleGraph
765
+ .getBundleGroupsContainingBundle(bundle)
766
+ .some((g) => bundleGraph.isEntryBundleGroup(g));
767
+ return (isInEntryBundleGroup ||
768
+ parents.length === 0 ||
769
+ parents.some((parent) => parent.env.context !== bundle.env.context || parent.type !== 'js'));
770
+ }
771
+ function getURLRuntime(dependency, from, to, options, shardingConfig) {
772
+ let relativePathExpr;
773
+ if ((0, feature_flags_1.getFeatureFlag)('hmrImprovements')) {
774
+ relativePathExpr = getRelativePathExpr(from, to, options, true);
775
+ }
776
+ else {
777
+ relativePathExpr = getRelativePathExpr(from, to, options);
778
+ }
779
+ let code;
780
+ if (dependency.meta.webworker === true && !from.env.isLibrary) {
781
+ code = `let workerURL = require('./helpers/get-worker-url');\n`;
782
+ if (from.env.outputFormat === 'esmodule' &&
783
+ from.env.supports('import-meta-url')) {
784
+ code += `let url = new __parcel__URL__(${relativePathExpr});\n`;
785
+ code += `module.exports = workerURL(url.toString(), url.origin, ${String(from.env.outputFormat === 'esmodule')});`;
786
+ }
787
+ else {
788
+ code += `let bundleURL = require('./helpers/bundle-url');\n`;
789
+ code += `let url = bundleURL.getBundleURL('${from.publicId}') + ${relativePathExpr};`;
790
+ if (shardingConfig) {
791
+ code += `url = require('@atlaspack/domain-sharding').shardUrl(url, ${shardingConfig.maxShards});`;
792
+ }
793
+ code += `module.exports = workerURL(url, bundleURL.getOrigin(url), ${String(from.env.outputFormat === 'esmodule')});`;
794
+ }
795
+ }
796
+ else {
797
+ code = `module.exports = ${getAbsoluteUrlExpr(relativePathExpr, from, shardingConfig)};`;
798
+ }
799
+ // Collect dependencies based on the URL runtime code patterns
800
+ let urlRuntimeDependencies = [];
801
+ if (dependency.meta.webworker === true && !from.env.isLibrary) {
802
+ // Web worker runtime requires get-worker-url helper
803
+ urlRuntimeDependencies.push({
804
+ specifier: './helpers/get-worker-url',
805
+ symbols: new Map([
806
+ ['default', { local: 'workerURL', loc: null, isWeak: false }],
807
+ ]),
808
+ usedSymbols: new Set(['default']),
809
+ });
810
+ if (!(from.env.outputFormat === 'esmodule' &&
811
+ from.env.supports('import-meta-url'))) {
812
+ // Also requires bundle-url helper in non-ESM environments
813
+ urlRuntimeDependencies.push({
814
+ specifier: './helpers/bundle-url',
815
+ symbols: new Map([
816
+ ['getBundleURL', { local: 'getBundleURL', loc: null, isWeak: false }],
817
+ ['getOrigin', { local: 'getOrigin', loc: null, isWeak: false }],
818
+ ]),
819
+ usedSymbols: new Set(['getBundleURL', 'getOrigin']),
820
+ });
821
+ // Domain sharding if configured
822
+ if (shardingConfig) {
823
+ urlRuntimeDependencies.push({
824
+ specifier: '@atlaspack/domain-sharding',
825
+ symbols: new Map([
826
+ ['shardUrl', { local: 'shardUrl', loc: null, isWeak: false }],
827
+ ]),
828
+ usedSymbols: new Set(['shardUrl']),
829
+ });
830
+ }
831
+ }
832
+ }
833
+ else {
834
+ // Regular URL runtime may use bundle-url helper
835
+ if (!(from.env.outputFormat === 'esmodule' &&
836
+ from.env.supports('import-meta-url')) &&
837
+ !(from.env.outputFormat === 'commonjs')) {
838
+ urlRuntimeDependencies.push({
839
+ specifier: './helpers/bundle-url',
840
+ symbols: new Map([
841
+ ['getBundleURL', { local: 'getBundleURL', loc: null, isWeak: false }],
842
+ ]),
843
+ usedSymbols: new Set(['getBundleURL']),
844
+ });
845
+ if (shardingConfig) {
846
+ urlRuntimeDependencies.push({
847
+ specifier: '@atlaspack/domain-sharding',
848
+ symbols: new Map([
849
+ ['shardUrl', { local: 'shardUrl', loc: null, isWeak: false }],
850
+ ]),
851
+ usedSymbols: new Set(['shardUrl']),
852
+ });
853
+ }
854
+ }
855
+ }
856
+ return {
857
+ filePath: __filename,
858
+ code,
859
+ dependency,
860
+ env: { sourceType: 'module' },
861
+ // Pre-computed symbols: URL runtime with helper dependencies
862
+ symbolData: {
863
+ symbols: new Map([['default', { local: 'module.exports', loc: null }]]),
864
+ dependencies: urlRuntimeDependencies,
865
+ },
866
+ };
867
+ }
868
+ function getRegisterCode(entryBundle, bundleGraph) {
869
+ // @ts-expect-error TS2304
870
+ let mappings = [];
871
+ bundleGraph.traverseBundles((bundle, _, actions) => {
872
+ if (bundle.bundleBehavior === 'inline' ||
873
+ bundle.bundleBehavior === 'inlineIsolated') {
874
+ return;
875
+ }
876
+ // To make the manifest as small as possible all bundle key/values are
877
+ // serialised into a single array e.g. ['id', 'value', 'id2', 'value2'].
878
+ // `./helpers/bundle-manifest` accounts for this by iterating index by 2
879
+ mappings.push(bundle.publicId, (0, utils_1.relativeBundlePath)(entryBundle, (0, nullthrows_1.default)(bundle), {
880
+ leadingDotSlash: false,
881
+ }));
882
+ if (bundle !== entryBundle && isNewContext(bundle, bundleGraph)) {
883
+ for (let referenced of bundleGraph.getReferencedBundles(bundle)) {
884
+ mappings.push(referenced.publicId, (0, utils_1.relativeBundlePath)(entryBundle, (0, nullthrows_1.default)(referenced), {
885
+ leadingDotSlash: false,
886
+ }));
887
+ }
888
+ // New contexts have their own manifests, so there's no need to continue.
889
+ actions.skipChildren();
890
+ }
891
+ }, entryBundle);
892
+ let baseUrl = entryBundle.env.outputFormat === 'esmodule' &&
893
+ entryBundle.env.supports('import-meta-url')
894
+ ? 'new __parcel__URL__("").toString()' // <-- this isn't ideal. We should use `import.meta.url` directly but it gets replaced currently
895
+ : `require('./helpers/bundle-url').getBundleURL('${entryBundle.publicId}')`;
896
+ return `require('./helpers/bundle-manifest').register(${baseUrl},JSON.parse(${JSON.stringify(JSON.stringify(mappings))}));`;
897
+ }
898
+ function getRelativePathExpr(from, to, options, isURL = to.type !== 'js') {
899
+ let relativePath = (0, utils_1.relativeBundlePath)(from, to, { leadingDotSlash: false });
900
+ let res = JSON.stringify(relativePath);
901
+ if ((0, feature_flags_1.getFeatureFlag)('hmrImprovements')) {
902
+ if (isURL && options.hmrOptions) {
903
+ if ((0, feature_flags_1.getFeatureFlag)('hmrBundleVersioning')) {
904
+ res +=
905
+ ' + (globalThis.__parcel__hmrBundleVersion == null' +
906
+ ' ? ""' +
907
+ ' : (' +
908
+ JSON.stringify(relativePath) +
909
+ '.includes("?") ? "&" : "?") + "t=" + globalThis.__parcel__hmrBundleVersion)';
910
+ }
911
+ else {
912
+ res += ' + "?" + Date.now()';
913
+ }
914
+ }
915
+ }
916
+ else {
917
+ if (options.hmrOptions) {
918
+ if ((0, feature_flags_1.getFeatureFlag)('hmrBundleVersioning')) {
919
+ res +=
920
+ ' + (globalThis.__parcel__hmrBundleVersion == null' +
921
+ ' ? ""' +
922
+ ' : (' +
923
+ JSON.stringify(relativePath) +
924
+ '.includes("?") ? "&" : "?") + "t=" + globalThis.__parcel__hmrBundleVersion)';
925
+ }
926
+ else {
927
+ res += ' + "?" + Date.now()';
928
+ }
929
+ }
930
+ }
931
+ return res;
932
+ }
933
+ function getAbsoluteUrlExpr(relativePathExpr, fromBundle, shardingConfig) {
934
+ if ((fromBundle.env.outputFormat === 'esmodule' &&
935
+ fromBundle.env.supports('import-meta-url')) ||
936
+ fromBundle.env.outputFormat === 'commonjs') {
937
+ // This will be compiled to new URL(url, import.meta.url) or new URL(url, 'file:' + __filename).
938
+ return `new __parcel__URL__(${relativePathExpr}).toString()`;
939
+ }
940
+ const regularBundleUrl = `require('./helpers/bundle-url').getBundleURL('${fromBundle.publicId}') + ${relativePathExpr}`;
941
+ if (!shardingConfig) {
942
+ return regularBundleUrl;
943
+ }
944
+ return `require('@atlaspack/domain-sharding').shardUrl(${regularBundleUrl}, ${shardingConfig.maxShards})`;
945
+ }
946
+ function shouldUseRuntimeManifest(bundle, options) {
947
+ let env = bundle.env;
948
+ return (!env.isLibrary &&
949
+ bundle.bundleBehavior !== 'inline' &&
950
+ bundle.bundleBehavior !== 'inlineIsolated' &&
951
+ env.isBrowser() &&
952
+ options.mode === 'production');
953
+ }
954
+ function getManifestBundlePriority(bundleGraph, bundle, threshold) {
955
+ let bundleSize = 0;
956
+ bundle.traverseAssets((asset, _, actions) => {
957
+ bundleSize += asset.stats.size;
958
+ if (bundleSize > threshold) {
959
+ actions.stop();
960
+ }
961
+ });
962
+ return bundleSize > threshold ? 'parallel' : 'sync';
963
+ }