@atlaspack/packager-js 2.12.1-dev.3401 → 2.12.1-dev.3450

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.
@@ -53,6 +53,13 @@ function _path() {
53
53
  };
54
54
  return data;
55
55
  }
56
+ function _featureFlags() {
57
+ const data = require("@atlaspack/feature-flags");
58
+ _featureFlags = function () {
59
+ return data;
60
+ };
61
+ return data;
62
+ }
56
63
  var _ESMOutputFormat = require("./ESMOutputFormat");
57
64
  var _CJSOutputFormat = require("./CJSOutputFormat");
58
65
  var _GlobalOutputFormat = require("./GlobalOutputFormat");
@@ -63,7 +70,10 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
63
70
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
64
71
  // General regex used to replace imports with the resolved code, references with resolutions,
65
72
  // and count the number of newlines in the file for source maps.
66
- const REPLACEMENT_RE = /\n|import\s+"([0-9a-f]{16}:.+?)";|(?:\$[0-9a-f]{16}\$exports)|(?:\$[0-9a-f]{16}\$(?:import|importAsync|require)\$[0-9a-f]+(?:\$[0-9a-f]+)?)/g;
73
+ //
74
+ // For conditional bundling the only difference in this regex is adding `importCond` where we have `importAsync` etc..
75
+ const REPLACEMENT_RE_CONDITIONAL = /\n|import\s+"([0-9a-f]{16,20}:.+?)";|(?:\$[0-9a-f]{16,20}\$exports)|(?:\$[0-9a-f]{16,20}\$(?:import|importAsync|require|importCond)\$[0-9a-f]+(?:\$[0-9a-f]+)?)/g;
76
+ const REPLACEMENT_RE = /\n|import\s+"([0-9a-f]{16,20}:.+?)";|(?:\$[0-9a-f]{16,20}\$exports)|(?:\$[0-9a-f]{16,20}\$(?:import|importAsync|require)\$[0-9a-f]+(?:\$[0-9a-f]+)?)/g;
67
77
  const BUILTINS = Object.keys(_globals().default.builtin);
