@parcel/packager-js 2.0.0-dev.1424 → 2.0.0-dev.1425

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.
@@ -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);
@@ -61,11 +61,6 @@ 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
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
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
-
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 = '';
@@ -256,7 +238,7 @@ class ScopeHoistingPackager {
256
238
  map
257
239
  }];
258
240
  });
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')) {
241
+ 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')) {
260
242
  if (!asset.meta.isConstantModule) {
261
243
  this.wrappedAssets.add(asset.id);
262
244
  wrapped.push(asset);
@@ -282,13 +264,14 @@ class ScopeHoistingPackager {
282
264
  return wrapped;
283
265
  }
284
266
  buildExportedSymbols() {
285
- if (this.isAsyncBundle || !this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') {
267
+ if (!this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') {
286
268
  return;
287
269
  }
288
270
 
289
271
  // TODO: handle ESM exports of wrapped entry assets...
290
272
  let entry = this.bundle.getMainEntry();
291
273
  if (entry && !this.wrappedAssets.has(entry.id)) {
274
+ let hasNamespace = entry.symbols.hasExportSymbol('*');
292
275
  for (let {
293
276
  asset,
294
277
  exportAs,
@@ -297,6 +280,12 @@ class ScopeHoistingPackager {
297
280
  } of this.bundleGraph.getExportedSymbols(entry)) {
298
281
  if (typeof symbol === 'string') {
299
282
  var _this$exportedSymbols, _entry$symbols$get2;
283
+ // If the module has a namespace (e.g. commonjs), and this is not an entry, only export the namespace
284
+ // as default, without individual exports. This mirrors the importing logic in addExternal, avoiding
285
+ // extra unused exports and potential for non-identifier export names.
286
+ if (hasNamespace && this.isAsyncBundle && exportAs !== '*') {
287
+ continue;
288
+ }
300
289
  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
290
  if (!symbols) {
302
291
  symbols = [];
@@ -331,8 +320,8 @@ class ScopeHoistingPackager {
331
320
  }
332
321
  }
333
322
  getTopLevelName(name) {
334
- name = name.replace(NON_ID_CONTINUE_RE, '');
335
- if (!ID_START_RE.test(name) || this.globalNames.has(name)) {
323
+ name = (0, _utils2.makeValidIdentifier)(name);
324
+ if (this.globalNames.has(name)) {
336
325
  name = '_' + name;
337
326
  }
338
327
  let count = this.topLevelNames.get(name);
@@ -344,7 +333,7 @@ class ScopeHoistingPackager {
344
333
  return name + count;
345
334
  }
346
335
  getPropertyAccess(obj, property) {
347
- if (IDENTIFIER_RE.test(property)) {
336
+ if ((0, _utils2.isValidIdentifier)(property)) {
348
337
  return `${obj}.${property}`;
349
338
  }
350
339
  return `${obj}[${JSON.stringify(property)}]`;
@@ -401,7 +390,7 @@ class ScopeHoistingPackager {
401
390
  code = code.replace('$parcel$filenameReplace', relPath);
402
391
  }
403
392
  let [depMap, replacements] = this.buildReplacements(asset, deps);
404
- let [prepend, prependLines, append] = this.buildAssetPrelude(asset, deps);
393
+ let [prepend, prependLines, append] = this.buildAssetPrelude(asset, deps, replacements);
405
394
  if (prependLines > 0) {
406
395
  sourceMap === null || sourceMap === void 0 || sourceMap.offsetLines(1, prependLines);
407
396
  code = prepend + code;
@@ -543,6 +532,16 @@ ${code}
543
532
  if (!resolved) {
544
533
  continue;
545
534
  }
535
+
536
+ // Handle imports from other bundles in libraries.
537
+ if (this.bundle.env.isLibrary && !this.bundle.hasAsset(resolved)) {
538
+ let referencedBundle = this.bundleGraph.getReferencedBundle(dep, this.bundle);
539
+ if (referencedBundle && referencedBundle.getMainEntry() === resolved && referencedBundle.type === 'js' && !this.bundleGraph.isAssetReferenced(referencedBundle, resolved)) {
540
+ this.addExternal(dep, replacements, referencedBundle);
541
+ this.externalAssets.add(resolved);
542
+ continue;
543
+ }
544
+ }
546
545
  for (let [imported, {
547
546
  local
548
547
  }] of dep.symbols) {
@@ -575,7 +574,7 @@ ${code}
575
574
  }
576
575
  return [depMap, replacements];
577
576
  }
578
- addExternal(dep, replacements) {
577
+ addExternal(dep, replacements, referencedBundle) {
579
578
  if (this.bundle.env.outputFormat === 'global') {
580
579
  throw new (_diagnostic().default)({
581
580
  diagnostic: {
@@ -587,12 +586,16 @@ ${code}
587
586
  }
588
587
  });
589
588
  }
589
+ let specifier = dep.specifier;
590
+ if (referencedBundle) {
591
+ specifier = (0, _utils().relativeBundlePath)(this.bundle, referencedBundle);
592
+ }
590
593
 
591
594
  // Map of DependencySpecifier -> Map<ExportedSymbol, Identifier>>
592
- let external = this.externals.get(dep.specifier);
595
+ let external = this.externals.get(specifier);
593
596
  if (!external) {
594
597
  external = new Map();
595
- this.externals.set(dep.specifier, external);
598
+ this.externals.set(specifier, external);
596
599
  }
597
600
  for (let [imported, {
598
601
  local
@@ -609,7 +612,13 @@ ${code}
609
612
  if (this.bundle.env.outputFormat === 'commonjs') {
610
613
  renamed = external.get('*');
611
614
  if (!renamed) {
612
- renamed = this.getTopLevelName(`$${this.bundle.publicId}$${dep.specifier}`);
615
+ if (referencedBundle) {
616
+ var _entry$symbols$get$lo, _entry$symbols$get3;
617
+ let entry = (0, _nullthrows().default)(referencedBundle.getMainEntry());
618
+ renamed = (_entry$symbols$get$lo = (_entry$symbols$get3 = entry.symbols.get('*')) === null || _entry$symbols$get3 === void 0 ? void 0 : _entry$symbols$get3.local) !== null && _entry$symbols$get$lo !== void 0 ? _entry$symbols$get$lo : `$${String(entry.meta.id)}$exports`;
619
+ } else {
620
+ renamed = this.getTopLevelName(`$${this.bundle.publicId}$${specifier}`);
621
+ }
613
622
  external.set('*', renamed);
614
623
  }
615
624
  if (local !== '*' && replacements) {
@@ -625,19 +634,55 @@ ${code}
625
634
  replacements.set(local, replacement);
626
635
  }
627
636
  } else {
637
+ let property;
638
+ if (referencedBundle) {
639
+ let entry = (0, _nullthrows().default)(referencedBundle.getMainEntry());
640
+ if (entry.symbols.hasExportSymbol('*')) {
641
+ // If importing * and the referenced module has a * export (e.g. CJS), use default instead.
642
+ // This mirrors the logic in buildExportedSymbols.
643
+ property = imported;
644
+ imported = (referencedBundle === null || referencedBundle === void 0 ? void 0 : referencedBundle.env.outputFormat) === 'esmodule' ? 'default' : '*';
645
+ } else {
646
+ if (imported === '*') {
647
+ let exportedSymbols = this.bundleGraph.getExportedSymbols(entry);
648
+ if (local === '*') {
649
+ // Re-export all symbols.
650
+ for (let exported of exportedSymbols) {
651
+ if (exported.symbol) {
652
+ external.set(exported.exportSymbol, exported.symbol);
653
+ }
654
+ }
655
+ continue;
656
+ }
657
+ }
658
+ renamed = this.bundleGraph.getSymbolResolution(entry, imported, this.bundle).symbol;
659
+ }
660
+ }
661
+
628
662
  // Rename the specifier so that multiple local imports of the same imported specifier
629
663
  // are deduplicated. We have to prefix the imported name with the bundle id so that
630
664
  // 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}`);
665
+ if (!renamed) {
666
+ if (this.exportedSymbols.has(local)) {
667
+ renamed = local;
668
+ } else if (imported === 'default' || imported === '*') {
669
+ renamed = this.getTopLevelName(`$${this.bundle.publicId}$${specifier}`);
670
+ } else {
671
+ renamed = this.getTopLevelName(`$${this.bundle.publicId}$${imported}`);
672
+ }
637
673
  }
638
674
  external.set(imported, renamed);
639
675
  if (local !== '*' && replacements) {
640
- replacements.set(local, renamed);
676
+ let replacement = renamed;
677
+ if (property === '*') {
678
+ replacement = renamed;
679
+ } else if (property === 'default') {
680
+ replacement = `($parcel$interopDefault(${renamed}))`;
681
+ this.usedHelpers.add('$parcel$interopDefault');
682
+ } else if (property) {
683
+ replacement = this.getPropertyAccess(renamed, property);
684
+ }
685
+ replacements.set(local, replacement);
641
686
  }
642
687
  }
643
688
  }
@@ -649,8 +694,7 @@ ${code}
649
694
  }
650
695
  return !this.bundle.hasAsset(resolved) && !this.externalAssets.has(resolved) || this.wrappedAssets.has(resolved.id) && resolved !== parentAsset;
651
696
  }
652
- getSymbolResolution(parentAsset, resolved, imported, dep) {
653
- var _resolvedAsset$symbol;
697
+ getSymbolResolution(parentAsset, resolved, imported, dep, replacements) {
654
698
  let {
655
699
  asset: resolvedAsset,
656
700
  exportSymbol,
@@ -696,9 +740,17 @@ ${code}
696
740
  // namespace export symbol.
697
741
  let assetId = resolvedAsset.meta.id;
698
742
  (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`;
743
+ let obj;
744
+ if (isWrapped && (!dep || dep !== null && dep !== void 0 && dep.meta.shouldWrap)) {
745
+ // Wrap in extra parenthesis to not change semantics, e.g.`new (parcelRequire("..."))()`.
746
+ obj = `(parcelRequire(${JSON.stringify(publicId)}))`;
747
+ } else if (isWrapped && dep) {
748
+ obj = `$${publicId}`;
749
+ } else {
750
+ var _resolvedAsset$symbol;
751
+ obj = ((_resolvedAsset$symbol = resolvedAsset.symbols.get('*')) === null || _resolvedAsset$symbol === void 0 ? void 0 : _resolvedAsset$symbol.local) || `$${assetId}$exports`;
752
+ obj = (replacements === null || replacements === void 0 ? void 0 : replacements.get(obj)) || obj;
753
+ }
702
754
  if (imported === '*' || exportSymbol === '*' || isDefaultInterop) {
703
755
  // Resolve to the namespace object if requested or this is a CJS default interop reqiure.
704
756
  if (parentAsset === resolvedAsset && this.wrappedAssets.has(resolvedAsset.id)) {
@@ -722,7 +774,7 @@ ${code}
722
774
  } else if (!symbol) {
723
775
  (0, _assert().default)(false, 'Asset was skipped or not found.');
724
776
  } else {
725
- return symbol;
777
+ return (replacements === null || replacements === void 0 ? void 0 : replacements.get(symbol)) || symbol;
726
778
  }
727
779
  }
728
780
  getHoistedParcelRequires(parentAsset, dep, resolved) {
@@ -749,7 +801,7 @@ ${code}
749
801
  }
750
802
  return [res, lineCount];
751
803
  }
752
- buildAssetPrelude(asset, deps) {
804
+ buildAssetPrelude(asset, deps, replacements) {
753
805
  let prepend = '';
754
806
  let prependLineCount = 0;
755
807
  let append = '';
@@ -767,13 +819,15 @@ ${code}
767
819
  // The one case where this isn't true is in ESM library entries, where the only
768
820
  // dependency on * is the entry dependency. In this case, we will use ESM exports
769
821
  // 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('*'))) ||
822
+ 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
823
  // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
772
824
  // we fallback on the namespace object.
773
825
  asset.symbols.hasExportSymbol('*') && [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s)) ||
774
826
  // If the exports has this asset's namespace (e.g. ESM output from CJS input),
775
827
  // include the namespace object for the default export.
776
- this.exportedSymbols.has(`$${assetId}$exports`);
828
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
829
+ // CommonJS library bundle entries always need a namespace.
830
+ this.bundle.env.isLibrary && this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry();
777
831
 
778
832
  // If the asset doesn't have static exports, should wrap, the namespace is used,
779
833
  // or we need default interop, then we need to synthesize a namespace object for
@@ -824,7 +878,7 @@ ${code}
824
878
  if (isWrapped || resolved.meta.staticExports === false || (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(resolved)).has('*') ||
825
879
  // an empty asset
826
880
  !resolved.meta.hasCJSExports && resolved.symbols.hasExportSymbol('*')) {
827
- let obj = this.getSymbolResolution(asset, resolved, '*', dep);
881
+ let obj = this.getSymbolResolution(asset, resolved, '*', dep, replacements);
828
882
  append += `$parcel$exportWildcard($${assetId}$exports, ${obj});\n`;
829
883
  this.usedHelpers.add('$parcel$exportWildcard');
830
884
  } else {
@@ -834,7 +888,7 @@ ${code}
834
888
  symbol === '__esModule') {
835
889
  continue;
836
890
  }
837
- let resolvedSymbol = this.getSymbolResolution(asset, resolved, symbol);
891
+ let resolvedSymbol = this.getSymbolResolution(asset, resolved, symbol, undefined, replacements);
838
892
  let get = this.buildFunctionExpression([], resolvedSymbol);
839
893
  let set = asset.meta.hasCJSExports ? ', ' + this.buildFunctionExpression(['v'], `${resolvedSymbol} = v`) : '';
840
894
  prepend += `$parcel$export($${assetId}$exports, ${JSON.stringify(symbol)}, ${get}${set});\n`;
@@ -873,7 +927,7 @@ ${code}
873
927
  // additional assignments after each mutation of the original binding.
874
928
  prepend += `\n${usedExports.map(exp => {
875
929
  var _asset$symbols$get2;
876
- let resolved = this.getSymbolResolution(asset, asset, exp);
930
+ let resolved = this.getSymbolResolution(asset, asset, exp, undefined, replacements);
877
931
  let get = this.buildFunctionExpression([], resolved);
878
932
  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
933
  let set = !isEsmExport && asset.meta.hasCJSExports ? ', ' + this.buildFunctionExpression(['v'], `${resolved} = v`) : '';
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 () {
@@ -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, _packageName$contents2, _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$contents = packageName === null || packageName === void 0 || (_packageName$contents2 = packageName.contents) === null || _packageName$contents2 === void 0 ? void 0 : _packageName$contents2.name) !== null && _packageName$contents !== void 0 ? _packageName$contents : '';
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"));
@@ -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.0.0-dev.1424+7f6b4dbbc",
3
+ "version": "2.0.0-dev.1425+8b1749694",
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-dev.1422+7f6b4dbbc"
20
+ "parcel": "^2.0.0-dev.1423+8b1749694"
21
21
  },
22
22
  "dependencies": {
23
- "@parcel/diagnostic": "2.0.0-dev.1424+7f6b4dbbc",
24
- "@parcel/plugin": "2.0.0-dev.1424+7f6b4dbbc",
25
- "@parcel/rust": "2.12.1-dev.3238+7f6b4dbbc",
23
+ "@parcel/diagnostic": "2.0.0-dev.1425+8b1749694",
24
+ "@parcel/plugin": "2.0.0-dev.1425+8b1749694",
25
+ "@parcel/rust": "2.12.1-dev.3262+8b1749694",
26
26
  "@parcel/source-map": "^2.1.1",
27
- "@parcel/types": "2.0.0-dev.1424+7f6b4dbbc",
28
- "@parcel/utils": "2.0.0-dev.1424+7f6b4dbbc",
27
+ "@parcel/types": "2.0.0-dev.1425+8b1749694",
28
+ "@parcel/utils": "2.0.0-dev.1425+8b1749694",
29
29
  "globals": "^13.2.0",
30
30
  "nullthrows": "^1.1.1"
31
31
  },
32
- "gitHead": "7f6b4dbbc56a203e0fce8794856c03598c4f6708"
32
+ "gitHead": "8b1749694c0ef79cefdacad40bb90c869a93993a"
33
33
  }
@@ -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
 
@@ -28,12 +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;
31
+ import {
32
+ replaceScriptDependencies,
33
+ getSpecifier,
34
+ isValidIdentifier,
35
+ makeValidIdentifier,
36
+ } from './utils';
37
37
 
38
38
  // General regex used to replace imports with the resolved code, references with resolutions,
39
39
  // and count the number of newlines in the file for source maps.
@@ -134,25 +134,10 @@ export class ScopeHoistingPackager {
134
134
  this.bundle.env.isLibrary ||
135
135
  this.bundle.env.outputFormat === 'commonjs'
136
136
  ) {
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);
137
+ for (let b of this.bundleGraph.getReferencedBundles(this.bundle, {
138
+ recursive: false,
139
+ })) {
140
+ this.externals.set(relativeBundlePath(this.bundle, b), new Map());
156
141
  }
157
142
  }
158
143
 
@@ -324,7 +309,6 @@ export class ScopeHoistingPackager {
324
309
 
325
310
  if (
326
311
  asset.meta.shouldWrap ||
327
- this.isAsyncBundle ||
328
312
  this.bundle.env.sourceType === 'script' ||
329
313
  this.bundleGraph.isAssetReferenced(this.bundle, asset) ||
330
314
  this.bundleGraph
@@ -361,7 +345,6 @@ export class ScopeHoistingPackager {
361
345
 
362
346
  buildExportedSymbols() {
363
347
  if (
364
- this.isAsyncBundle ||
365
348
  !this.bundle.env.isLibrary ||
366
349
  this.bundle.env.outputFormat !== 'esmodule'
367
350
  ) {
@@ -371,6 +354,8 @@ export class ScopeHoistingPackager {
371
354
  // TODO: handle ESM exports of wrapped entry assets...
372
355
  let entry = this.bundle.getMainEntry();
373
356
  if (entry && !this.wrappedAssets.has(entry.id)) {
357
+ let hasNamespace = entry.symbols.hasExportSymbol('*');
358
+
374
359
  for (let {
375
360
  asset,
376
361
  exportAs,
@@ -378,6 +363,13 @@ export class ScopeHoistingPackager {
378
363
  exportSymbol,
379
364
  } of this.bundleGraph.getExportedSymbols(entry)) {
380
365
  if (typeof symbol === 'string') {
366
+ // If the module has a namespace (e.g. commonjs), and this is not an entry, only export the namespace
367
+ // as default, without individual exports. This mirrors the importing logic in addExternal, avoiding
368
+ // extra unused exports and potential for non-identifier export names.
369
+ if (hasNamespace && this.isAsyncBundle && exportAs !== '*') {
370
+ continue;
371
+ }
372
+
381
373
  let symbols = this.exportedSymbols.get(
382
374
  symbol === '*' ? nullthrows(entry.symbols.get('*')?.local) : symbol,
383
375
  )?.exportAs;
@@ -418,8 +410,8 @@ export class ScopeHoistingPackager {
418
410
  }
419
411
 
420
412
  getTopLevelName(name: string): string {
421
- name = name.replace(NON_ID_CONTINUE_RE, '');
422
- if (!ID_START_RE.test(name) || this.globalNames.has(name)) {
413
+ name = makeValidIdentifier(name);
414
+ if (this.globalNames.has(name)) {
423
415
  name = '_' + name;
424
416
  }
425
417
 
@@ -434,7 +426,7 @@ export class ScopeHoistingPackager {
434
426
  }
435
427
 
436
428
  getPropertyAccess(obj: string, property: string): string {
437
- if (IDENTIFIER_RE.test(property)) {
429
+ if (isValidIdentifier(property)) {
438
430
  return `${obj}.${property}`;
439
431
  }
440
432
 
@@ -511,7 +503,11 @@ export class ScopeHoistingPackager {
511
503
  }
512
504
 
513
505
  let [depMap, replacements] = this.buildReplacements(asset, deps);
514
- let [prepend, prependLines, append] = this.buildAssetPrelude(asset, deps);
506
+ let [prepend, prependLines, append] = this.buildAssetPrelude(
507
+ asset,
508
+ deps,
509
+ replacements,
510
+ );
515
511
  if (prependLines > 0) {
516
512
  sourceMap?.offsetLines(1, prependLines);
517
513
  code = prepend + code;
@@ -703,6 +699,24 @@ ${code}
703
699
  continue;
704
700
  }
705
701
 
702
+ // Handle imports from other bundles in libraries.
703
+ if (this.bundle.env.isLibrary && !this.bundle.hasAsset(resolved)) {
704
+ let referencedBundle = this.bundleGraph.getReferencedBundle(
705
+ dep,
706
+ this.bundle,
707
+ );
708
+ if (
709
+ referencedBundle &&
710
+ referencedBundle.getMainEntry() === resolved &&
711
+ referencedBundle.type === 'js' &&
712
+ !this.bundleGraph.isAssetReferenced(referencedBundle, resolved)
713
+ ) {
714
+ this.addExternal(dep, replacements, referencedBundle);
715
+ this.externalAssets.add(resolved);
716
+ continue;
717
+ }
718
+ }
719
+
706
720
  for (let [imported, {local}] of dep.symbols) {
707
721
  if (local === '*') {
708
722
  continue;
@@ -748,7 +762,11 @@ ${code}
748
762
  return [depMap, replacements];
749
763
  }
750
764
 
751
- addExternal(dep: Dependency, replacements?: Map<string, string>) {
765
+ addExternal(
766
+ dep: Dependency,
767
+ replacements?: Map<string, string>,
768
+ referencedBundle?: NamedBundle,
769
+ ) {
752
770
  if (this.bundle.env.outputFormat === 'global') {
753
771
  throw new ThrowableDiagnostic({
754
772
  diagnostic: {
@@ -766,11 +784,16 @@ ${code}
766
784
  });
767
785
  }
768
786
 
787
+ let specifier = dep.specifier;
788
+ if (referencedBundle) {
789
+ specifier = relativeBundlePath(this.bundle, referencedBundle);
790
+ }
791
+
769
792
  // Map of DependencySpecifier -> Map<ExportedSymbol, Identifier>>
770
- let external = this.externals.get(dep.specifier);
793
+ let external = this.externals.get(specifier);
771
794
  if (!external) {
772
795
  external = new Map();
773
- this.externals.set(dep.specifier, external);
796
+ this.externals.set(specifier, external);
774
797
  }
775
798
 
776
799
  for (let [imported, {local}] of dep.symbols) {
@@ -786,9 +809,16 @@ ${code}
786
809
  if (this.bundle.env.outputFormat === 'commonjs') {
787
810
  renamed = external.get('*');
788
811
  if (!renamed) {
789
- renamed = this.getTopLevelName(
790
- `$${this.bundle.publicId}$${dep.specifier}`,
791
- );
812
+ if (referencedBundle) {
813
+ let entry = nullthrows(referencedBundle.getMainEntry());
814
+ renamed =
815
+ entry.symbols.get('*')?.local ??
816
+ `$${String(entry.meta.id)}$exports`;
817
+ } else {
818
+ renamed = this.getTopLevelName(
819
+ `$${this.bundle.publicId}$${specifier}`,
820
+ );
821
+ }
792
822
 
793
823
  external.set('*', renamed);
794
824
  }
@@ -807,24 +837,67 @@ ${code}
807
837
  replacements.set(local, replacement);
808
838
  }
809
839
  } else {
840
+ let property;
841
+ if (referencedBundle) {
842
+ let entry = nullthrows(referencedBundle.getMainEntry());
843
+ if (entry.symbols.hasExportSymbol('*')) {
844
+ // If importing * and the referenced module has a * export (e.g. CJS), use default instead.
845
+ // This mirrors the logic in buildExportedSymbols.
846
+ property = imported;
847
+ imported =
848
+ referencedBundle?.env.outputFormat === 'esmodule'
849
+ ? 'default'
850
+ : '*';
851
+ } else {
852
+ if (imported === '*') {
853
+ let exportedSymbols = this.bundleGraph.getExportedSymbols(entry);
854
+ if (local === '*') {
855
+ // Re-export all symbols.
856
+ for (let exported of exportedSymbols) {
857
+ if (exported.symbol) {
858
+ external.set(exported.exportSymbol, exported.symbol);
859
+ }
860
+ }
861
+ continue;
862
+ }
863
+ }
864
+ renamed = this.bundleGraph.getSymbolResolution(
865
+ entry,
866
+ imported,
867
+ this.bundle,
868
+ ).symbol;
869
+ }
870
+ }
871
+
810
872
  // Rename the specifier so that multiple local imports of the same imported specifier
811
873
  // are deduplicated. We have to prefix the imported name with the bundle id so that
812
874
  // 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
- );
875
+ if (!renamed) {
876
+ if (this.exportedSymbols.has(local)) {
877
+ renamed = local;
878
+ } else if (imported === 'default' || imported === '*') {
879
+ renamed = this.getTopLevelName(
880
+ `$${this.bundle.publicId}$${specifier}`,
881
+ );
882
+ } else {
883
+ renamed = this.getTopLevelName(
884
+ `$${this.bundle.publicId}$${imported}`,
885
+ );
886
+ }
823
887
  }
824
888
 
825
889
  external.set(imported, renamed);
826
890
  if (local !== '*' && replacements) {
827
- replacements.set(local, renamed);
891
+ let replacement = renamed;
892
+ if (property === '*') {
893
+ replacement = renamed;
894
+ } else if (property === 'default') {
895
+ replacement = `($parcel$interopDefault(${renamed}))`;
896
+ this.usedHelpers.add('$parcel$interopDefault');
897
+ } else if (property) {
898
+ replacement = this.getPropertyAccess(renamed, property);
899
+ }
900
+ replacements.set(local, replacement);
828
901
  }
829
902
  }
830
903
  }
@@ -849,6 +922,7 @@ ${code}
849
922
  resolved: Asset,
850
923
  imported: string,
851
924
  dep?: Dependency,
925
+ replacements?: Map<string, string>,
852
926
  ): string {
853
927
  let {
854
928
  asset: resolvedAsset,
@@ -922,13 +996,16 @@ ${code}
922
996
  // namespace export symbol.
923
997
  let assetId = resolvedAsset.meta.id;
924
998
  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`;
999
+ let obj;
1000
+ if (isWrapped && (!dep || dep?.meta.shouldWrap)) {
1001
+ // Wrap in extra parenthesis to not change semantics, e.g.`new (parcelRequire("..."))()`.
1002
+ obj = `(parcelRequire(${JSON.stringify(publicId)}))`;
1003
+ } else if (isWrapped && dep) {
1004
+ obj = `$${publicId}`;
1005
+ } else {
1006
+ obj = resolvedAsset.symbols.get('*')?.local || `$${assetId}$exports`;
1007
+ obj = replacements?.get(obj) || obj;
1008
+ }
932
1009
 
933
1010
  if (imported === '*' || exportSymbol === '*' || isDefaultInterop) {
934
1011
  // Resolve to the namespace object if requested or this is a CJS default interop reqiure.
@@ -963,7 +1040,7 @@ ${code}
963
1040
  } else if (!symbol) {
964
1041
  invariant(false, 'Asset was skipped or not found.');
965
1042
  } else {
966
- return symbol;
1043
+ return replacements?.get(symbol) || symbol;
967
1044
  }
968
1045
  }
969
1046
 
@@ -1010,6 +1087,7 @@ ${code}
1010
1087
  buildAssetPrelude(
1011
1088
  asset: Asset,
1012
1089
  deps: Array<Dependency>,
1090
+ replacements: Map<string, string>,
1013
1091
  ): [string, number, string] {
1014
1092
  let prepend = '';
1015
1093
  let prependLineCount = 0;
@@ -1042,6 +1120,7 @@ ${code}
1042
1120
  .some(
1043
1121
  dep =>
1044
1122
  !dep.isEntry &&
1123
+ this.bundle.hasDependency(dep) &&
1045
1124
  nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1046
1125
  ))) ||
1047
1126
  // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
@@ -1050,7 +1129,11 @@ ${code}
1050
1129
  [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s))) ||
1051
1130
  // If the exports has this asset's namespace (e.g. ESM output from CJS input),
1052
1131
  // include the namespace object for the default export.
1053
- this.exportedSymbols.has(`$${assetId}$exports`);
1132
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
1133
+ // CommonJS library bundle entries always need a namespace.
1134
+ (this.bundle.env.isLibrary &&
1135
+ this.bundle.env.outputFormat === 'commonjs' &&
1136
+ asset === this.bundle.getMainEntry());
1054
1137
 
1055
1138
  // If the asset doesn't have static exports, should wrap, the namespace is used,
1056
1139
  // or we need default interop, then we need to synthesize a namespace object for
@@ -1117,7 +1200,13 @@ ${code}
1117
1200
  (!resolved.meta.hasCJSExports &&
1118
1201
  resolved.symbols.hasExportSymbol('*'))
1119
1202
  ) {
1120
- let obj = this.getSymbolResolution(asset, resolved, '*', dep);
1203
+ let obj = this.getSymbolResolution(
1204
+ asset,
1205
+ resolved,
1206
+ '*',
1207
+ dep,
1208
+ replacements,
1209
+ );
1121
1210
  append += `$parcel$exportWildcard($${assetId}$exports, ${obj});\n`;
1122
1211
  this.usedHelpers.add('$parcel$exportWildcard');
1123
1212
  } else {
@@ -1135,6 +1224,8 @@ ${code}
1135
1224
  asset,
1136
1225
  resolved,
1137
1226
  symbol,
1227
+ undefined,
1228
+ replacements,
1138
1229
  );
1139
1230
  let get = this.buildFunctionExpression([], resolvedSymbol);
1140
1231
  let set = asset.meta.hasCJSExports
@@ -1181,7 +1272,13 @@ ${code}
1181
1272
  // additional assignments after each mutation of the original binding.
1182
1273
  prepend += `\n${usedExports
1183
1274
  .map(exp => {
1184
- let resolved = this.getSymbolResolution(asset, asset, exp);
1275
+ let resolved = this.getSymbolResolution(
1276
+ asset,
1277
+ asset,
1278
+ exp,
1279
+ undefined,
1280
+ replacements,
1281
+ );
1185
1282
  let get = this.buildFunctionExpression([], resolved);
1186
1283
  let isEsmExport = !!asset.symbols.get(exp)?.meta?.isEsm;
1187
1284
  let set =
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
+ }