@parcel/packager-js 2.12.0 → 2.13.0

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.
@@ -40,7 +40,7 @@ function _fs() {
40
40
  return data;
41
41
  }
42
42
  var _utils2 = require("./utils");
43
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
43
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
44
44
  const PRELUDE = _fs().default.readFileSync(_path().default.join(__dirname, 'dev-prelude.js'), 'utf8').trim().replace(/;$/, '');
45
45
  class DevPackager {
46
46
  constructor(options, bundleGraph, bundle, parcelRequireName) {
@@ -98,13 +98,14 @@ class DevPackager {
98
98
  let dependencies = this.bundleGraph.getDependencies(asset);
99
99
  for (let dep of dependencies) {
100
100
  let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle);
101
+ let specifier = (0, _utils2.getSpecifier)(dep);
101
102
  if (this.bundleGraph.isDependencySkipped(dep)) {
102
- deps[(0, _utils2.getSpecifier)(dep)] = false;
103
+ deps[specifier] = false;
103
104
  } else if (resolved) {
104
- deps[(0, _utils2.getSpecifier)(dep)] = this.bundleGraph.getAssetPublicId(resolved);
105
+ deps[specifier] = this.bundleGraph.getAssetPublicId(resolved);
105
106
  } else {
106
107
  // An external module - map placeholder to original specifier.
107
- deps[(0, _utils2.getSpecifier)(dep)] = dep.specifier;
108
+ deps[specifier] = dep.specifier;
108
109
  }
109
110
  }
110
111
  let {
@@ -112,7 +113,7 @@ class DevPackager {
112
113
  mapBuffer
113
114
  } = results[i];
114
115
  let output = code || '';
115
- wrapped += JSON.stringify(this.bundleGraph.getAssetPublicId(asset)) + ':[function(require,module,exports) {\n' + output + '\n},';
116
+ wrapped += JSON.stringify(this.bundleGraph.getAssetPublicId(asset)) + ':[function(require,module,exports,__globalThis) {\n' + output + '\n},';
116
117
  wrapped += JSON.stringify(deps);
117
118
  wrapped += ']';
118
119
  if (this.bundle.env.isNode() && asset.meta.has_node_replacements === true) {
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.ESMOutputFormat = void 0;
7
+ var _utils = require("./utils");
7
8
  class ESMOutputFormat {
8
9
  constructor(packager) {
9
10
  this.packager = packager;
@@ -22,6 +23,9 @@ class ESMOutputFormat {
22
23
  namespaceSpecifier = `* as ${symbol}`;
23
24
  } else {
24
25
  let specifier = imported;
26
+ if (!(0, _utils.isValidIdentifier)(specifier)) {
27
+ specifier = JSON.stringify(specifier);
28
+ }
25
29
  if (symbol !== imported) {
26
30
  specifier += ` as ${symbol}`;
27
31
  }
@@ -78,7 +82,10 @@ class ESMOutputFormat {
78
82
  }
79
83
  for (let as of exportAs) {
80
84
  let specifier = local;
81
- if (exportAs !== local) {
85
+ if (as !== local) {
86
+ if (!(0, _utils.isValidIdentifier)(as)) {
87
+ as = JSON.stringify(as);
88
+ }
82
89
  specifier += ` as ${as}`;
83
90
  }
84
91
  exportSpecifiers.push(specifier);
@@ -26,7 +26,7 @@ function _nullthrows() {
26
26
  return data;
27
27
  }
28
28
  function _assert() {
29
- const data = _interopRequireDefault(require("assert"));
29
+ const data = _interopRequireWildcard(require("assert"));
30
30
  _assert = function () {
31
31
  return data;
32
32
  };
@@ -59,13 +59,8 @@ var _GlobalOutputFormat = require("./GlobalOutputFormat");
59
59
  var _helpers = require("./helpers");
60
60
  var _utils2 = require("./utils");
61
61
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
62
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
63
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
64
- // https://262.ecma-international.org/6.0/#sec-names-and-keywords
65
- const IDENTIFIER_RE = /^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u;
66
- const ID_START_RE = /^[$_\p{ID_Start}]/u;
67
- const NON_ID_CONTINUE_RE = /[^$_\u200C\u200D\p{ID_Continue}]/gu;
68
-
62
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
63
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
69
64
  // General regex used to replace imports with the resolved code, references with resolutions,
70
65
  // and count the number of newlines in the file for source maps.
71
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;
@@ -116,23 +111,10 @@ class ScopeHoistingPackager {
116
111
  // of each bundle group pointing at the sibling bundles. These can be
117
112
  // picked up by another bundler later at which point runtimes will be added.
118
113
  if (this.bundle.env.isLibrary || this.bundle.env.outputFormat === 'commonjs') {
119
- for (let b of this.bundleGraph.getReferencedBundles(this.bundle)) {
120
- let entry = b.getMainEntry();
121
- let symbols = new Map();
122
- if (entry && !this.isAsyncBundle && entry.type === 'js') {
123
- this.externalAssets.add(entry);
124
- let usedSymbols = this.bundleGraph.getUsedSymbols(entry) || new Set();
125
- for (let s of usedSymbols) {
126
- // If the referenced bundle is ESM, and we are importing '*', use 'default' instead.
127
- // This matches the logic below in buildExportedSymbols.
128
- let imported = s;
129
- if (imported === '*' && b.env.outputFormat === 'esmodule') {
130
- imported = 'default';
131
- }
132
- symbols.set(imported, this.getSymbolResolution(entry, entry, s));
133
- }
134
- }
135
- this.externals.set((0, _utils().relativeBundlePath)(this.bundle, b), symbols);
114
+ for (let b of this.bundleGraph.getReferencedBundles(this.bundle, {
115
+ recursive: false
116
+ })) {
117
+ this.externals.set((0, _utils().relativeBundlePath)(this.bundle, b), new Map());
136
118
  }
137
119
  }
138
120
  let res = '';
@@ -232,7 +214,9 @@ class ScopeHoistingPackager {
232
214
  };
233
215
  }
234
216
  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');
217
+ let referencingBundles = this.bundleGraph.getReferencingBundles(bundle);
218
+ let hasHtmlReference = referencingBundles.some(b => b.type === 'html');
219
+ return this.useAsyncBundleRuntime && bundle.type === 'js' && bundle.bundleBehavior !== 'inline' && bundle.env.outputFormat === 'esmodule' && !bundle.env.isIsolated() && bundle.bundleBehavior !== 'isolated' && hasHtmlReference;
236
220
  }
237
221
  runWhenReady(bundle, codeToRun) {
238
222
  let deps = this.bundleGraph.getReferencedBundles(bundle).filter(b => this.shouldBundleQueue(b)).map(b => b.publicId);
@@ -256,8 +240,9 @@ class ScopeHoistingPackager {
256
240
  map
257
241
  }];
258
242
  });
259
- if (asset.meta.shouldWrap || this.isAsyncBundle || this.bundle.env.sourceType === 'script' || this.bundleGraph.isAssetReferenced(this.bundle, asset) || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.meta.shouldWrap && dep.specifierType !== 'url')) {
260
- if (!asset.meta.isConstantModule) {
243
+ if (asset.meta.shouldWrap || this.bundle.env.sourceType === 'script' || this.bundleGraph.isAssetReferenced(this.bundle, asset) || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.meta.shouldWrap && dep.specifierType !== 'url')) {
244
+ // Don't wrap constant "entry" modules _except_ if they are referenced by any lazy dependency
245
+ if (!asset.meta.isConstantModule || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.priority === 'lazy')) {
261
246
  this.wrappedAssets.add(asset.id);
262
247
  wrapped.push(asset);
263
248
  }
@@ -282,13 +267,14 @@ class ScopeHoistingPackager {
282
267
  return wrapped;
283
268
  }
284
269
  buildExportedSymbols() {
285
- if (this.isAsyncBundle || !this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') {
270
+ if (!this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') {
286
271
  return;
287
272
  }
288
273
 
289
274
  // TODO: handle ESM exports of wrapped entry assets...
290
275
  let entry = this.bundle.getMainEntry();
291
276
  if (entry && !this.wrappedAssets.has(entry.id)) {
277
+ let hasNamespace = entry.symbols.hasExportSymbol('*');
292
278
  for (let {
293
279
  asset,
294
280
  exportAs,
@@ -297,6 +283,12 @@ class ScopeHoistingPackager {
297
283
  } of this.bundleGraph.getExportedSymbols(entry)) {
298
284
  if (typeof symbol === 'string') {
299
285
  var _this$exportedSymbols, _entry$symbols$get2;
286
+ // If the module has a namespace (e.g. commonjs), and this is not an entry, only export the namespace
287
+ // as default, without individual exports. This mirrors the importing logic in addExternal, avoiding
288
+ // extra unused exports and potential for non-identifier export names.
289
+ if (hasNamespace && this.isAsyncBundle && exportAs !== '*') {
290
+ continue;
291
+ }
300
292
  let symbols = (_this$exportedSymbols = this.exportedSymbols.get(symbol === '*' ? (0, _nullthrows().default)((_entry$symbols$get2 = entry.symbols.get('*')) === null || _entry$symbols$get2 === void 0 ? void 0 : _entry$symbols$get2.local) : symbol)) === null || _this$exportedSymbols === void 0 ? void 0 : _this$exportedSymbols.exportAs;
301
293
  if (!symbols) {
302
294
  symbols = [];
@@ -331,8 +323,8 @@ class ScopeHoistingPackager {
331
323
  }
332
324
  }
333
325
  getTopLevelName(name) {
334
- name = name.replace(NON_ID_CONTINUE_RE, '');
335
- if (!ID_START_RE.test(name) || this.globalNames.has(name)) {
326
+ name = (0, _utils2.makeValidIdentifier)(name);
327
+ if (this.globalNames.has(name)) {
336
328
  name = '_' + name;
337
329
  }
338
330
  let count = this.topLevelNames.get(name);
@@ -344,7 +336,7 @@ class ScopeHoistingPackager {
344
336
  return name + count;
345
337
  }
346
338
  getPropertyAccess(obj, property) {
347
- if (IDENTIFIER_RE.test(property)) {
339
+ if ((0, _utils2.isValidIdentifier)(property)) {
348
340
  return `${obj}.${property}`;
349
341
  }
350
342
  return `${obj}[${JSON.stringify(property)}]`;
@@ -401,7 +393,7 @@ class ScopeHoistingPackager {
401
393
  code = code.replace('$parcel$filenameReplace', relPath);
402
394
  }
403
395
  let [depMap, replacements] = this.buildReplacements(asset, deps);
404
- let [prepend, prependLines, append] = this.buildAssetPrelude(asset, deps);
396
+ let [prepend, prependLines, append] = this.buildAssetPrelude(asset, deps, replacements);
405
397
  if (prependLines > 0) {
406
398
  sourceMap === null || sourceMap === void 0 || sourceMap.offsetLines(1, prependLines);
407
399
  code = prepend + code;
@@ -421,7 +413,6 @@ class ScopeHoistingPackager {
421
413
  let offset = 0;
422
414
  let columnStartIndex = 0;
423
415
  code = code.replace(REPLACEMENT_RE, (m, d, i) => {
424
- var _replacements$get;
425
416
  if (m === '\n') {
426
417
  columnStartIndex = i + offset + 1;
427
418
  lineCount++;
@@ -481,7 +472,7 @@ class ScopeHoistingPackager {
481
472
  }
482
473
 
483
474
  // If it wasn't a dependency, then it was an inline replacement (e.g. $id$import$foo -> $id$export$foo).
484
- let replacement = (_replacements$get = replacements.get(m)) !== null && _replacements$get !== void 0 ? _replacements$get : m;
475
+ let replacement = replacements.get(m) ?? m;
485
476
  if (sourceMap) {
486
477
  // Offset the source map columns for this line if the replacement was a different length.
487
478
  // This assumes that the match and replacement both do not contain any newlines.
@@ -543,6 +534,16 @@ ${code}
543
534
  if (!resolved) {
544
535
  continue;
545
536
  }
537
+
538
+ // Handle imports from other bundles in libraries.
539
+ if (this.bundle.env.isLibrary && !this.bundle.hasAsset(resolved)) {
540
+ let referencedBundle = this.bundleGraph.getReferencedBundle(dep, this.bundle);
541
+ if (referencedBundle && referencedBundle.getMainEntry() === resolved && referencedBundle.type === 'js' && !this.bundleGraph.isAssetReferenced(referencedBundle, resolved)) {
542
+ this.addExternal(dep, replacements, referencedBundle);
543
+ this.externalAssets.add(resolved);
544
+ continue;
545
+ }
546
+ }
546
547
  for (let [imported, {
547
548
  local
548
549
  }] of dep.symbols) {
@@ -575,7 +576,7 @@ ${code}
575
576
  }
576
577
  return [depMap, replacements];
577
578
  }
578
- addExternal(dep, replacements) {
579
+ addExternal(dep, replacements, referencedBundle) {
579
580
  if (this.bundle.env.outputFormat === 'global') {
580
581
  throw new (_diagnostic().default)({
581
582
  diagnostic: {
@@ -587,12 +588,16 @@ ${code}
587
588
  }
588
589
  });
589
590
  }
591
+ let specifier = dep.specifier;
592
+ if (referencedBundle) {
593
+ specifier = (0, _utils().relativeBundlePath)(this.bundle, referencedBundle);
594
+ }
590
595
 
591
596
  // Map of DependencySpecifier -> Map<ExportedSymbol, Identifier>>
592
- let external = this.externals.get(dep.specifier);
597
+ let external = this.externals.get(specifier);
593
598
  if (!external) {
594
599
  external = new Map();
595
- this.externals.set(dep.specifier, external);
600
+ this.externals.set(specifier, external);
596
601
  }
597
602
  for (let [imported, {
598
603
  local
@@ -609,7 +614,13 @@ ${code}
609
614
  if (this.bundle.env.outputFormat === 'commonjs') {
610
615
  renamed = external.get('*');
611
616
  if (!renamed) {
612
- renamed = this.getTopLevelName(`$${this.bundle.publicId}$${dep.specifier}`);
617
+ if (referencedBundle) {
618
+ var _entry$symbols$get3;
619
+ let entry = (0, _nullthrows().default)(referencedBundle.getMainEntry());
620
+ renamed = ((_entry$symbols$get3 = entry.symbols.get('*')) === null || _entry$symbols$get3 === void 0 ? void 0 : _entry$symbols$get3.local) ?? `$${String(entry.meta.id)}$exports`;
621
+ } else {
622
+ renamed = this.getTopLevelName(`$${this.bundle.publicId}$${specifier}`);
623
+ }
613
624
  external.set('*', renamed);
614
625
  }
615
626
  if (local !== '*' && replacements) {
@@ -617,40 +628,88 @@ ${code}
617
628
  if (imported === '*') {
618
629
  replacement = renamed;
619
630
  } else if (imported === 'default') {
620
- replacement = `($parcel$interopDefault(${renamed}))`;
621
- this.usedHelpers.add('$parcel$interopDefault');
631
+ let needsDefaultInterop = true;
632
+ if (referencedBundle) {
633
+ let entry = (0, _nullthrows().default)(referencedBundle.getMainEntry());
634
+ needsDefaultInterop = this.needsDefaultInterop(entry);
635
+ }
636
+ if (needsDefaultInterop) {
637
+ replacement = `($parcel$interopDefault(${renamed}))`;
638
+ this.usedHelpers.add('$parcel$interopDefault');
639
+ } else {
640
+ replacement = `${renamed}.default`;
641
+ }
622
642
  } else {
623
643
  replacement = this.getPropertyAccess(renamed, imported);
624
644
  }
625
645
  replacements.set(local, replacement);
626
646
  }
627
647
  } else {
648
+ let property;
649
+ if (referencedBundle) {
650
+ let entry = (0, _nullthrows().default)(referencedBundle.getMainEntry());
651
+ if (entry.symbols.hasExportSymbol('*')) {
652
+ // If importing * and the referenced module has a * export (e.g. CJS), use default instead.
653
+ // This mirrors the logic in buildExportedSymbols.
654
+ property = imported;
655
+ imported = (referencedBundle === null || referencedBundle === void 0 ? void 0 : referencedBundle.env.outputFormat) === 'esmodule' ? 'default' : '*';
656
+ } else {
657
+ if (imported === '*') {
658
+ let exportedSymbols = this.bundleGraph.getExportedSymbols(entry);
659
+ if (local === '*') {
660
+ // Re-export all symbols.
661
+ for (let exported of exportedSymbols) {
662
+ if (exported.symbol) {
663
+ external.set(exported.exportSymbol, exported.symbol);
664
+ }
665
+ }
666
+ continue;
667
+ }
668
+ }
669
+ renamed = this.bundleGraph.getSymbolResolution(entry, imported, this.bundle).symbol;
670
+ }
671
+ }
672
+
628
673
  // Rename the specifier so that multiple local imports of the same imported specifier
629
674
  // are deduplicated. We have to prefix the imported name with the bundle id so that
630
675
  // local variables do not shadow it.
631
- if (this.exportedSymbols.has(local)) {
632
- renamed = local;
633
- } else if (imported === 'default' || imported === '*') {
634
- renamed = this.getTopLevelName(`$${this.bundle.publicId}$${dep.specifier}`);
635
- } else {
636
- renamed = this.getTopLevelName(`$${this.bundle.publicId}$${imported}`);
676
+ if (!renamed) {
677
+ if (this.exportedSymbols.has(local)) {
678
+ renamed = local;
679
+ } else if (imported === 'default' || imported === '*') {
680
+ renamed = this.getTopLevelName(`$${this.bundle.publicId}$${specifier}`);
681
+ } else {
682
+ renamed = this.getTopLevelName(`$${this.bundle.publicId}$${imported}`);
683
+ }
637
684
  }
638
685
  external.set(imported, renamed);
639
686
  if (local !== '*' && replacements) {
640
- replacements.set(local, renamed);
687
+ let replacement = renamed;
688
+ if (property === '*') {
689
+ replacement = renamed;
690
+ } else if (property === 'default') {
691
+ replacement = `($parcel$interopDefault(${renamed}))`;
692
+ this.usedHelpers.add('$parcel$interopDefault');
693
+ } else if (property) {
694
+ replacement = this.getPropertyAccess(renamed, property);
695
+ }
696
+ replacements.set(local, replacement);
641
697
  }
642
698
  }
643
699
  }
644
700
  }
645
701
  isWrapped(resolved, parentAsset) {
646
702
  if (resolved.meta.isConstantModule) {
647
- (0, _assert().default)(this.bundle.hasAsset(resolved), 'Constant module not found in bundle');
703
+ if (!this.bundle.hasAsset(resolved)) {
704
+ throw new (_assert().AssertionError)({
705
+ message: `Constant module ${_path().default.relative(this.options.projectRoot, resolved.filePath)} referenced from ${_path().default.relative(this.options.projectRoot, parentAsset.filePath)} not found in bundle ${this.bundle.name}`
706
+ });
707
+ }
648
708
  return false;
649
709
  }
650
710
  return !this.bundle.hasAsset(resolved) && !this.externalAssets.has(resolved) || this.wrappedAssets.has(resolved.id) && resolved !== parentAsset;
651
711
  }
652
- getSymbolResolution(parentAsset, resolved, imported, dep) {
653
- var _resolvedAsset$symbol;
712
+ getSymbolResolution(parentAsset, resolved, imported, dep, replacements) {
654
713
  let {
655
714
  asset: resolvedAsset,
656
715
  exportSymbol,
@@ -696,9 +755,17 @@ ${code}
696
755
  // namespace export symbol.
697
756
  let assetId = resolvedAsset.meta.id;
698
757
  (0, _assert().default)(typeof assetId === 'string');
699
- let obj = isWrapped && (!dep || dep !== null && dep !== void 0 && dep.meta.shouldWrap) ?
700
- // Wrap in extra parenthesis to not change semantics, e.g.`new (parcelRequire("..."))()`.
701
- `(parcelRequire(${JSON.stringify(publicId)}))` : isWrapped && dep ? `$${publicId}` : ((_resolvedAsset$symbol = resolvedAsset.symbols.get('*')) === null || _resolvedAsset$symbol === void 0 ? void 0 : _resolvedAsset$symbol.local) || `$${assetId}$exports`;
758
+ let obj;
759
+ if (isWrapped && (!dep || dep !== null && dep !== void 0 && dep.meta.shouldWrap)) {
760
+ // Wrap in extra parenthesis to not change semantics, e.g.`new (parcelRequire("..."))()`.
761
+ obj = `(parcelRequire(${JSON.stringify(publicId)}))`;
762
+ } else if (isWrapped && dep) {
763
+ obj = `$${publicId}`;
764
+ } else {
765
+ var _resolvedAsset$symbol;
766
+ obj = ((_resolvedAsset$symbol = resolvedAsset.symbols.get('*')) === null || _resolvedAsset$symbol === void 0 ? void 0 : _resolvedAsset$symbol.local) || `$${assetId}$exports`;
767
+ obj = (replacements === null || replacements === void 0 ? void 0 : replacements.get(obj)) || obj;
768
+ }
702
769
  if (imported === '*' || exportSymbol === '*' || isDefaultInterop) {
703
770
  // Resolve to the namespace object if requested or this is a CJS default interop reqiure.
704
771
  if (parentAsset === resolvedAsset && this.wrappedAssets.has(resolvedAsset.id)) {
@@ -722,7 +789,7 @@ ${code}
722
789
  } else if (!symbol) {
723
790
  (0, _assert().default)(false, 'Asset was skipped or not found.');
724
791
  } else {
725
- return symbol;
792
+ return (replacements === null || replacements === void 0 ? void 0 : replacements.get(symbol)) || symbol;
726
793
  }
727
794
  }
728
795
  getHoistedParcelRequires(parentAsset, dep, resolved) {
@@ -749,7 +816,7 @@ ${code}
749
816
  }
750
817
  return [res, lineCount];
751
818
  }
752
- buildAssetPrelude(asset, deps) {
819
+ buildAssetPrelude(asset, deps, replacements) {
753
820
  let prepend = '';
754
821
  let prependLineCount = 0;
755
822
  let append = '';
@@ -767,13 +834,15 @@ ${code}
767
834
  // The one case where this isn't true is in ESM library entries, where the only
768
835
  // dependency on * is the entry dependency. In this case, we will use ESM exports
769
836
  // instead of the namespace object.
770
- usedSymbols.has('*') && (this.bundle.env.outputFormat !== 'esmodule' || !this.bundle.env.isLibrary || asset !== this.bundle.getMainEntry() || this.bundleGraph.getIncomingDependencies(asset).some(dep => !dep.isEntry && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep)).has('*'))) ||
837
+ usedSymbols.has('*') && (this.bundle.env.outputFormat !== 'esmodule' || !this.bundle.env.isLibrary || asset !== this.bundle.getMainEntry() || this.bundleGraph.getIncomingDependencies(asset).some(dep => !dep.isEntry && this.bundle.hasDependency(dep) && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep)).has('*'))) ||
771
838
  // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
772
839
  // we fallback on the namespace object.
773
840
  asset.symbols.hasExportSymbol('*') && [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s)) ||
774
841
  // If the exports has this asset's namespace (e.g. ESM output from CJS input),
775
842
  // include the namespace object for the default export.
776
- this.exportedSymbols.has(`$${assetId}$exports`);
843
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
844
+ // CommonJS library bundle entries always need a namespace.
845
+ this.bundle.env.isLibrary && this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry();
777
846
 
778
847
  // If the asset doesn't have static exports, should wrap, the namespace is used,
779
848
  // or we need default interop, then we need to synthesize a namespace object for
@@ -824,7 +893,7 @@ ${code}
824
893
  if (isWrapped || resolved.meta.staticExports === false || (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(resolved)).has('*') ||
825
894
  // an empty asset
826
895
  !resolved.meta.hasCJSExports && resolved.symbols.hasExportSymbol('*')) {
827
- let obj = this.getSymbolResolution(asset, resolved, '*', dep);
896
+ let obj = this.getSymbolResolution(asset, resolved, '*', dep, replacements);
828
897
  append += `$parcel$exportWildcard($${assetId}$exports, ${obj});\n`;
829
898
  this.usedHelpers.add('$parcel$exportWildcard');
830
899
  } else {
@@ -834,7 +903,7 @@ ${code}
834
903
  symbol === '__esModule') {
835
904
  continue;
836
905
  }
837
- let resolvedSymbol = this.getSymbolResolution(asset, resolved, symbol);
906
+ let resolvedSymbol = this.getSymbolResolution(asset, resolved, symbol, undefined, replacements);
838
907
  let get = this.buildFunctionExpression([], resolvedSymbol);
839
908
  let set = asset.meta.hasCJSExports ? ', ' + this.buildFunctionExpression(['v'], `${resolvedSymbol} = v`) : '';
840
909
  prepend += `$parcel$export($${assetId}$exports, ${JSON.stringify(symbol)}, ${get}${set});\n`;
@@ -873,7 +942,7 @@ ${code}
873
942
  // additional assignments after each mutation of the original binding.
874
943
  prepend += `\n${usedExports.map(exp => {
875
944
  var _asset$symbols$get2;
876
- let resolved = this.getSymbolResolution(asset, asset, exp);
945
+ let resolved = this.getSymbolResolution(asset, asset, exp, undefined, replacements);
877
946
  let get = this.buildFunctionExpression([], resolved);
878
947
  let isEsmExport = !!((_asset$symbols$get2 = asset.symbols.get(exp)) !== null && _asset$symbols$get2 !== void 0 && (_asset$symbols$get2 = _asset$symbols$get2.meta) !== null && _asset$symbols$get2 !== void 0 && _asset$symbols$get2.isEsm);
879
948
  let set = !isEsmExport && asset.meta.hasCJSExports ? ', ' + this.buildFunctionExpression(['v'], `${resolved} = v`) : '';
@@ -73,7 +73,7 @@
73
73
  localRequire,
74
74
  module,
75
75
  module.exports,
76
- this
76
+ globalObject
77
77
  );
78
78
  }
79
79
 
package/lib/index.js CHANGED
@@ -32,13 +32,6 @@ function _rust() {
32
32
  };
33
33
  return data;
34
34
  }
35
- function _path() {
36
- const data = _interopRequireDefault(require("path"));
37
- _path = function () {
38
- return data;
39
- };
40
- return data;
41
- }
42
35
  function _nullthrows() {
43
36
  const data = _interopRequireDefault(require("nullthrows"));
44
37
  _nullthrows = function () {
@@ -48,7 +41,7 @@ function _nullthrows() {
48
41
  }
49
42
  var _DevPackager = require("./DevPackager");
50
43
  var _ScopeHoistingPackager = require("./ScopeHoistingPackager");
51
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
44
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
52
45
  const CONFIG_SCHEMA = {
53
46
  type: 'object',
54
47
  properties: {
@@ -63,23 +56,29 @@ var _default = exports.default = new (_plugin().Packager)({
63
56
  config,
64
57
  options
65
58
  }) {
66
- var _pkg$contents$name, _pkg$contents, _pkg$contents$package;
67
- // Generate a name for the global parcelRequire function that is unique to this project.
68
- // This allows multiple parcel builds to coexist on the same page.
69
- let pkg = await config.getConfigFrom(_path().default.join(options.projectRoot, 'index'), ['package.json']);
59
+ var _packageName$contents, _conf$contents;
70
60
  let packageKey = '@parcel/packager-js';
71
- if (pkg !== null && pkg !== void 0 && pkg.contents[packageKey]) {
61
+ let conf = await config.getConfigFrom(options.projectRoot + '/index', [], {
62
+ packageKey
63
+ });
64
+ if (conf !== null && conf !== void 0 && conf.contents) {
72
65
  _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,
66
+ data: conf === null || conf === void 0 ? void 0 : conf.contents,
67
+ source: await options.inputFS.readFile(conf.filePath, 'utf8'),
68
+ filePath: conf.filePath,
76
69
  prependKey: `/${(0, _diagnostic().encodeJSONKeyComponent)(packageKey)}`
77
70
  }, packageKey, `Invalid config for ${packageKey}`);
78
71
  }
79
- let name = (_pkg$contents$name = pkg === null || pkg === 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 : '';
72
+
73
+ // Generate a name for the global parcelRequire function that is unique to this project.
74
+ // This allows multiple parcel builds to coexist on the same page.
75
+ let packageName = await config.getConfigFrom(options.projectRoot + '/index', [], {
76
+ packageKey: 'name'
77
+ });
78
+ let name = (packageName === null || packageName === void 0 || (_packageName$contents = packageName.contents) === null || _packageName$contents === void 0 ? void 0 : _packageName$contents.name) ?? '';
80
79
  return {
81
80
  parcelRequireName: 'parcelRequire' + (0, _rust().hashString)(name).slice(-4),
82
- unstable_asyncBundleRuntime: Boolean(pkg === null || pkg === void 0 || (_pkg$contents$package = pkg.contents[packageKey]) === null || _pkg$contents$package === void 0 ? void 0 : _pkg$contents$package.unstable_asyncBundleRuntime)
81
+ unstable_asyncBundleRuntime: Boolean(conf === null || conf === void 0 || (_conf$contents = conf.contents) === null || _conf$contents === void 0 ? void 0 : _conf$contents.unstable_asyncBundleRuntime)
83
82
  };
84
83
  },
85
84
  async package({
package/lib/utils.js CHANGED
@@ -4,6 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.getSpecifier = getSpecifier;
7
+ exports.isValidIdentifier = isValidIdentifier;
8
+ exports.makeValidIdentifier = makeValidIdentifier;
7
9
  exports.replaceScriptDependencies = replaceScriptDependencies;
8
10
  function _nullthrows() {
9
11
  const data = _interopRequireDefault(require("nullthrows"));
@@ -12,7 +14,7 @@ function _nullthrows() {
12
14
  };
13
15
  return data;
14
16
  }
15
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
18
  // This replaces __parcel__require__ references left by the transformer with
17
19
  // parcelRequire calls of the resolved asset id. This lets runtimes work within
18
20
  // script bundles, which must be outside the bundle wrapper so their variables are global.
@@ -48,4 +50,19 @@ function getSpecifier(dep) {
48
50
  return dep.meta.placeholder;
49
51
  }
50
52
  return dep.specifier;
53
+ }
54
+
55
+ // https://262.ecma-international.org/6.0/#sec-names-and-keywords
56
+ const IDENTIFIER_RE = /^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u;
57
+ const ID_START_RE = /^[$_\p{ID_Start}]/u;
58
+ const NON_ID_CONTINUE_RE = /[^$_\u200C\u200D\p{ID_Continue}]/gu;
59
+ function isValidIdentifier(id) {
60
+ return IDENTIFIER_RE.test(id);
61
+ }
62
+ function makeValidIdentifier(name) {
63
+ name = name.replace(NON_ID_CONTINUE_RE, '');
64
+ if (!ID_START_RE.test(name)) {
65
+ name = '_' + name;
66
+ }
67
+ return name;
51
68
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parcel/packager-js",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -16,18 +16,18 @@
16
16
  "main": "lib/index.js",
17
17
  "source": "src/index.js",
18
18
  "engines": {
19
- "node": ">= 12.0.0",
20
- "parcel": "^2.12.0"
19
+ "node": ">= 16.0.0",
20
+ "parcel": "^2.13.0"
21
21
  },
22
22
  "dependencies": {
23
- "@parcel/diagnostic": "2.12.0",
24
- "@parcel/plugin": "2.12.0",
25
- "@parcel/rust": "2.12.0",
23
+ "@parcel/diagnostic": "2.13.0",
24
+ "@parcel/plugin": "2.13.0",
25
+ "@parcel/rust": "2.13.0",
26
26
  "@parcel/source-map": "^2.1.1",
27
- "@parcel/types": "2.12.0",
28
- "@parcel/utils": "2.12.0",
27
+ "@parcel/types": "2.13.0",
28
+ "@parcel/utils": "2.13.0",
29
29
  "globals": "^13.2.0",
30
30
  "nullthrows": "^1.1.1"
31
31
  },
32
- "gitHead": "2059029ee91e5f03a273b0954d3e629d7375f986"
32
+ "gitHead": "a53f8f3ba1025c7ea8653e9719e0a61ef9717079"
33
33
  }
@@ -101,14 +101,14 @@ export class DevPackager {
101
101
  let dependencies = this.bundleGraph.getDependencies(asset);
102
102
  for (let dep of dependencies) {
103
103
  let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle);
104
+ let specifier = getSpecifier(dep);
104
105
  if (this.bundleGraph.isDependencySkipped(dep)) {
105
- deps[getSpecifier(dep)] = false;
106
+ deps[specifier] = false;
106
107
  } else if (resolved) {
107
- deps[getSpecifier(dep)] =
108
- this.bundleGraph.getAssetPublicId(resolved);
108
+ deps[specifier] = this.bundleGraph.getAssetPublicId(resolved);
109
109
  } else {
110
110
  // An external module - map placeholder to original specifier.
111
- deps[getSpecifier(dep)] = dep.specifier;
111
+ deps[specifier] = dep.specifier;
112
112
  }
113
113
  }
114
114
 
@@ -116,7 +116,7 @@ export class DevPackager {
116
116
  let output = code || '';
117
117
  wrapped +=
118
118
  JSON.stringify(this.bundleGraph.getAssetPublicId(asset)) +
119
- ':[function(require,module,exports) {\n' +
119
+ ':[function(require,module,exports,__globalThis) {\n' +
120
120
  output +
121
121
  '\n},';
122
122
  wrapped += JSON.stringify(deps);
@@ -3,6 +3,7 @@ import type {
3
3
  ScopeHoistingPackager,
4
4
  OutputFormat,
5
5
  } from './ScopeHoistingPackager';
6
+ import {isValidIdentifier} from './utils';
6
7
 
7
8
  export class ESMOutputFormat implements OutputFormat {
8
9
  packager: ScopeHoistingPackager;
@@ -25,6 +26,9 @@ export class ESMOutputFormat implements OutputFormat {
25
26
  namespaceSpecifier = `* as ${symbol}`;
26
27
  } else {
27
28
  let specifier = imported;
29
+ if (!isValidIdentifier(specifier)) {
30
+ specifier = JSON.stringify(specifier);
31
+ }
28
32
  if (symbol !== imported) {
29
33
  specifier += ` as ${symbol}`;
30
34
  }
@@ -93,7 +97,10 @@ export class ESMOutputFormat implements OutputFormat {
93
97
 
94
98
  for (let as of exportAs) {
95
99
  let specifier = local;
96
- if (exportAs !== local) {
100
+ if (as !== local) {
101
+ if (!isValidIdentifier(as)) {
102
+ as = JSON.stringify(as);
103
+ }
97
104
  specifier += ` as ${as}`;
98
105
  }
99
106
 
@@ -17,7 +17,7 @@ import {
17
17
  } from '@parcel/utils';
18
18
  import SourceMap from '@parcel/source-map';
19
19
  import nullthrows from 'nullthrows';
20
- import invariant from 'assert';
20
+ import invariant, {AssertionError} from 'assert';
21
21
  import ThrowableDiagnostic, {
22
22
  convertSourceLocationToHighlight,
23
23
  } from '@parcel/diagnostic';
@@ -28,13 +28,12 @@ import {ESMOutputFormat} from './ESMOutputFormat';
28
28
  import {CJSOutputFormat} from './CJSOutputFormat';
29
29
  import {GlobalOutputFormat} from './GlobalOutputFormat';
30
30
  import {prelude, helpers, bundleQueuePrelude, fnExpr} from './helpers';
31
- import {replaceScriptDependencies, getSpecifier} from './utils';
32
-
33
- // https://262.ecma-international.org/6.0/#sec-names-and-keywords
34
- const IDENTIFIER_RE = /^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u;
35
- const ID_START_RE = /^[$_\p{ID_Start}]/u;
36
- const NON_ID_CONTINUE_RE = /[^$_\u200C\u200D\p{ID_Continue}]/gu;
37
-
31
+ import {
32
+ replaceScriptDependencies,
33
+ getSpecifier,
34
+ isValidIdentifier,
35
+ makeValidIdentifier,
36
+ } from './utils';
38
37
  // General regex used to replace imports with the resolved code, references with resolutions,
39
38
  // and count the number of newlines in the file for source maps.
40
39
  const REPLACEMENT_RE =
@@ -134,25 +133,10 @@ export class ScopeHoistingPackager {
134
133
  this.bundle.env.isLibrary ||
135
134
  this.bundle.env.outputFormat === 'commonjs'
136
135
  ) {
137
- for (let b of this.bundleGraph.getReferencedBundles(this.bundle)) {
138
- let entry = b.getMainEntry();
139
- let symbols = new Map();
140
- if (entry && !this.isAsyncBundle && entry.type === 'js') {
141
- this.externalAssets.add(entry);
142
-
143
- let usedSymbols = this.bundleGraph.getUsedSymbols(entry) || new Set();
144
- for (let s of usedSymbols) {
145
- // If the referenced bundle is ESM, and we are importing '*', use 'default' instead.
146
- // This matches the logic below in buildExportedSymbols.
147
- let imported = s;
148
- if (imported === '*' && b.env.outputFormat === 'esmodule') {
149
- imported = 'default';
150
- }
151
- symbols.set(imported, this.getSymbolResolution(entry, entry, s));
152
- }
153
- }
154
-
155
- this.externals.set(relativeBundlePath(this.bundle, b), symbols);
136
+ for (let b of this.bundleGraph.getReferencedBundles(this.bundle, {
137
+ recursive: false,
138
+ })) {
139
+ this.externals.set(relativeBundlePath(this.bundle, b), new Map());
156
140
  }
157
141
  }
158
142
 
@@ -279,6 +263,9 @@ export class ScopeHoistingPackager {
279
263
  }
280
264
 
281
265
  shouldBundleQueue(bundle: NamedBundle): boolean {
266
+ let referencingBundles = this.bundleGraph.getReferencingBundles(bundle);
267
+ let hasHtmlReference = referencingBundles.some(b => b.type === 'html');
268
+
282
269
  return (
283
270
  this.useAsyncBundleRuntime &&
284
271
  bundle.type === 'js' &&
@@ -286,7 +273,7 @@ export class ScopeHoistingPackager {
286
273
  bundle.env.outputFormat === 'esmodule' &&
287
274
  !bundle.env.isIsolated() &&
288
275
  bundle.bundleBehavior !== 'isolated' &&
289
- !this.bundleGraph.hasParentBundleOfType(bundle, 'js')
276
+ hasHtmlReference
290
277
  );
291
278
  }
292
279
 
@@ -324,14 +311,19 @@ export class ScopeHoistingPackager {
324
311
 
325
312
  if (
326
313
  asset.meta.shouldWrap ||
327
- this.isAsyncBundle ||
328
314
  this.bundle.env.sourceType === 'script' ||
329
315
  this.bundleGraph.isAssetReferenced(this.bundle, asset) ||
330
316
  this.bundleGraph
331
317
  .getIncomingDependencies(asset)
332
318
  .some(dep => dep.meta.shouldWrap && dep.specifierType !== 'url')
333
319
  ) {
334
- if (!asset.meta.isConstantModule) {
320
+ // Don't wrap constant "entry" modules _except_ if they are referenced by any lazy dependency
321
+ if (
322
+ !asset.meta.isConstantModule ||
323
+ this.bundleGraph
324
+ .getIncomingDependencies(asset)
325
+ .some(dep => dep.priority === 'lazy')
326
+ ) {
335
327
  this.wrappedAssets.add(asset.id);
336
328
  wrapped.push(asset);
337
329
  }
@@ -361,7 +353,6 @@ export class ScopeHoistingPackager {
361
353
 
362
354
  buildExportedSymbols() {
363
355
  if (
364
- this.isAsyncBundle ||
365
356
  !this.bundle.env.isLibrary ||
366
357
  this.bundle.env.outputFormat !== 'esmodule'
367
358
  ) {
@@ -371,6 +362,8 @@ export class ScopeHoistingPackager {
371
362
  // TODO: handle ESM exports of wrapped entry assets...
372
363
  let entry = this.bundle.getMainEntry();
373
364
  if (entry && !this.wrappedAssets.has(entry.id)) {
365
+ let hasNamespace = entry.symbols.hasExportSymbol('*');
366
+
374
367
  for (let {
375
368
  asset,
376
369
  exportAs,
@@ -378,6 +371,13 @@ export class ScopeHoistingPackager {
378
371
  exportSymbol,
379
372
  } of this.bundleGraph.getExportedSymbols(entry)) {
380
373
  if (typeof symbol === 'string') {
374
+ // If the module has a namespace (e.g. commonjs), and this is not an entry, only export the namespace
375
+ // as default, without individual exports. This mirrors the importing logic in addExternal, avoiding
376
+ // extra unused exports and potential for non-identifier export names.
377
+ if (hasNamespace && this.isAsyncBundle && exportAs !== '*') {
378
+ continue;
379
+ }
380
+
381
381
  let symbols = this.exportedSymbols.get(
382
382
  symbol === '*' ? nullthrows(entry.symbols.get('*')?.local) : symbol,
383
383
  )?.exportAs;
@@ -418,8 +418,8 @@ export class ScopeHoistingPackager {
418
418
  }
419
419
 
420
420
  getTopLevelName(name: string): string {
421
- name = name.replace(NON_ID_CONTINUE_RE, '');
422
- if (!ID_START_RE.test(name) || this.globalNames.has(name)) {
421
+ name = makeValidIdentifier(name);
422
+ if (this.globalNames.has(name)) {
423
423
  name = '_' + name;
424
424
  }
425
425
 
@@ -434,7 +434,7 @@ export class ScopeHoistingPackager {
434
434
  }
435
435
 
436
436
  getPropertyAccess(obj: string, property: string): string {
437
- if (IDENTIFIER_RE.test(property)) {
437
+ if (isValidIdentifier(property)) {
438
438
  return `${obj}.${property}`;
439
439
  }
440
440
 
@@ -511,7 +511,11 @@ export class ScopeHoistingPackager {
511
511
  }
512
512
 
513
513
  let [depMap, replacements] = this.buildReplacements(asset, deps);
514
- let [prepend, prependLines, append] = this.buildAssetPrelude(asset, deps);
514
+ let [prepend, prependLines, append] = this.buildAssetPrelude(
515
+ asset,
516
+ deps,
517
+ replacements,
518
+ );
515
519
  if (prependLines > 0) {
516
520
  sourceMap?.offsetLines(1, prependLines);
517
521
  code = prepend + code;
@@ -703,6 +707,24 @@ ${code}
703
707
  continue;
704
708
  }
705
709
 
710
+ // Handle imports from other bundles in libraries.
711
+ if (this.bundle.env.isLibrary && !this.bundle.hasAsset(resolved)) {
712
+ let referencedBundle = this.bundleGraph.getReferencedBundle(
713
+ dep,
714
+ this.bundle,
715
+ );
716
+ if (
717
+ referencedBundle &&
718
+ referencedBundle.getMainEntry() === resolved &&
719
+ referencedBundle.type === 'js' &&
720
+ !this.bundleGraph.isAssetReferenced(referencedBundle, resolved)
721
+ ) {
722
+ this.addExternal(dep, replacements, referencedBundle);
723
+ this.externalAssets.add(resolved);
724
+ continue;
725
+ }
726
+ }
727
+
706
728
  for (let [imported, {local}] of dep.symbols) {
707
729
  if (local === '*') {
708
730
  continue;
@@ -748,7 +770,11 @@ ${code}
748
770
  return [depMap, replacements];
749
771
  }
750
772
 
751
- addExternal(dep: Dependency, replacements?: Map<string, string>) {
773
+ addExternal(
774
+ dep: Dependency,
775
+ replacements?: Map<string, string>,
776
+ referencedBundle?: NamedBundle,
777
+ ) {
752
778
  if (this.bundle.env.outputFormat === 'global') {
753
779
  throw new ThrowableDiagnostic({
754
780
  diagnostic: {
@@ -766,11 +792,16 @@ ${code}
766
792
  });
767
793
  }
768
794
 
795
+ let specifier = dep.specifier;
796
+ if (referencedBundle) {
797
+ specifier = relativeBundlePath(this.bundle, referencedBundle);
798
+ }
799
+
769
800
  // Map of DependencySpecifier -> Map<ExportedSymbol, Identifier>>
770
- let external = this.externals.get(dep.specifier);
801
+ let external = this.externals.get(specifier);
771
802
  if (!external) {
772
803
  external = new Map();
773
- this.externals.set(dep.specifier, external);
804
+ this.externals.set(specifier, external);
774
805
  }
775
806
 
776
807
  for (let [imported, {local}] of dep.symbols) {
@@ -786,9 +817,16 @@ ${code}
786
817
  if (this.bundle.env.outputFormat === 'commonjs') {
787
818
  renamed = external.get('*');
788
819
  if (!renamed) {
789
- renamed = this.getTopLevelName(
790
- `$${this.bundle.publicId}$${dep.specifier}`,
791
- );
820
+ if (referencedBundle) {
821
+ let entry = nullthrows(referencedBundle.getMainEntry());
822
+ renamed =
823
+ entry.symbols.get('*')?.local ??
824
+ `$${String(entry.meta.id)}$exports`;
825
+ } else {
826
+ renamed = this.getTopLevelName(
827
+ `$${this.bundle.publicId}$${specifier}`,
828
+ );
829
+ }
792
830
 
793
831
  external.set('*', renamed);
794
832
  }
@@ -798,8 +836,17 @@ ${code}
798
836
  if (imported === '*') {
799
837
  replacement = renamed;
800
838
  } else if (imported === 'default') {
801
- replacement = `($parcel$interopDefault(${renamed}))`;
802
- this.usedHelpers.add('$parcel$interopDefault');
839
+ let needsDefaultInterop = true;
840
+ if (referencedBundle) {
841
+ let entry = nullthrows(referencedBundle.getMainEntry());
842
+ needsDefaultInterop = this.needsDefaultInterop(entry);
843
+ }
844
+ if (needsDefaultInterop) {
845
+ replacement = `($parcel$interopDefault(${renamed}))`;
846
+ this.usedHelpers.add('$parcel$interopDefault');
847
+ } else {
848
+ replacement = `${renamed}.default`;
849
+ }
803
850
  } else {
804
851
  replacement = this.getPropertyAccess(renamed, imported);
805
852
  }
@@ -807,24 +854,67 @@ ${code}
807
854
  replacements.set(local, replacement);
808
855
  }
809
856
  } else {
857
+ let property;
858
+ if (referencedBundle) {
859
+ let entry = nullthrows(referencedBundle.getMainEntry());
860
+ if (entry.symbols.hasExportSymbol('*')) {
861
+ // If importing * and the referenced module has a * export (e.g. CJS), use default instead.
862
+ // This mirrors the logic in buildExportedSymbols.
863
+ property = imported;
864
+ imported =
865
+ referencedBundle?.env.outputFormat === 'esmodule'
866
+ ? 'default'
867
+ : '*';
868
+ } else {
869
+ if (imported === '*') {
870
+ let exportedSymbols = this.bundleGraph.getExportedSymbols(entry);
871
+ if (local === '*') {
872
+ // Re-export all symbols.
873
+ for (let exported of exportedSymbols) {
874
+ if (exported.symbol) {
875
+ external.set(exported.exportSymbol, exported.symbol);
876
+ }
877
+ }
878
+ continue;
879
+ }
880
+ }
881
+ renamed = this.bundleGraph.getSymbolResolution(
882
+ entry,
883
+ imported,
884
+ this.bundle,
885
+ ).symbol;
886
+ }
887
+ }
888
+
810
889
  // Rename the specifier so that multiple local imports of the same imported specifier
811
890
  // are deduplicated. We have to prefix the imported name with the bundle id so that
812
891
  // local variables do not shadow it.
813
- if (this.exportedSymbols.has(local)) {
814
- renamed = local;
815
- } else if (imported === 'default' || imported === '*') {
816
- renamed = this.getTopLevelName(
817
- `$${this.bundle.publicId}$${dep.specifier}`,
818
- );
819
- } else {
820
- renamed = this.getTopLevelName(
821
- `$${this.bundle.publicId}$${imported}`,
822
- );
892
+ if (!renamed) {
893
+ if (this.exportedSymbols.has(local)) {
894
+ renamed = local;
895
+ } else if (imported === 'default' || imported === '*') {
896
+ renamed = this.getTopLevelName(
897
+ `$${this.bundle.publicId}$${specifier}`,
898
+ );
899
+ } else {
900
+ renamed = this.getTopLevelName(
901
+ `$${this.bundle.publicId}$${imported}`,
902
+ );
903
+ }
823
904
  }
824
905
 
825
906
  external.set(imported, renamed);
826
907
  if (local !== '*' && replacements) {
827
- replacements.set(local, renamed);
908
+ let replacement = renamed;
909
+ if (property === '*') {
910
+ replacement = renamed;
911
+ } else if (property === 'default') {
912
+ replacement = `($parcel$interopDefault(${renamed}))`;
913
+ this.usedHelpers.add('$parcel$interopDefault');
914
+ } else if (property) {
915
+ replacement = this.getPropertyAccess(renamed, property);
916
+ }
917
+ replacements.set(local, replacement);
828
918
  }
829
919
  }
830
920
  }
@@ -832,10 +922,17 @@ ${code}
832
922
 
833
923
  isWrapped(resolved: Asset, parentAsset: Asset): boolean {
834
924
  if (resolved.meta.isConstantModule) {
835
- invariant(
836
- this.bundle.hasAsset(resolved),
837
- 'Constant module not found in bundle',
838
- );
925
+ if (!this.bundle.hasAsset(resolved)) {
926
+ throw new AssertionError({
927
+ message: `Constant module ${path.relative(
928
+ this.options.projectRoot,
929
+ resolved.filePath,
930
+ )} referenced from ${path.relative(
931
+ this.options.projectRoot,
932
+ parentAsset.filePath,
933
+ )} not found in bundle ${this.bundle.name}`,
934
+ });
935
+ }
839
936
  return false;
840
937
  }
841
938
  return (
@@ -849,6 +946,7 @@ ${code}
849
946
  resolved: Asset,
850
947
  imported: string,
851
948
  dep?: Dependency,
949
+ replacements?: Map<string, string>,
852
950
  ): string {
853
951
  let {
854
952
  asset: resolvedAsset,
@@ -922,13 +1020,16 @@ ${code}
922
1020
  // namespace export symbol.
923
1021
  let assetId = resolvedAsset.meta.id;
924
1022
  invariant(typeof assetId === 'string');
925
- let obj =
926
- isWrapped && (!dep || dep?.meta.shouldWrap)
927
- ? // Wrap in extra parenthesis to not change semantics, e.g.`new (parcelRequire("..."))()`.
928
- `(parcelRequire(${JSON.stringify(publicId)}))`
929
- : isWrapped && dep
930
- ? `$${publicId}`
931
- : resolvedAsset.symbols.get('*')?.local || `$${assetId}$exports`;
1023
+ let obj;
1024
+ if (isWrapped && (!dep || dep?.meta.shouldWrap)) {
1025
+ // Wrap in extra parenthesis to not change semantics, e.g.`new (parcelRequire("..."))()`.
1026
+ obj = `(parcelRequire(${JSON.stringify(publicId)}))`;
1027
+ } else if (isWrapped && dep) {
1028
+ obj = `$${publicId}`;
1029
+ } else {
1030
+ obj = resolvedAsset.symbols.get('*')?.local || `$${assetId}$exports`;
1031
+ obj = replacements?.get(obj) || obj;
1032
+ }
932
1033
 
933
1034
  if (imported === '*' || exportSymbol === '*' || isDefaultInterop) {
934
1035
  // Resolve to the namespace object if requested or this is a CJS default interop reqiure.
@@ -964,7 +1065,7 @@ ${code}
964
1065
  } else if (!symbol) {
965
1066
  invariant(false, 'Asset was skipped or not found.');
966
1067
  } else {
967
- return symbol;
1068
+ return replacements?.get(symbol) || symbol;
968
1069
  }
969
1070
  }
970
1071
 
@@ -1011,6 +1112,7 @@ ${code}
1011
1112
  buildAssetPrelude(
1012
1113
  asset: Asset,
1013
1114
  deps: Array<Dependency>,
1115
+ replacements: Map<string, string>,
1014
1116
  ): [string, number, string] {
1015
1117
  let prepend = '';
1016
1118
  let prependLineCount = 0;
@@ -1043,6 +1145,7 @@ ${code}
1043
1145
  .some(
1044
1146
  dep =>
1045
1147
  !dep.isEntry &&
1148
+ this.bundle.hasDependency(dep) &&
1046
1149
  nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1047
1150
  ))) ||
1048
1151
  // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
@@ -1051,7 +1154,11 @@ ${code}
1051
1154
  [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s))) ||
1052
1155
  // If the exports has this asset's namespace (e.g. ESM output from CJS input),
1053
1156
  // include the namespace object for the default export.
1054
- this.exportedSymbols.has(`$${assetId}$exports`);
1157
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
1158
+ // CommonJS library bundle entries always need a namespace.
1159
+ (this.bundle.env.isLibrary &&
1160
+ this.bundle.env.outputFormat === 'commonjs' &&
1161
+ asset === this.bundle.getMainEntry());
1055
1162
 
1056
1163
  // If the asset doesn't have static exports, should wrap, the namespace is used,
1057
1164
  // or we need default interop, then we need to synthesize a namespace object for
@@ -1118,7 +1225,13 @@ ${code}
1118
1225
  (!resolved.meta.hasCJSExports &&
1119
1226
  resolved.symbols.hasExportSymbol('*'))
1120
1227
  ) {
1121
- let obj = this.getSymbolResolution(asset, resolved, '*', dep);
1228
+ let obj = this.getSymbolResolution(
1229
+ asset,
1230
+ resolved,
1231
+ '*',
1232
+ dep,
1233
+ replacements,
1234
+ );
1122
1235
  append += `$parcel$exportWildcard($${assetId}$exports, ${obj});\n`;
1123
1236
  this.usedHelpers.add('$parcel$exportWildcard');
1124
1237
  } else {
@@ -1136,6 +1249,8 @@ ${code}
1136
1249
  asset,
1137
1250
  resolved,
1138
1251
  symbol,
1252
+ undefined,
1253
+ replacements,
1139
1254
  );
1140
1255
  let get = this.buildFunctionExpression([], resolvedSymbol);
1141
1256
  let set = asset.meta.hasCJSExports
@@ -1182,7 +1297,13 @@ ${code}
1182
1297
  // additional assignments after each mutation of the original binding.
1183
1298
  prepend += `\n${usedExports
1184
1299
  .map(exp => {
1185
- let resolved = this.getSymbolResolution(asset, asset, exp);
1300
+ let resolved = this.getSymbolResolution(
1301
+ asset,
1302
+ asset,
1303
+ exp,
1304
+ undefined,
1305
+ replacements,
1306
+ );
1186
1307
  let get = this.buildFunctionExpression([], resolved);
1187
1308
  let isEsmExport = !!asset.symbols.get(exp)?.meta?.isEsm;
1188
1309
  let set =
@@ -73,7 +73,7 @@
73
73
  localRequire,
74
74
  module,
75
75
  module.exports,
76
- this
76
+ globalObject
77
77
  );
78
78
  }
79
79
 
package/src/index.js CHANGED
@@ -10,7 +10,6 @@ import {
10
10
  } from '@parcel/utils';
11
11
  import {encodeJSONKeyComponent} from '@parcel/diagnostic';
12
12
  import {hashString} from '@parcel/rust';
13
- import path from 'path';
14
13
  import nullthrows from 'nullthrows';
15
14
  import {DevPackager} from './DevPackager';
16
15
  import {ScopeHoistingPackager} from './ScopeHoistingPackager';
@@ -32,22 +31,18 @@ const CONFIG_SCHEMA: SchemaEntity = {
32
31
 
33
32
  export default (new Packager({
34
33
  async loadConfig({config, options}): Promise<JSPackagerConfig> {
35
- // Generate a name for the global parcelRequire function that is unique to this project.
36
- // This allows multiple parcel builds to coexist on the same page.
37
- let pkg = await config.getConfigFrom(
38
- path.join(options.projectRoot, 'index'),
39
- ['package.json'],
40
- );
41
-
42
34
  let packageKey = '@parcel/packager-js';
35
+ let conf = await config.getConfigFrom(options.projectRoot + '/index', [], {
36
+ packageKey,
37
+ });
43
38
 
44
- if (pkg?.contents[packageKey]) {
39
+ if (conf?.contents) {
45
40
  validateSchema.diagnostic(
46
41
  CONFIG_SCHEMA,
47
42
  {
48
- data: pkg?.contents[packageKey],
49
- source: await options.inputFS.readFile(pkg.filePath, 'utf8'),
50
- filePath: pkg.filePath,
43
+ data: conf?.contents,
44
+ source: await options.inputFS.readFile(conf.filePath, 'utf8'),
45
+ filePath: conf.filePath,
51
46
  prependKey: `/${encodeJSONKeyComponent(packageKey)}`,
52
47
  },
53
48
  packageKey,
@@ -55,11 +50,21 @@ export default (new Packager({
55
50
  );
56
51
  }
57
52
 
58
- let name = pkg?.contents?.name ?? '';
53
+ // Generate a name for the global parcelRequire function that is unique to this project.
54
+ // This allows multiple parcel builds to coexist on the same page.
55
+ let packageName = await config.getConfigFrom(
56
+ options.projectRoot + '/index',
57
+ [],
58
+ {
59
+ packageKey: 'name',
60
+ },
61
+ );
62
+
63
+ let name = packageName?.contents?.name ?? '';
59
64
  return {
60
65
  parcelRequireName: 'parcelRequire' + hashString(name).slice(-4),
61
66
  unstable_asyncBundleRuntime: Boolean(
62
- pkg?.contents[packageKey]?.unstable_asyncBundleRuntime,
67
+ conf?.contents?.unstable_asyncBundleRuntime,
63
68
  ),
64
69
  };
65
70
  },
package/src/utils.js CHANGED
@@ -55,3 +55,20 @@ export function getSpecifier(dep: Dependency): string {
55
55
 
56
56
  return dep.specifier;
57
57
  }
58
+
59
+ // https://262.ecma-international.org/6.0/#sec-names-and-keywords
60
+ const IDENTIFIER_RE = /^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u;
61
+ const ID_START_RE = /^[$_\p{ID_Start}]/u;
62
+ const NON_ID_CONTINUE_RE = /[^$_\u200C\u200D\p{ID_Continue}]/gu;
63
+
64
+ export function isValidIdentifier(id: string): boolean {
65
+ return IDENTIFIER_RE.test(id);
66
+ }
67
+
68
+ export function makeValidIdentifier(name: string): string {
69
+ name = name.replace(NON_ID_CONTINUE_RE, '');
70
+ if (!ID_START_RE.test(name)) {
71
+ name = '_' + name;
72
+ }
73
+ return name;
74
+ }