68
78
  const GLOBALS_BY_CONTEXT = {
69
79
  browser: new Set([...BUILTINS, ...Object.keys(_globals().default.browser)]),
@@ -89,12 +99,15 @@ class ScopeHoistingPackager {
89
99
  needsPrelude = false;
90
100
  usedHelpers = new Set();
91
101
  externalAssets = new Set();
92
- constructor(options, bundleGraph, bundle, parcelRequireName, useAsyncBundleRuntime) {
102
+ forceSkipWrapAssets = [];
103
+ constructor(options, bundleGraph, bundle, parcelRequireName, useAsyncBundleRuntime, forceSkipWrapAssets, logger) {
93
104
  this.options = options;
94
105
  this.bundleGraph = bundleGraph;
95
106
  this.bundle = bundle;
96
107
  this.parcelRequireName = parcelRequireName;
97
108
  this.useAsyncBundleRuntime = useAsyncBundleRuntime;
109
+ this.forceSkipWrapAssets = forceSkipWrapAssets ?? [];
110
+ this.logger = logger;
98
111
  let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
99
112
  this.outputFormat = new OutputFormat(this);
100
113
  this.isAsyncBundle = this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') && !this.bundle.env.isIsolated() && this.bundle.bundleBehavior !== 'isolated';
@@ -257,6 +270,18 @@ class ScopeHoistingPackager {
257
270
  actions.skipChildren();
258
271
  return;
259
272
  }
273
+ // This prevents children of a wrapped asset also being wrapped - it's an "unsafe" optimisation
274
+ // that should only be used when you know (or think you know) what you're doing.
275
+ //
276
+ // In particular this can force an async bundle to be scope hoisted where it previously would not be
277
+ // due to the entry asset being wrapped.
278
+ if (this.forceSkipWrapAssets.length > 0 && this.forceSkipWrapAssets.some(p => p === _path().default.relative(this.options.projectRoot, asset.filePath))) {
279
+ this.logger.verbose({
280
+ message: `Force skipping wrapping of ${_path().default.relative(this.options.projectRoot, asset.filePath)}`
281
+ });
282
+ actions.skipChildren();
283
+ return;
284
+ }
260
285
  if (!asset.meta.isConstantModule) {
261
286
  this.wrappedAssets.add(asset.id);
262
287
  wrapped.push(asset);
@@ -412,7 +437,7 @@ class ScopeHoistingPackager {
412
437
  // in a single regex so that we only do one pass over the whole code.
413
438
  let offset = 0;
414
439
  let columnStartIndex = 0;
415
- code = code.replace(REPLACEMENT_RE, (m, d, i) => {
440
+ code = code.replace((0, _featureFlags().getFeatureFlag)('conditionalBundlingApi') ? REPLACEMENT_RE_CONDITIONAL : REPLACEMENT_RE, (m, d, i) => {
416
441
  if (m === '\n') {
417
442
  columnStartIndex = i + offset + 1;
418
443
  lineCount++;
@@ -559,7 +584,7 @@ ${code}
559
584
  // Async dependencies need a namespace object even if all used symbols were statically analyzed.
560
585
  // This is recorded in the promiseSymbol meta property set by the transformer rather than in
561
586
  // symbols so that we don't mark all symbols as used.
562
- if (dep.priority === 'lazy' && dep.meta.promiseSymbol) {
587
+ if ((dep.priority === 'lazy' || dep.priority === 'conditional') && dep.meta.promiseSymbol) {
563
588
  let promiseSymbol = dep.meta.promiseSymbol;
564
589
  (0, _assert().default)(typeof promiseSymbol === 'string');
565
590
  let symbol = this.getSymbolResolution(asset, resolved, '*', dep);
@@ -993,7 +1018,9 @@ ${code}
993
1018
  // Add the prelude if this is potentially the first JS bundle to load in a
994
1019
  // particular context (e.g. entry scripts in HTML, workers, etc.).
995
1020
  let parentBundles = this.bundleGraph.getParentBundles(this.bundle);
996
- let mightBeFirstJS = parentBundles.length === 0 || parentBundles.some(b => b.type !== 'js') || this.bundleGraph.getBundleGroupsContainingBundle(this.bundle).some(g => this.bundleGraph.isEntryBundleGroup(g)) || this.bundle.env.isIsolated() || this.bundle.bundleBehavior === 'isolated';
1021
+ let mightBeFirstJS = parentBundles.length === 0 || parentBundles.some(b => b.type !== 'js') || this.bundleGraph.getBundleGroupsContainingBundle(this.bundle).some(g => this.bundleGraph.isEntryBundleGroup(g)) || this.bundle.env.isIsolated() || this.bundle.bundleBehavior === 'isolated' ||
1022
+ // Conditional deps may be loaded before entrypoints on the server
1023
+ this.hasConditionalDependency();
997
1024
  if (mightBeFirstJS) {
998
1025
  let preludeCode = (0, _helpers.prelude)(this.parcelRequireName);
999
1026
  res += preludeCode;
@@ -1036,10 +1063,7 @@ ${code}
1036
1063
  }
1037
1064
  needsDefaultInterop(asset) {
1038
1065
  if (asset.symbols.hasExportSymbol('*') && !asset.symbols.hasExportSymbol('default')) {
1039
- let deps = this.bundleGraph.getIncomingDependencies(asset);
1040
- return deps.some(dep => this.bundle.hasDependency(dep) &&
1041
- // dep.meta.isES6Module &&
1042
- dep.symbols.hasExportSymbol('default'));
1066
+ return true;
1043
1067
  }
1044
1068
  return false;
1045
1069
  }
@@ -1055,5 +1079,11 @@ ${code}
1055
1079
  buildFunctionExpression(args, expr) {
1056
1080
  return this.bundle.env.supports('arrow-functions', true) ? `(${args.join(', ')}) => ${expr}` : `function (${args.join(', ')}) { return ${expr}; }`;
1057
1081
  }
1082
+ hasConditionalDependency() {
1083
+ if (!(0, _featureFlags().getFeatureFlag)('conditionalBundlingApi')) {
1084
+ return false;
1085
+ }
1086
+ return this.bundle.getEntryAssets().some(entry => this.bundleGraph.getIncomingDependencies(entry).some(dep => dep.priority === 'conditional'));
1087
+ }
1058
1088
  }
1059
1089
  exports.ScopeHoistingPackager = ScopeHoistingPackager;
package/lib/index.js CHANGED
@@ -47,6 +47,12 @@ const CONFIG_SCHEMA = {
47
47
  properties: {
48
48
  unstable_asyncBundleRuntime: {
49
49
  type: 'boolean'
50
+ },
51
+ unstable_forceSkipWrapAssets: {
52
+ type: 'array',
53
+ items: {
54
+ type: 'string'
55
+ }
50
56
  }
51
57
  },
52
58
  additionalProperties: false
@@ -56,7 +62,7 @@ var _default = exports.default = new (_plugin().Packager)({
56
62
  config,
57
63
  options
58
64
  }) {
59
- var _packageName$contents, _conf$contents;
65
+ var _packageName$contents, _conf$contents, _conf$contents2;
60
66
  let packageKey = '@atlaspack/packager-js';
61
67
  let conf = await config.getConfigFrom(options.projectRoot + '/index', [], {
62
68
  packageKey
@@ -78,7 +84,8 @@ var _default = exports.default = new (_plugin().Packager)({
78
84
  let name = (packageName === null || packageName === void 0 || (_packageName$contents = packageName.contents) === null || _packageName$contents === void 0 ? void 0 : _packageName$contents.name) ?? '';
79
85
  return {
80
86
  parcelRequireName: 'parcelRequire' + (0, _rust().hashString)(name).slice(-4),
81
- unstable_asyncBundleRuntime: Boolean(conf === null || conf === void 0 || (_conf$contents = conf.contents) === null || _conf$contents === void 0 ? void 0 : _conf$contents.unstable_asyncBundleRuntime)
87
+ unstable_asyncBundleRuntime: Boolean(conf === null || conf === void 0 || (_conf$contents = conf.contents) === null || _conf$contents === void 0 ? void 0 : _conf$contents.unstable_asyncBundleRuntime),
88
+ unstable_forceSkipWrapAssets: (conf === null || conf === void 0 || (_conf$contents2 = conf.contents) === null || _conf$contents2 === void 0 ? void 0 : _conf$contents2.unstable_forceSkipWrapAssets) ?? []
82
89
  };
83
90
  },
84
91
  async package({
@@ -87,7 +94,8 @@ var _default = exports.default = new (_plugin().Packager)({
87
94
  getInlineBundleContents,
88
95
  getSourceMapReference,
89
96
  config,
90
- options
97
+ options,
98
+ logger
91
99
  }) {
92
100
  // If this is a non-module script, and there is only one asset with no dependencies,
93
101
  // then we don't need to package at all and can pass through the original code un-wrapped.
@@ -100,7 +108,7 @@ var _default = exports.default = new (_plugin().Packager)({
100
108
  }
101
109
  }
102
110
  if (contents == null) {
103
- 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);
111
+ let packager = bundle.env.shouldScopeHoist ? new _ScopeHoistingPackager.ScopeHoistingPackager(options, bundleGraph, bundle, (0, _nullthrows().default)(config).parcelRequireName, (0, _nullthrows().default)(config).unstable_asyncBundleRuntime, (0, _nullthrows().default)(config).unstable_forceSkipWrapAssets, logger) : new _DevPackager.DevPackager(options, bundleGraph, bundle, (0, _nullthrows().default)(config).parcelRequireName);
104
112
  ({
105
113
  contents,
106
114
  map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@atlaspack/packager-js",
3
- "version": "2.12.1-dev.3401+b483af77f",
4
- "license": "MIT",
3
+ "version": "2.12.1-dev.3450+58845ef87",
4
+ "license": "(MIT OR Apache-2.0)",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -13,17 +13,18 @@
13
13
  "source": "src/index.js",
14
14
  "engines": {
15
15
  "node": ">= 16.0.0",
16
- "parcel": "^2.12.1-dev.3401+b483af77f"
16
+ "parcel": "^2.12.1-dev.3450+58845ef87"
17
17
  },
18
18
  "dependencies": {
19
- "@atlaspack/diagnostic": "2.12.1-dev.3401+b483af77f",
20
- "@atlaspack/plugin": "2.12.1-dev.3401+b483af77f",
21
- "@atlaspack/rust": "2.12.1-dev.3401+b483af77f",
22
- "@atlaspack/types": "2.12.1-dev.3401+b483af77f",
23
- "@atlaspack/utils": "2.12.1-dev.3401+b483af77f",
19
+ "@atlaspack/diagnostic": "2.12.1-dev.3450+58845ef87",
20
+ "@atlaspack/feature-flags": "2.12.1-dev.3450+58845ef87",
21
+ "@atlaspack/plugin": "2.12.1-dev.3450+58845ef87",
22
+ "@atlaspack/rust": "2.12.1-dev.3450+58845ef87",
23
+ "@atlaspack/types": "2.12.1-dev.3450+58845ef87",
24
+ "@atlaspack/utils": "2.12.1-dev.3450+58845ef87",
24
25
  "@parcel/source-map": "^2.1.1",
25
26
  "globals": "^13.2.0",
26
27
  "nullthrows": "^1.1.1"
27
28
  },
28
- "gitHead": "b483af77f02d1258c8dad156e097b94f83671d8e"
29
+ "gitHead": "58845ef87446fcedb7d7d8876440c64184645cbb"
29
30
  }
@@ -6,6 +6,7 @@ import type {
6
6
  Dependency,
7
7
  PluginOptions,
8
8
  NamedBundle,
9
+ PluginLogger,
9
10
  } from '@atlaspack/types';
10
11
 
11
12
  import {
@@ -23,6 +24,7 @@ import ThrowableDiagnostic, {
23
24
  } from '@atlaspack/diagnostic';
24
25
  import globals from 'globals';
25
26
  import path from 'path';
27
+ import {getFeatureFlag} from '@atlaspack/feature-flags';
26
28
 
27
29
  import {ESMOutputFormat} from './ESMOutputFormat';
28
30
  import {CJSOutputFormat} from './CJSOutputFormat';
@@ -34,10 +36,15 @@ import {
34
36
  isValidIdentifier,
35
37
  makeValidIdentifier,
36
38
  } from './utils';
39
+
37
40
  // General regex used to replace imports with the resolved code, references with resolutions,
38
41
  // and count the number of newlines in the file for source maps.
42
+ //
43
+ // For conditional bundling the only difference in this regex is adding `importCond` where we have `importAsync` etc..
44
+ const REPLACEMENT_RE_CONDITIONAL =
45
+ /\n|import\s+"([0-9a-f]{16,20}:.+?)";|(?:\$[0-9a-f]{16,20}\$exports)|(?:\$[0-9a-f]{16,20}\$(?:import|importAsync|require|importCond)\$[0-9a-f]+(?:\$[0-9a-f]+)?)/g;
39
46
  const REPLACEMENT_RE =
40
- /\n|import\s+"([0-9a-f]{16}:.+?)";|(?:\$[0-9a-f]{16}\$exports)|(?:\$[0-9a-f]{16}\$(?:import|importAsync|require)\$[0-9a-f]+(?:\$[0-9a-f]+)?)/g;
47
+ /\n|import\s+"([0-9a-f]{16,20}:.+?)";|(?:\$[0-9a-f]{16,20}\$exports)|(?:\$[0-9a-f]{16,20}\$(?:import|importAsync|require)\$[0-9a-f]+(?:\$[0-9a-f]+)?)/g;
41
48
 
42
49
  const BUILTINS = Object.keys(globals.builtin);
43
50
  const GLOBALS_BY_CONTEXT = {
@@ -95,6 +102,8 @@ export class ScopeHoistingPackager {
95
102
  needsPrelude: boolean = false;
96
103
  usedHelpers: Set<string> = new Set();
97
104
  externalAssets: Set<Asset> = new Set();
105
+ forceSkipWrapAssets: Array<string> = [];
106
+ logger: PluginLogger;
98
107
 
99
108
  constructor(
100
109
  options: PluginOptions,
@@ -102,12 +111,16 @@ export class ScopeHoistingPackager {
102
111
  bundle: NamedBundle,
103
112
  parcelRequireName: string,
104
113
  useAsyncBundleRuntime: boolean,
114
+ forceSkipWrapAssets: Array<string>,
115
+ logger: PluginLogger,
105
116
  ) {
106
117
  this.options = options;
107
118
  this.bundleGraph = bundleGraph;
108
119
  this.bundle = bundle;
109
120
  this.parcelRequireName = parcelRequireName;
110
121
  this.useAsyncBundleRuntime = useAsyncBundleRuntime;
122
+ this.forceSkipWrapAssets = forceSkipWrapAssets ?? [];
123
+ this.logger = logger;
111
124
 
112
125
  let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
113
126
  this.outputFormat = new OutputFormat(this);
@@ -340,6 +353,26 @@ export class ScopeHoistingPackager {
340
353
  actions.skipChildren();
341
354
  return;
342
355
  }
356
+ // This prevents children of a wrapped asset also being wrapped - it's an "unsafe" optimisation
357
+ // that should only be used when you know (or think you know) what you're doing.
358
+ //
359
+ // In particular this can force an async bundle to be scope hoisted where it previously would not be
360
+ // due to the entry asset being wrapped.
361
+ if (
362
+ this.forceSkipWrapAssets.length > 0 &&
363
+ this.forceSkipWrapAssets.some(
364
+ p => p === path.relative(this.options.projectRoot, asset.filePath),
365
+ )
366
+ ) {
367
+ this.logger.verbose({
368
+ message: `Force skipping wrapping of ${path.relative(
369
+ this.options.projectRoot,
370
+ asset.filePath,
371
+ )}`,
372
+ });
373
+ actions.skipChildren();
374
+ return;
375
+ }
343
376
  if (!asset.meta.isConstantModule) {
344
377
  this.wrappedAssets.add(asset.id);
345
378
  wrapped.push(asset);
@@ -536,92 +569,100 @@ export class ScopeHoistingPackager {
536
569
  // in a single regex so that we only do one pass over the whole code.
537
570
  let offset = 0;
538
571
  let columnStartIndex = 0;
539
- code = code.replace(REPLACEMENT_RE, (m, d, i) => {
540
- if (m === '\n') {
541
- columnStartIndex = i + offset + 1;
542
- lineCount++;
543
- return '\n';
544
- }
545
-
546
- // If we matched an import, replace with the source code for the dependency.
547
- if (d != null) {
548
- let deps = depMap.get(d);
549
- if (!deps) {
550
- return m;
572
+ code = code.replace(
573
+ getFeatureFlag('conditionalBundlingApi')
574
+ ? REPLACEMENT_RE_CONDITIONAL
575
+ : REPLACEMENT_RE,
576
+ (m, d, i) => {
577
+ if (m === '\n') {
578
+ columnStartIndex = i + offset + 1;
579
+ lineCount++;
580
+ return '\n';
551
581
  }
552
582
 
553
- let replacement = '';
554
-
555
- // A single `${id}:${specifier}:esm` might have been resolved to multiple assets due to
556
- // reexports.
557
- for (let dep of deps) {
558
- let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle);
559
- let skipped = this.bundleGraph.isDependencySkipped(dep);
560
- if (resolved && !skipped) {
561
- // Hoist variable declarations for the referenced parcelRequire dependencies
562
- // after the dependency is declared. This handles the case where the resulting asset
563
- // is wrapped, but the dependency in this asset is not marked as wrapped. This means
564
- // that it was imported/required at the top-level, so its side effects should run immediately.
565
- let [res, lines] = this.getHoistedParcelRequires(
566
- asset,
583
+ // If we matched an import, replace with the source code for the dependency.
584
+ if (d != null) {
585
+ let deps = depMap.get(d);
586
+ if (!deps) {
587
+ return m;
588
+ }
589
+
590
+ let replacement = '';
591
+
592
+ // A single `${id}:${specifier}:esm` might have been resolved to multiple assets due to
593
+ // reexports.
594
+ for (let dep of deps) {
595
+ let resolved = this.bundleGraph.getResolvedAsset(
567
596
  dep,
568
- resolved,
597
+ this.bundle,
569
598
  );
570
- let map;
571
- if (
572
- this.bundle.hasAsset(resolved) &&
573
- !this.seenAssets.has(resolved.id)
574
- ) {
575
- // If this asset is wrapped, we need to hoist the code for the dependency
576
- // outside our parcelRequire.register wrapper. This is safe because all
577
- // assets referenced by this asset will also be wrapped. Otherwise, inline the
578
- // asset content where the import statement was.
579
- if (shouldWrap) {
580
- depContent.push(this.visitAsset(resolved));
581
- } else {
582
- let [depCode, depMap, depLines] = this.visitAsset(resolved);
583
- res = depCode + '\n' + res;
584
- lines += 1 + depLines;
585
- map = depMap;
599
+ let skipped = this.bundleGraph.isDependencySkipped(dep);
600
+ if (resolved && !skipped) {
601
+ // Hoist variable declarations for the referenced parcelRequire dependencies
602
+ // after the dependency is declared. This handles the case where the resulting asset
603
+ // is wrapped, but the dependency in this asset is not marked as wrapped. This means
604
+ // that it was imported/required at the top-level, so its side effects should run immediately.
605
+ let [res, lines] = this.getHoistedParcelRequires(
606
+ asset,
607
+ dep,
608
+ resolved,
609
+ );
610
+ let map;
611
+ if (
612
+ this.bundle.hasAsset(resolved) &&
613
+ !this.seenAssets.has(resolved.id)
614
+ ) {
615
+ // If this asset is wrapped, we need to hoist the code for the dependency
616
+ // outside our parcelRequire.register wrapper. This is safe because all
617
+ // assets referenced by this asset will also be wrapped. Otherwise, inline the
618
+ // asset content where the import statement was.
619
+ if (shouldWrap) {
620
+ depContent.push(this.visitAsset(resolved));
621
+ } else {
622
+ let [depCode, depMap, depLines] = this.visitAsset(resolved);
623
+ res = depCode + '\n' + res;
624
+ lines += 1 + depLines;
625
+ map = depMap;
626
+ }
586
627
  }
587
- }
588
628
 
589
- // Push this asset's source mappings down by the number of lines in the dependency
590
- // plus the number of hoisted parcelRequires. Then insert the source map for the dependency.
591
- if (sourceMap) {
592
- if (lines > 0) {
593
- sourceMap.offsetLines(lineCount + 1, lines);
594
- }
629
+ // Push this asset's source mappings down by the number of lines in the dependency
630
+ // plus the number of hoisted parcelRequires. Then insert the source map for the dependency.
631
+ if (sourceMap) {
632
+ if (lines > 0) {
633
+ sourceMap.offsetLines(lineCount + 1, lines);
634
+ }
595
635
 
596
- if (map) {
597
- sourceMap.addSourceMap(map, lineCount);
636
+ if (map) {
637
+ sourceMap.addSourceMap(map, lineCount);
638
+ }
598
639
  }
599
- }
600
640
 
601
- replacement += res;
602
- lineCount += lines;
641
+ replacement += res;
642
+ lineCount += lines;
643
+ }
603
644
  }
645
+ return replacement;
604
646
  }
605
- return replacement;
606
- }
607
647
 
608
- // If it wasn't a dependency, then it was an inline replacement (e.g. $id$import$foo -> $id$export$foo).
609
- let replacement = replacements.get(m) ?? m;
610
- if (sourceMap) {
611
- // Offset the source map columns for this line if the replacement was a different length.
612
- // This assumes that the match and replacement both do not contain any newlines.
613
- let lengthDifference = replacement.length - m.length;
614
- if (lengthDifference !== 0) {
615
- sourceMap.offsetColumns(
616
- lineCount + 1,
617
- i + offset - columnStartIndex + m.length,
618
- lengthDifference,
619
- );
620
- offset += lengthDifference;
648
+ // If it wasn't a dependency, then it was an inline replacement (e.g. $id$import$foo -> $id$export$foo).
649
+ let replacement = replacements.get(m) ?? m;
650
+ if (sourceMap) {
651
+ // Offset the source map columns for this line if the replacement was a different length.
652
+ // This assumes that the match and replacement both do not contain any newlines.
653
+ let lengthDifference = replacement.length - m.length;
654
+ if (lengthDifference !== 0) {
655
+ sourceMap.offsetColumns(
656
+ lineCount + 1,
657
+ i + offset - columnStartIndex + m.length,
658
+ lengthDifference,
659
+ );
660
+ offset += lengthDifference;
661
+ }
621
662
  }
622
- }
623
- return replacement;
624
- });
663
+ return replacement;
664
+ },
665
+ );
625
666
  }
626
667
 
627
668
  // If the asset is wrapped, we need to insert the dependency code outside the parcelRequire.register
@@ -743,7 +784,10 @@ ${code}
743
784
  // Async dependencies need a namespace object even if all used symbols were statically analyzed.
744
785
  // This is recorded in the promiseSymbol meta property set by the transformer rather than in
745
786
  // symbols so that we don't mark all symbols as used.
746
- if (dep.priority === 'lazy' && dep.meta.promiseSymbol) {
787
+ if (
788
+ (dep.priority === 'lazy' || dep.priority === 'conditional') &&
789
+ dep.meta.promiseSymbol
790
+ ) {
747
791
  let promiseSymbol = dep.meta.promiseSymbol;
748
792
  invariant(typeof promiseSymbol === 'string');
749
793
  let symbol = this.getSymbolResolution(asset, resolved, '*', dep);
@@ -1376,7 +1420,9 @@ ${code}
1376
1420
  .getBundleGroupsContainingBundle(this.bundle)
1377
1421
  .some(g => this.bundleGraph.isEntryBundleGroup(g)) ||
1378
1422
  this.bundle.env.isIsolated() ||
1379
- this.bundle.bundleBehavior === 'isolated';
1423
+ this.bundle.bundleBehavior === 'isolated' ||
1424
+ // Conditional deps may be loaded before entrypoints on the server
1425
+ this.hasConditionalDependency();
1380
1426
 
1381
1427
  if (mightBeFirstJS) {
1382
1428
  let preludeCode = prelude(this.parcelRequireName);
@@ -1430,13 +1476,7 @@ ${code}
1430
1476
  asset.symbols.hasExportSymbol('*') &&
1431
1477
  !asset.symbols.hasExportSymbol('default')
1432
1478
  ) {
1433
- let deps = this.bundleGraph.getIncomingDependencies(asset);
1434
- return deps.some(
1435
- dep =>
1436
- this.bundle.hasDependency(dep) &&
1437
- // dep.meta.isES6Module &&
1438
- dep.symbols.hasExportSymbol('default'),
1439
- );
1479
+ return true;
1440
1480
  }
1441
1481
 
1442
1482
  return false;
@@ -1467,4 +1507,18 @@ ${code}
1467
1507
  ? `(${args.join(', ')}) => ${expr}`
1468
1508
  : `function (${args.join(', ')}) { return ${expr}; }`;
1469
1509
  }
1510
+
1511
+ hasConditionalDependency(): boolean {
1512
+ if (!getFeatureFlag('conditionalBundlingApi')) {
1513
+ return false;
1514
+ }
1515
+
1516
+ return this.bundle
1517
+ .getEntryAssets()
1518
+ .some(entry =>
1519
+ this.bundleGraph
1520
+ .getIncomingDependencies(entry)
1521
+ .some(dep => dep.priority === 'conditional'),
1522
+ );
1523
+ }
1470
1524
  }
package/src/index.js CHANGED
@@ -17,6 +17,7 @@ import {ScopeHoistingPackager} from './ScopeHoistingPackager';
17
17
  type JSPackagerConfig = {|
18
18
  parcelRequireName: string,
19
19
  unstable_asyncBundleRuntime: boolean,
20
+ unstable_forceSkipWrapAssets: Array<string>,
20
21
  |};
21
22
 
22
23
  const CONFIG_SCHEMA: SchemaEntity = {
@@ -25,6 +26,12 @@ const CONFIG_SCHEMA: SchemaEntity = {
25
26
  unstable_asyncBundleRuntime: {
26
27
  type: 'boolean',
27
28
  },
29
+ unstable_forceSkipWrapAssets: {
30
+ type: 'array',
31
+ items: {
32
+ type: 'string',
33
+ },
34
+ },
28
35
  },
29
36
  additionalProperties: false,
30
37
  };
@@ -66,6 +73,8 @@ export default (new Packager({
66
73
  unstable_asyncBundleRuntime: Boolean(
67
74
  conf?.contents?.unstable_asyncBundleRuntime,
68
75
  ),
76
+ unstable_forceSkipWrapAssets:
77
+ conf?.contents?.unstable_forceSkipWrapAssets ?? [],
69
78
  };
70
79
  },
71
80
  async package({
@@ -75,6 +84,7 @@ export default (new Packager({
75
84
  getSourceMapReference,
76
85
  config,
77
86
  options,
87
+ logger,
78
88
  }) {
79
89
  // If this is a non-module script, and there is only one asset with no dependencies,
80
90
  // then we don't need to package at all and can pass through the original code un-wrapped.
@@ -98,6 +108,8 @@ export default (new Packager({
98
108
  bundle,
99
109
  nullthrows(config).parcelRequireName,
100
110
  nullthrows(config).unstable_asyncBundleRuntime,
111
+ nullthrows(config).unstable_forceSkipWrapAssets,
112
+ logger,
101
113
  )
102
114
  : new DevPackager(
103
115
  options,