@parcel/packager-js 2.0.0-nightly.1357 → 2.0.0-nightly.1359

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.
@@ -88,6 +88,11 @@ class ESMOutputFormat {
88
88
  res += `\nexport {${exportSpecifiers.join(', ')}};`;
89
89
  lines++;
90
90
  }
91
+ if (this.packager.shouldBundleQueue(this.packager.bundle)) {
92
+ // Should be last thing the bundle executes on intial eval
93
+ res += `\n$parcel$global.rlb(${JSON.stringify(this.packager.bundle.publicId)})`;
94
+ lines++;
95
+ }
91
96
  return [res, lines];
92
97
  }
93
98
  }
@@ -94,11 +94,12 @@ class ScopeHoistingPackager {
94
94
  needsPrelude = false;
95
95
  usedHelpers = new Set();
96
96
  externalAssets = new Set();
97
- constructor(options, bundleGraph, bundle, parcelRequireName) {
97
+ constructor(options, bundleGraph, bundle, parcelRequireName, useAsyncBundleRuntime) {
98
98
  this.options = options;
99
99
  this.bundleGraph = bundleGraph;
100
100
  this.bundle = bundle;
101
101
  this.parcelRequireName = parcelRequireName;
102
+ this.useAsyncBundleRuntime = useAsyncBundleRuntime;
102
103
  let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
103
104
  this.outputFormat = new OutputFormat(this);
104
105
  this.isAsyncBundle = this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') && !this.bundle.env.isIsolated() && this.bundle.bundleBehavior !== 'isolated';
@@ -181,6 +182,7 @@ class ScopeHoistingPackager {
181
182
  });
182
183
  mainEntry = null;
183
184
  }
185
+ let needsBundleQueue = this.shouldBundleQueue(this.bundle);
184
186
 
185
187
  // If any of the entry assets are wrapped, call parcelRequire so they are executed.
186
188
  for (let entry of entries) {
@@ -189,8 +191,12 @@ class ScopeHoistingPackager {
189
191
  let parcelRequire = `parcelRequire(${JSON.stringify(this.bundleGraph.getAssetPublicId(entry))});\n`;
190
192
  let entryExports = (_entry$symbols$get = entry.symbols.get('*')) === null || _entry$symbols$get === void 0 ? void 0 : _entry$symbols$get.local;
191
193
  if (entryExports && entry === mainEntry && this.exportedSymbols.has(entryExports)) {
194
+ (0, _assert().default)(!needsBundleQueue, 'Entry exports are not yet compaitble with async bundles');
192
195
  res += `\nvar ${entryExports} = ${parcelRequire}`;
193
196
  } else {
197
+ if (needsBundleQueue) {
198
+ parcelRequire = this.runWhenReady(this.bundle, parcelRequire);
199
+ }
194
200
  res += `\n${parcelRequire}`;
195
201
  }
196
202
  lineCount += 2;
@@ -225,6 +231,18 @@ class ScopeHoistingPackager {
225
231
  map: sourceMap
226
232
  };
227
233
  }
234
+ shouldBundleQueue(bundle) {
235
+ return this.useAsyncBundleRuntime && bundle.type === 'js' && bundle.bundleBehavior !== 'inline' && bundle.env.outputFormat === 'esmodule' && !bundle.env.isIsolated() && bundle.bundleBehavior !== 'isolated' && !this.bundleGraph.hasParentBundleOfType(bundle, 'js');
236
+ }
237
+ runWhenReady(bundle, codeToRun) {
238
+ let deps = this.bundleGraph.getReferencedBundles(bundle).filter(b => this.shouldBundleQueue(b)).map(b => b.publicId);
239
+ if (deps.length === 0) {
240
+ // If no deps we can safely execute immediately
241
+ return codeToRun;
242
+ }
243
+ let params = [JSON.stringify(this.bundle.publicId), (0, _helpers.fnExpr)(this.bundle.env, [], [codeToRun]), JSON.stringify(deps)];
244
+ return `$parcel$global.rwr(${params.join(', ')});`;
245
+ }
228
246
  async loadAssets() {
229
247
  let queue = new (_utils().PromiseQueue)({
230
248
  maxConcurrent: 32
@@ -494,6 +512,9 @@ ${code}
494
512
  }
495
513
  this.needsPrelude = true;
496
514
  }
515
+ if (!shouldWrap && this.shouldBundleQueue(this.bundle) && this.bundle.getEntryAssets().some(entry => entry.id === asset.id)) {
516
+ code = this.runWhenReady(this.bundle, code);
517
+ }
497
518
  return [code, sourceMap, lineCount];
498
519
  }
499
520
  buildReplacements(asset, deps) {
@@ -902,6 +923,13 @@ ${code}
902
923
  if (enableSourceMaps) {
903
924
  lines += (0, _utils().countLines)(preludeCode) - 1;
904
925
  }
926
+ if (this.shouldBundleQueue(this.bundle)) {
927
+ let bundleQueuePreludeCode = (0, _helpers.bundleQueuePrelude)(this.bundle.env);
928
+ res += bundleQueuePreludeCode;
929
+ if (enableSourceMaps) {
930
+ lines += (0, _utils().countLines)(bundleQueuePreludeCode) - 1;
931
+ }
932
+ }
905
933
  } else {
906
934
  // Otherwise, get the current parcelRequire global.
907
935
  res += `var parcelRequire = $parcel$global[${JSON.stringify(this.parcelRequireName)}];\n`;
package/lib/helpers.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.prelude = exports.helpers = void 0;
6
+ exports.prelude = exports.helpers = exports.fnExpr = exports.bundleQueuePrelude = void 0;
7
7
  const prelude = parcelRequireName => `
8
8
  var $parcel$modules = {};
9
9
  var $parcel$inits = {};
@@ -35,6 +35,36 @@ if (parcelRequire == null) {
35
35
  }
36
36
  `;
37
37
  exports.prelude = prelude;
38
+ const fnExpr = (env, params, body) => {
39
+ let block = `{ ${body.join(' ')} }`;
40
+ if (env.supports('arrow-functions')) {
41
+ return `(${params.join(', ')}) => ${block}`;
42
+ }
43
+ return `function (${params.join(', ')}) ${block}`;
44
+ };
45
+ exports.fnExpr = fnExpr;
46
+ const bundleQueuePrelude = env => `
47
+ if (!$parcel$global.lb) {
48
+ // Set of loaded bundles
49
+ $parcel$global.lb = new Set();
50
+ // Queue of bundles to execute once they're dep bundles are loaded
51
+ $parcel$global.bq = [];
52
+
53
+ // Register loaded bundle
54
+ $parcel$global.rlb = ${fnExpr(env, ['bundle'], ['$parcel$global.lb.add(bundle);', '$parcel$global.pq();'])}
55
+
56
+ // Run when ready
57
+ $parcel$global.rwr = ${fnExpr(env,
58
+ // b = bundle public id
59
+ // r = run function to execute the bundle entry
60
+ // d = list of dependent bundles this bundle requires before executing
61
+ ['b', 'r', 'd'], ['$parcel$global.bq.push({b, r, d});', '$parcel$global.pq();'])}
62
+
63
+ // Process queue
64
+ $parcel$global.pq = ${fnExpr(env, [], [`var runnableEntry = $parcel$global.bq.find(${fnExpr(env, ['i'], [`return i.d.every(${fnExpr(env, ['dep'], ['return $parcel$global.lb.has(dep);'])});`])});`, 'if (runnableEntry) {', `$parcel$global.bq = $parcel$global.bq.filter(${fnExpr(env, ['i'], ['return i.b !== runnableEntry.b;'])});`, 'runnableEntry.r();', '$parcel$global.pq();', '}'])}
65
+ }
66
+ `;
67
+ exports.bundleQueuePrelude = bundleQueuePrelude;
38
68
  const $parcel$export = `
39
69
  function $parcel$export(e, n, v, s) {
40
70
  Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
package/lib/index.js CHANGED
@@ -18,6 +18,13 @@ function _utils() {
18
18
  };
19
19
  return data;
20
20
  }
21
+ function _diagnostic() {
22
+ const data = require("@parcel/diagnostic");
23
+ _diagnostic = function () {
24
+ return data;
25
+ };
26
+ return data;
27
+ }
21
28
  function _hash() {
22
29
  const data = require("@parcel/hash");
23
30
  _hash = function () {
@@ -42,18 +49,37 @@ function _nullthrows() {
42
49
  var _DevPackager = require("./DevPackager");
43
50
  var _ScopeHoistingPackager = require("./ScopeHoistingPackager");
44
51
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
52
+ const CONFIG_SCHEMA = {
53
+ type: 'object',
54
+ properties: {
55
+ unstable_asyncBundleRuntime: {
56
+ type: 'boolean'
57
+ }
58
+ },
59
+ additionalProperties: false
60
+ };
45
61
  var _default = new (_plugin().Packager)({
46
62
  async loadConfig({
47
63
  config,
48
64
  options
49
65
  }) {
50
- var _pkg$contents$name, _pkg$contents;
66
+ var _pkg$contents$name, _pkg$contents, _pkg$contents$package;
51
67
  // Generate a name for the global parcelRequire function that is unique to this project.
52
68
  // This allows multiple parcel builds to coexist on the same page.
53
69
  let pkg = await config.getConfigFrom(_path().default.join(options.projectRoot, 'index'), ['package.json']);
70
+ let packageKey = '@parcel/packager-js';
71
+ if (pkg !== null && pkg !== void 0 && pkg.contents[packageKey]) {
72
+ _utils().validateSchema.diagnostic(CONFIG_SCHEMA, {
73
+ data: pkg === null || pkg === void 0 ? void 0 : pkg.contents[packageKey],
74
+ source: await options.inputFS.readFile(pkg.filePath, 'utf8'),
75
+ filePath: pkg.filePath,
76
+ prependKey: `/${(0, _diagnostic().encodeJSONKeyComponent)(packageKey)}`
77
+ }, packageKey, `Invalid config for ${packageKey}`);
78
+ }
54
79
  let name = (_pkg$contents$name = pkg === null || pkg === void 0 ? void 0 : (_pkg$contents = pkg.contents) === null || _pkg$contents === void 0 ? void 0 : _pkg$contents.name) !== null && _pkg$contents$name !== void 0 ? _pkg$contents$name : '';
55
80
  return {
56
- parcelRequireName: 'parcelRequire' + (0, _hash().hashString)(name).slice(-4)
81
+ parcelRequireName: 'parcelRequire' + (0, _hash().hashString)(name).slice(-4),
82
+ unstable_asyncBundleRuntime: Boolean(pkg === null || pkg === void 0 ? void 0 : (_pkg$contents$package = pkg.contents[packageKey]) === null || _pkg$contents$package === void 0 ? void 0 : _pkg$contents$package.unstable_asyncBundleRuntime)
57
83
  };
58
84
  },
59
85
  async package({
@@ -75,7 +101,7 @@ var _default = new (_plugin().Packager)({
75
101
  }
76
102
  }
77
103
  if (contents == null) {
78
- let packager = bundle.env.shouldScopeHoist ? new _ScopeHoistingPackager.ScopeHoistingPackager(options, bundleGraph, bundle, (0, _nullthrows().default)(config).parcelRequireName) : new _DevPackager.DevPackager(options, bundleGraph, bundle, (0, _nullthrows().default)(config).parcelRequireName);
104
+ let packager = bundle.env.shouldScopeHoist ? new _ScopeHoistingPackager.ScopeHoistingPackager(options, bundleGraph, bundle, (0, _nullthrows().default)(config).parcelRequireName, (0, _nullthrows().default)(config).unstable_asyncBundleRuntime) : new _DevPackager.DevPackager(options, bundleGraph, bundle, (0, _nullthrows().default)(config).parcelRequireName);
79
105
  ({
80
106
  contents,
81
107
  map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parcel/packager-js",
3
- "version": "2.0.0-nightly.1357+feae29eba",
3
+ "version": "2.0.0-nightly.1359+0b5edcfaf",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -17,17 +17,17 @@
17
17
  "source": "src/index.js",
18
18
  "engines": {
19
19
  "node": ">= 12.0.0",
20
- "parcel": "2.0.0-nightly.1355+feae29eba"
20
+ "parcel": "2.0.0-nightly.1357+0b5edcfaf"
21
21
  },
22
22
  "dependencies": {
23
- "@parcel/diagnostic": "2.0.0-nightly.1357+feae29eba",
24
- "@parcel/hash": "2.9.4-nightly.2980+feae29eba",
25
- "@parcel/plugin": "2.0.0-nightly.1357+feae29eba",
23
+ "@parcel/diagnostic": "2.0.0-nightly.1359+0b5edcfaf",
24
+ "@parcel/hash": "2.9.4-nightly.2982+0b5edcfaf",
25
+ "@parcel/plugin": "2.0.0-nightly.1359+0b5edcfaf",
26
26
  "@parcel/source-map": "^2.1.1",
27
- "@parcel/types": "2.0.0-nightly.1357+feae29eba",
28
- "@parcel/utils": "2.0.0-nightly.1357+feae29eba",
27
+ "@parcel/types": "2.0.0-nightly.1359+0b5edcfaf",
28
+ "@parcel/utils": "2.0.0-nightly.1359+0b5edcfaf",
29
29
  "globals": "^13.2.0",
30
30
  "nullthrows": "^1.1.1"
31
31
  },
32
- "gitHead": "feae29ebaebcc79f624c87c386de8137970835b0"
32
+ "gitHead": "0b5edcfaf174a62f454f774d1c78cbf0004cb457"
33
33
  }
@@ -106,6 +106,14 @@ export class ESMOutputFormat implements OutputFormat {
106
106
  lines++;
107
107
  }
108
108
 
109
+ if (this.packager.shouldBundleQueue(this.packager.bundle)) {
110
+ // Should be last thing the bundle executes on intial eval
111
+ res += `\n$parcel$global.rlb(${JSON.stringify(
112
+ this.packager.bundle.publicId,
113
+ )})`;
114
+ lines++;
115
+ }
116
+
109
117
  return [res, lines];
110
118
  }
111
119
  }
@@ -27,7 +27,7 @@ import path from 'path';
27
27
  import {ESMOutputFormat} from './ESMOutputFormat';
28
28
  import {CJSOutputFormat} from './CJSOutputFormat';
29
29
  import {GlobalOutputFormat} from './GlobalOutputFormat';
30
- import {prelude, helpers} from './helpers';
30
+ import {prelude, helpers, bundleQueuePrelude, fnExpr} from './helpers';
31
31
  import {replaceScriptDependencies, getSpecifier} from './utils';
32
32
 
33
33
  // https://262.ecma-international.org/6.0/#sec-names-and-keywords
@@ -74,6 +74,7 @@ export class ScopeHoistingPackager {
74
74
  bundleGraph: BundleGraph<NamedBundle>;
75
75
  bundle: NamedBundle;
76
76
  parcelRequireName: string;
77
+ useAsyncBundleRuntime: boolean;
77
78
  outputFormat: OutputFormat;
78
79
  isAsyncBundle: boolean;
79
80
  globalNames: $ReadOnlySet<string>;
@@ -101,11 +102,13 @@ export class ScopeHoistingPackager {
101
102
  bundleGraph: BundleGraph<NamedBundle>,
102
103
  bundle: NamedBundle,
103
104
  parcelRequireName: string,
105
+ useAsyncBundleRuntime: boolean,
104
106
  ) {
105
107
  this.options = options;
106
108
  this.bundleGraph = bundleGraph;
107
109
  this.bundle = bundle;
108
110
  this.parcelRequireName = parcelRequireName;
111
+ this.useAsyncBundleRuntime = useAsyncBundleRuntime;
109
112
 
110
113
  let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
111
114
  this.outputFormat = new OutputFormat(this);
@@ -202,6 +205,8 @@ export class ScopeHoistingPackager {
202
205
  mainEntry = null;
203
206
  }
204
207
 
208
+ let needsBundleQueue = this.shouldBundleQueue(this.bundle);
209
+
205
210
  // If any of the entry assets are wrapped, call parcelRequire so they are executed.
206
211
  for (let entry of entries) {
207
212
  if (this.wrappedAssets.has(entry.id) && !this.isScriptEntry(entry)) {
@@ -210,13 +215,22 @@ export class ScopeHoistingPackager {
210
215
  )});\n`;
211
216
 
212
217
  let entryExports = entry.symbols.get('*')?.local;
218
+
213
219
  if (
214
220
  entryExports &&
215
221
  entry === mainEntry &&
216
222
  this.exportedSymbols.has(entryExports)
217
223
  ) {
224
+ invariant(
225
+ !needsBundleQueue,
226
+ 'Entry exports are not yet compaitble with async bundles',
227
+ );
218
228
  res += `\nvar ${entryExports} = ${parcelRequire}`;
219
229
  } else {
230
+ if (needsBundleQueue) {
231
+ parcelRequire = this.runWhenReady(this.bundle, parcelRequire);
232
+ }
233
+
220
234
  res += `\n${parcelRequire}`;
221
235
  }
222
236
 
@@ -264,6 +278,38 @@ export class ScopeHoistingPackager {
264
278
  };
265
279
  }
266
280
 
281
+ shouldBundleQueue(bundle: NamedBundle): boolean {
282
+ return (
283
+ this.useAsyncBundleRuntime &&
284
+ bundle.type === 'js' &&
285
+ bundle.bundleBehavior !== 'inline' &&
286
+ bundle.env.outputFormat === 'esmodule' &&
287
+ !bundle.env.isIsolated() &&
288
+ bundle.bundleBehavior !== 'isolated' &&
289
+ !this.bundleGraph.hasParentBundleOfType(bundle, 'js')
290
+ );
291
+ }
292
+
293
+ runWhenReady(bundle: NamedBundle, codeToRun: string): string {
294
+ let deps = this.bundleGraph
295
+ .getReferencedBundles(bundle)
296
+ .filter(b => this.shouldBundleQueue(b))
297
+ .map(b => b.publicId);
298
+
299
+ if (deps.length === 0) {
300
+ // If no deps we can safely execute immediately
301
+ return codeToRun;
302
+ }
303
+
304
+ let params = [
305
+ JSON.stringify(this.bundle.publicId),
306
+ fnExpr(this.bundle.env, [], [codeToRun]),
307
+ JSON.stringify(deps),
308
+ ];
309
+
310
+ return `$parcel$global.rwr(${params.join(', ')});`;
311
+ }
312
+
267
313
  async loadAssets(): Promise<Array<Asset>> {
268
314
  let queue = new PromiseQueue({maxConcurrent: 32});
269
315
  let wrapped = [];
@@ -599,6 +645,14 @@ ${code}
599
645
  this.needsPrelude = true;
600
646
  }
601
647
 
648
+ if (
649
+ !shouldWrap &&
650
+ this.shouldBundleQueue(this.bundle) &&
651
+ this.bundle.getEntryAssets().some(entry => entry.id === asset.id)
652
+ ) {
653
+ code = this.runWhenReady(this.bundle, code);
654
+ }
655
+
602
656
  return [code, sourceMap, lineCount];
603
657
  }
604
658
 
@@ -1199,6 +1253,14 @@ ${code}
1199
1253
  if (enableSourceMaps) {
1200
1254
  lines += countLines(preludeCode) - 1;
1201
1255
  }
1256
+
1257
+ if (this.shouldBundleQueue(this.bundle)) {
1258
+ let bundleQueuePreludeCode = bundleQueuePrelude(this.bundle.env);
1259
+ res += bundleQueuePreludeCode;
1260
+ if (enableSourceMaps) {
1261
+ lines += countLines(bundleQueuePreludeCode) - 1;
1262
+ }
1263
+ }
1202
1264
  } else {
1203
1265
  // Otherwise, get the current parcelRequire global.
1204
1266
  res += `var parcelRequire = $parcel$global[${JSON.stringify(
package/src/helpers.js CHANGED
@@ -32,6 +32,74 @@ if (parcelRequire == null) {
32
32
  }
33
33
  `;
34
34
 
35
+ export const fnExpr = (
36
+ env: Environment,
37
+ params: Array<string>,
38
+ body: Array<string>,
39
+ ): string => {
40
+ let block = `{ ${body.join(' ')} }`;
41
+
42
+ if (env.supports('arrow-functions')) {
43
+ return `(${params.join(', ')}) => ${block}`;
44
+ }
45
+
46
+ return `function (${params.join(', ')}) ${block}`;
47
+ };
48
+
49
+ export const bundleQueuePrelude = (env: Environment): string => `
50
+ if (!$parcel$global.lb) {
51
+ // Set of loaded bundles
52
+ $parcel$global.lb = new Set();
53
+ // Queue of bundles to execute once they're dep bundles are loaded
54
+ $parcel$global.bq = [];
55
+
56
+ // Register loaded bundle
57
+ $parcel$global.rlb = ${fnExpr(
58
+ env,
59
+ ['bundle'],
60
+ ['$parcel$global.lb.add(bundle);', '$parcel$global.pq();'],
61
+ )}
62
+
63
+ // Run when ready
64
+ $parcel$global.rwr = ${fnExpr(
65
+ env,
66
+ // b = bundle public id
67
+ // r = run function to execute the bundle entry
68
+ // d = list of dependent bundles this bundle requires before executing
69
+ ['b', 'r', 'd'],
70
+ ['$parcel$global.bq.push({b, r, d});', '$parcel$global.pq();'],
71
+ )}
72
+
73
+ // Process queue
74
+ $parcel$global.pq = ${fnExpr(
75
+ env,
76
+ [],
77
+ [
78
+ `var runnableEntry = $parcel$global.bq.find(${fnExpr(
79
+ env,
80
+ ['i'],
81
+ [
82
+ `return i.d.every(${fnExpr(
83
+ env,
84
+ ['dep'],
85
+ ['return $parcel$global.lb.has(dep);'],
86
+ )});`,
87
+ ],
88
+ )});`,
89
+ 'if (runnableEntry) {',
90
+ `$parcel$global.bq = $parcel$global.bq.filter(${fnExpr(
91
+ env,
92
+ ['i'],
93
+ ['return i.b !== runnableEntry.b;'],
94
+ )});`,
95
+ 'runnableEntry.r();',
96
+ '$parcel$global.pq();',
97
+ '}',
98
+ ],
99
+ )}
100
+ }
101
+ `;
102
+
35
103
  const $parcel$export = `
36
104
  function $parcel$export(e, n, v, s) {
37
105
  Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
package/src/index.js CHANGED
@@ -2,24 +2,65 @@
2
2
  import type {Async} from '@parcel/types';
3
3
  import type SourceMap from '@parcel/source-map';
4
4
  import {Packager} from '@parcel/plugin';
5
- import {replaceInlineReferences, replaceURLReferences} from '@parcel/utils';
5
+ import {
6
+ replaceInlineReferences,
7
+ replaceURLReferences,
8
+ validateSchema,
9
+ type SchemaEntity,
10
+ } from '@parcel/utils';
11
+ import {encodeJSONKeyComponent} from '@parcel/diagnostic';
6
12
  import {hashString} from '@parcel/hash';
7
13
  import path from 'path';
8
14
  import nullthrows from 'nullthrows';
9
15
  import {DevPackager} from './DevPackager';
10
16
  import {ScopeHoistingPackager} from './ScopeHoistingPackager';
11
17
 
18
+ type JSPackagerConfig = {|
19
+ parcelRequireName: string,
20
+ unstable_asyncBundleRuntime: boolean,
21
+ |};
22
+
23
+ const CONFIG_SCHEMA: SchemaEntity = {
24
+ type: 'object',
25
+ properties: {
26
+ unstable_asyncBundleRuntime: {
27
+ type: 'boolean',
28
+ },
29
+ },
30
+ additionalProperties: false,
31
+ };
32
+
12
33
  export default (new Packager({
13
- async loadConfig({config, options}) {
34
+ async loadConfig({config, options}): Promise<JSPackagerConfig> {
14
35
  // Generate a name for the global parcelRequire function that is unique to this project.
15
36
  // This allows multiple parcel builds to coexist on the same page.
16
37
  let pkg = await config.getConfigFrom(
17
38
  path.join(options.projectRoot, 'index'),
18
39
  ['package.json'],
19
40
  );
41
+
42
+ let packageKey = '@parcel/packager-js';
43
+
44
+ if (pkg?.contents[packageKey]) {
45
+ validateSchema.diagnostic(
46
+ CONFIG_SCHEMA,
47
+ {
48
+ data: pkg?.contents[packageKey],
49
+ source: await options.inputFS.readFile(pkg.filePath, 'utf8'),
50
+ filePath: pkg.filePath,
51
+ prependKey: `/${encodeJSONKeyComponent(packageKey)}`,
52
+ },
53
+ packageKey,
54
+ `Invalid config for ${packageKey}`,
55
+ );
56
+ }
57
+
20
58
  let name = pkg?.contents?.name ?? '';
21
59
  return {
22
60
  parcelRequireName: 'parcelRequire' + hashString(name).slice(-4),
61
+ unstable_asyncBundleRuntime: Boolean(
62
+ pkg?.contents[packageKey]?.unstable_asyncBundleRuntime,
63
+ ),
23
64
  };
24
65
  },
25
66
  async package({
@@ -51,6 +92,7 @@ export default (new Packager({
51
92
  bundleGraph,
52
93
  bundle,
53
94
  nullthrows(config).parcelRequireName,
95
+ nullthrows(config).unstable_asyncBundleRuntime,
54
96
  )
55
97
  : new DevPackager(
56
98
  options,