@atlaspack/core 2.12.1-dev.3401 → 2.12.1-dev.3443

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/lib/AssetGraph.js +1 -2
  2. package/lib/Atlaspack.js +25 -3
  3. package/lib/AtlaspackConfig.schema.js +10 -36
  4. package/lib/BundleGraph.js +59 -5
  5. package/lib/Dependency.js +46 -1
  6. package/lib/Environment.js +12 -2
  7. package/lib/PackagerRunner.js +3 -45
  8. package/lib/RequestTracker.js +112 -30
  9. package/lib/SymbolPropagation.js +1 -1
  10. package/lib/Transformation.js +1 -15
  11. package/lib/UncommittedAsset.js +4 -4
  12. package/lib/Validation.js +1 -13
  13. package/lib/applyRuntimes.js +96 -20
  14. package/lib/assetUtils.js +9 -3
  15. package/lib/atlaspack-v3/AtlaspackV3.js +6 -8
  16. package/lib/atlaspack-v3/fs.js +8 -1
  17. package/lib/atlaspack-v3/worker/compat.js +57 -0
  18. package/lib/atlaspack-v3/worker/worker.js +156 -1
  19. package/lib/public/BundleGraph.js +68 -0
  20. package/lib/requests/AssetGraphRequestRust.js +79 -12
  21. package/lib/requests/BundleGraphRequest.js +19 -0
  22. package/lib/requests/WriteBundleRequest.js +15 -15
  23. package/lib/requests/asset-graph-diff.js +128 -0
  24. package/lib/resolveOptions.js +15 -8
  25. package/lib/types.js +2 -1
  26. package/package.json +19 -17
  27. package/src/AssetGraph.js +1 -1
  28. package/src/Atlaspack.js +28 -6
  29. package/src/AtlaspackConfig.schema.js +13 -36
  30. package/src/BundleGraph.js +77 -1
  31. package/src/CommittedAsset.js +1 -1
  32. package/src/Dependency.js +50 -12
  33. package/src/Environment.js +13 -15
  34. package/src/PackagerRunner.js +5 -53
  35. package/src/RequestTracker.js +144 -38
  36. package/src/SymbolPropagation.js +5 -2
  37. package/src/Transformation.js +1 -9
  38. package/src/UncommittedAsset.js +6 -6
  39. package/src/Validation.js +1 -7
  40. package/src/applyRuntimes.js +86 -22
  41. package/src/assetUtils.js +12 -19
  42. package/src/atlaspack-v3/AtlaspackV3.js +8 -11
  43. package/src/atlaspack-v3/fs.js +8 -3
  44. package/src/atlaspack-v3/jsCallable.js +4 -0
  45. package/src/atlaspack-v3/worker/compat.js +82 -0
  46. package/src/atlaspack-v3/worker/worker.js +209 -2
  47. package/src/public/BundleGraph.js +106 -0
  48. package/src/requests/AssetGraphRequestRust.js +105 -17
  49. package/src/requests/BundleGraphRequest.js +18 -0
  50. package/src/requests/WriteBundleRequest.js +17 -23
  51. package/src/requests/asset-graph-diff.js +145 -0
  52. package/src/resolveOptions.js +12 -2
  53. package/src/types.js +10 -0
  54. package/test/AssetGraph.test.js +23 -9
  55. package/test/AtlaspackConfigRequest.test.js +0 -161
  56. package/test/BundleGraph.test.js +8 -3
  57. package/test/Dependency.test.js +21 -0
  58. package/test/Environment.test.js +16 -5
  59. package/test/InternalAsset.test.js +8 -2
  60. package/test/PublicAsset.test.js +6 -2
  61. package/test/PublicBundle.test.js +1 -0
  62. package/test/PublicMutableBundleGraph.test.js +9 -4
  63. package/test/RequestTracker.test.js +139 -2
  64. package/test/SymbolPropagation.test.js +1 -0
  65. package/test/TargetRequest.test.js +25 -25
  66. package/test/requests/WriteBundleRequest.test.js +132 -0
  67. package/lib/atlaspack-v3/plugins/Resolver.js +0 -12
  68. package/lib/atlaspack-v3/plugins/index.js +0 -16
  69. package/src/atlaspack-v3/plugins/Resolver.js +0 -9
  70. package/src/atlaspack-v3/plugins/index.js +0 -3
@@ -3,7 +3,9 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = exports.RequestGraph = void 0;
6
+ exports.RequestGraph = void 0;
7
+ exports.cleanUpOrphans = cleanUpOrphans;
8
+ exports.default = void 0;
7
9
  exports.getWatcherOptions = getWatcherOptions;
8
10
  exports.readAndDeserializeRequestGraph = readAndDeserializeRequestGraph;
9
11
  exports.requestTypes = exports.requestGraphEdgeTypes = void 0;
@@ -21,6 +23,13 @@ function _path2() {
21
23
  };
22
24
  return data;
23
25
  }
26
+ function _featureFlags() {
27
+ const data = require("@atlaspack/feature-flags");
28
+ _featureFlags = function () {
29
+ return data;
30
+ };
31
+ return data;
32
+ }
24
33
  function _graph() {
25
34
  const data = require("@atlaspack/graph");
26
35
  _graph = function () {
@@ -204,7 +213,7 @@ class RequestGraph extends _graph().ContentGraph {
204
213
  this.removeCachedRequestChunkForNode(nodeId);
205
214
  return nodeId;
206
215
  }
207
- removeNode(nodeId) {
216
+ removeNode(nodeId, removeOrphans = true) {
208
217
  this.invalidNodeIds.delete(nodeId);
209
218
  this.incompleteNodeIds.delete(nodeId);
210
219
  this.incompleteNodePromises.delete(nodeId);
@@ -222,7 +231,7 @@ class RequestGraph extends _graph().ContentGraph {
222
231
  configKeyNodes.delete(nodeId);
223
232
  }
224
233
  }
225
- return super.removeNode(nodeId);
234
+ return super.removeNode(nodeId, removeOrphans);
226
235
  }
227
236
  getRequestNode(nodeId) {
228
237
  let node = (0, _nullthrows().default)(this.getNode(nodeId));
@@ -456,18 +465,32 @@ class RequestGraph extends _graph().ContentGraph {
456
465
  return node;
457
466
  });
458
467
  }
459
- invalidateFileNameNode(node, filePath, matchNodes) {
468
+ invalidateFileNameNode(node, filePath, matchNodes, invalidateNode) {
460
469
  // If there is an edge between this file_name node and one of the original file nodes pointed to
461
470
  // by the original file_name node, and the matched node is inside the current directory, invalidate
462
471
  // all connected requests pointed to by the file node.
463
- let dirname = _path2().default.dirname((0, _projectPath.fromProjectPathRelative)(filePath));
472
+
464
473
  let nodeId = this.getNodeIdByContentKey(node.id);
465
- for (let matchNode of matchNodes) {
466
- let matchNodeId = this.getNodeIdByContentKey(matchNode.id);
467
- if (this.hasEdge(nodeId, matchNodeId, requestGraphEdgeTypes.invalidated_by_create_above) && (0, _utils().isDirectoryInside)((0, _projectPath.fromProjectPathRelative)((0, _projectPath.toProjectPathUnsafe)(matchNode.id)), dirname)) {
468
- let connectedNodes = this.getNodeIdsConnectedTo(matchNodeId, requestGraphEdgeTypes.invalidated_by_create);
474
+ let dirname = _path2().default.dirname((0, _projectPath.fromProjectPathRelative)(filePath));
475
+ if ((0, _featureFlags().getFeatureFlag)('fixQuadraticCacheInvalidation')) {
476
+ while (dirname !== '/') {
477
+ if (!this.hasContentKey(dirname)) break;
478
+ const matchNodeId = this.getNodeIdByContentKey(dirname);
479
+ if (!this.hasEdge(nodeId, matchNodeId, requestGraphEdgeTypes.invalidated_by_create_above)) break;
480
+ const connectedNodes = this.getNodeIdsConnectedTo(matchNodeId, requestGraphEdgeTypes.invalidated_by_create);
469
481
  for (let connectedNode of connectedNodes) {
470
- this.invalidateNode(connectedNode, _constants.FILE_CREATE);
482
+ invalidateNode(connectedNode, _constants.FILE_CREATE);
483
+ }
484
+ dirname = _path2().default.dirname(dirname);
485
+ }
486
+ } else {
487
+ for (let matchNode of matchNodes) {
488
+ let matchNodeId = this.getNodeIdByContentKey(matchNode.id);
489
+ if (this.hasEdge(nodeId, matchNodeId, requestGraphEdgeTypes.invalidated_by_create_above) && (0, _utils().isDirectoryInside)((0, _projectPath.fromProjectPathRelative)((0, _projectPath.toProjectPathUnsafe)(matchNode.id)), dirname)) {
490
+ let connectedNodes = this.getNodeIdsConnectedTo(matchNodeId, requestGraphEdgeTypes.invalidated_by_create);
491
+ for (let connectedNode of connectedNodes) {
492
+ this.invalidateNode(connectedNode, _constants.FILE_CREATE);
493
+ }
471
494
  }
472
495
  }
473
496
  }
@@ -480,7 +503,7 @@ class RequestGraph extends _graph().ContentGraph {
480
503
  if (this.hasEdge(nodeId, this.getNodeIdByContentKey(contentKey), requestGraphEdgeTypes.dirname)) {
481
504
  let parent = (0, _nullthrows().default)(this.getNodeByContentKey(contentKey));
482
505
  (0, _assert().default)(parent.type === FILE_NAME);
483
- this.invalidateFileNameNode(parent, (0, _projectPath.toProjectPathUnsafe)(dirname), matchNodes);
506
+ this.invalidateFileNameNode(parent, (0, _projectPath.toProjectPathUnsafe)(dirname), matchNodes, invalidateNode);
484
507
  }
485
508
  }
486
509
  }
@@ -489,11 +512,38 @@ class RequestGraph extends _graph().ContentGraph {
489
512
  let count = 0;
490
513
  let predictedTime = 0;
491
514
  let startTime = Date.now();
515
+ const enableOptimization = (0, _featureFlags().getFeatureFlag)('fixQuadraticCacheInvalidation');
516
+ const removeOrphans = !enableOptimization;
517
+ const invalidatedNodes = new Set();
518
+ const invalidateNode = (nodeId, reason) => {
519
+ if (enableOptimization && invalidatedNodes.has(nodeId)) {
520
+ return;
521
+ }
522
+ invalidatedNodes.add(nodeId);
523
+ this.invalidateNode(nodeId, reason);
524
+ };
525
+ const aboveCache = new Map();
526
+ const getAbove = fileNameNodeId => {
527
+ const cachedResult = aboveCache.get(fileNameNodeId);
528
+ if (enableOptimization && cachedResult) {
529
+ return cachedResult;
530
+ }
531
+ let above = [];
532
+ const children = this.getNodeIdsConnectedTo(fileNameNodeId, requestGraphEdgeTypes.invalidated_by_create_above);
533
+ for (const nodeId of children) {
534
+ let node = (0, _nullthrows().default)(this.getNode(nodeId));
535
+ if (node.type === FILE) {
536
+ above.push(node);
537
+ }
538
+ }
539
+ aboveCache.set(fileNameNodeId, above);
540
+ return above;
541
+ };
492
542
  for (let {
493
543
  path: _path,
494
544
  type
495
545
  } of events) {
496
- if (++count === 256) {
546
+ if (!enableOptimization && process.env.ATLASPACK_DISABLE_CACHE_TIMEOUT !== 'true' && ++count === 256) {
497
547
  let duration = Date.now() - startTime;
498
548
  predictedTime = duration * (events.length >> 8);
499
549
  if (predictedTime > threshold) {
@@ -540,13 +590,13 @@ class RequestGraph extends _graph().ContentGraph {
540
590
  let nodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update);
541
591
  for (let connectedNode of nodes) {
542
592
  didInvalidate = true;
543
- this.invalidateNode(connectedNode, _constants.FILE_UPDATE);
593
+ invalidateNode(connectedNode, _constants.FILE_UPDATE);
544
594
  }
545
595
  if (type === 'create') {
546
596
  let nodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_create);
547
597
  for (let connectedNode of nodes) {
548
598
  didInvalidate = true;
549
- this.invalidateNode(connectedNode, _constants.FILE_CREATE);
599
+ invalidateNode(connectedNode, _constants.FILE_CREATE);
550
600
  }
551
601
  }
552
602
  } else if (type === 'create') {
@@ -556,17 +606,10 @@ class RequestGraph extends _graph().ContentGraph {
556
606
  let fileNameNodeId = this.getNodeIdByContentKey('file_name:' + basename);
557
607
 
558
608
  // Find potential file nodes to be invalidated if this file name pattern matches
559
- let above = [];
560
- for (const nodeId of this.getNodeIdsConnectedTo(fileNameNodeId, requestGraphEdgeTypes.invalidated_by_create_above)) {
561
- let node = (0, _nullthrows().default)(this.getNode(nodeId));
562
- // these might also be `glob` nodes which get handled below, we only care about files here.
563
- if (node.type === FILE) {
564
- above.push(node);
565
- }
566
- }
609
+ let above = getAbove(fileNameNodeId);
567
610
  if (above.length > 0) {
568
611
  didInvalidate = true;
569
- this.invalidateFileNameNode(fileNameNode, _filePath, above);
612
+ this.invalidateFileNameNode(fileNameNode, _filePath, above, invalidateNode);
570
613
  }
571
614
  }
572
615
  for (let globeNodeId of this.globNodeIds) {
@@ -576,7 +619,7 @@ class RequestGraph extends _graph().ContentGraph {
576
619
  let connectedNodes = this.getNodeIdsConnectedTo(globeNodeId, requestGraphEdgeTypes.invalidated_by_create);
577
620
  for (let connectedNode of connectedNodes) {
578
621
  didInvalidate = true;
579
- this.invalidateNode(connectedNode, _constants.FILE_CREATE);
622
+ invalidateNode(connectedNode, _constants.FILE_CREATE);
580
623
  }
581
624
  }
582
625
  }
@@ -584,13 +627,13 @@ class RequestGraph extends _graph().ContentGraph {
584
627
  let nodeId = this.getNodeIdByContentKey(filePath);
585
628
  for (let connectedNode of this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_delete)) {
586
629
  didInvalidate = true;
587
- this.invalidateNode(connectedNode, _constants.FILE_DELETE);
630
+ invalidateNode(connectedNode, _constants.FILE_DELETE);
588
631
  }
589
632
 
590
633
  // Delete the file node since it doesn't exist anymore.
591
634
  // This ensures that files that don't exist aren't sent
592
635
  // to requests as invalidations for future requests.
593
- this.removeNode(nodeId);
636
+ this.removeNode(nodeId, removeOrphans);
594
637
  }
595
638
  let configKeyNodes = this.configKeyNodes.get(_filePath);
596
639
  if (configKeyNodes && (type === 'delete' || type === 'update')) {
@@ -604,14 +647,17 @@ class RequestGraph extends _graph().ContentGraph {
604
647
  }
605
648
  if (isInvalid) {
606
649
  for (let connectedNode of this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update)) {
607
- this.invalidateNode(connectedNode, type === 'delete' ? _constants.FILE_DELETE : _constants.FILE_UPDATE);
650
+ invalidateNode(connectedNode, type === 'delete' ? _constants.FILE_DELETE : _constants.FILE_UPDATE);
608
651
  }
609
652
  didInvalidate = true;
610
- this.removeNode(nodeId);
653
+ this.removeNode(nodeId, removeOrphans);
611
654
  }
612
655
  }
613
656
  }
614
657
  }
658
+ if ((0, _featureFlags().getFeatureFlag)('fixQuadraticCacheInvalidation')) {
659
+ cleanUpOrphans(this);
660
+ }
615
661
  let duration = Date.now() - startTime;
616
662
  _logger().default.verbose({
617
663
  origin: '@atlaspack/core',
@@ -619,7 +665,9 @@ class RequestGraph extends _graph().ContentGraph {
619
665
  meta: {
620
666
  trackableEvent: 'fsevent_response_time',
621
667
  duration,
622
- predictedTime
668
+ predictedTime,
669
+ numberOfEvents: events.length,
670
+ numberOfInvalidatedNodes: invalidatedNodes.size
623
671
  }
624
672
  });
625
673
  return didInvalidate && this.invalidNodeIds.size > 0;
@@ -1022,7 +1070,16 @@ async function loadRequestGraph(options) {
1022
1070
  let cacheKey = getCacheKey(options);
1023
1071
  let requestGraphKey = `requestGraph-${cacheKey}`;
1024
1072
  let timeout;
1025
- const snapshotPath = _path2().default.join(options.cacheDir, `snapshot-${cacheKey}` + '.txt');
1073
+ const snapshotKey = `snapshot-${cacheKey}`;
1074
+ const snapshotPath = _path2().default.join(options.cacheDir, snapshotKey + '.txt');
1075
+ _logger().default.verbose({
1076
+ origin: '@atlaspack/core',
1077
+ message: 'Loading request graph',
1078
+ meta: {
1079
+ cacheKey,
1080
+ snapshotKey
1081
+ }
1082
+ });
1026
1083
  if (await options.cache.hasLargeBlob(requestGraphKey)) {
1027
1084
  try {
1028
1085
  let {
@@ -1062,6 +1119,14 @@ async function loadRequestGraph(options) {
1062
1119
  return new RequestGraph();
1063
1120
  }
1064
1121
  }
1122
+ _logger().default.verbose({
1123
+ origin: '@atlaspack/core',
1124
+ message: 'Cache entry for request tracker was not found, initializing a clean cache.',
1125
+ meta: {
1126
+ cacheKey,
1127
+ snapshotKey
1128
+ }
1129
+ });
1065
1130
  return new RequestGraph();
1066
1131
  }
1067
1132
  function logErrorOnBailout(options, snapshotPath, e) {
@@ -1086,4 +1151,21 @@ function logErrorOnBailout(options, snapshotPath, e) {
1086
1151
  }
1087
1152
  });
1088
1153
  }
1154
+ }
1155
+ function cleanUpOrphans(graph) {
1156
+ if (graph.rootNodeId == null) {
1157
+ return [];
1158
+ }
1159
+ const reachableNodes = new Set();
1160
+ graph.traverse(nodeId => {
1161
+ reachableNodes.add(nodeId);
1162
+ });
1163
+ const removedNodeIds = [];
1164
+ graph.nodes.forEach((_node, nodeId) => {
1165
+ if (!reachableNodes.has(nodeId)) {
1166
+ removedNodeIds.push(nodeId);
1167
+ graph.removeNode(nodeId);
1168
+ }
1169
+ });
1170
+ return removedNodeIds;
1089
1171
  }
@@ -108,7 +108,7 @@ function propagateSymbols({
108
108
  namespaceReexportedSymbols.add('*');
109
109
  } else {
110
110
  for (let incomingDep of incomingDeps) {
111
- if (incomingDep.value.symbols == null) {
111
+ if (incomingDep.value.symbols == null || incomingDep.value.priority === _types.Priority.conditional) {
112
112
  if (incomingDep.value.sourceAssetId == null) {
113
113
  // The root dependency on non-library builds
114
114
  isEntry = true;
@@ -46,13 +46,6 @@ function _utils() {
46
46
  };
47
47
  return data;
48
48
  }
49
- function _rust() {
50
- const data = require("@atlaspack/rust");
51
- _rust = function () {
52
- return data;
53
- };
54
- return data;
55
- }
56
49
  var _Dependency = require("./Dependency");
57
50
  var _AtlaspackConfig = _interopRequireDefault(require("./AtlaspackConfig"));
58
51
  var _PathRequest = require("./requests/PathRequest");
@@ -181,16 +174,9 @@ class Transformation {
181
174
 
182
175
  // Prefer `isSource` originating from the AssetRequest.
183
176
 
184
- // If the transformer request passed code, use a hash in addition
185
- // to the filename as the base for the id to ensure it is unique.
186
- let idBase = (0, _projectPath.fromProjectPathRelative)(filePath);
187
- if (code != null) {
188
- idBase += (0, _rust().hashString)(code);
189
- }
190
177
  return new _UncommittedAsset.default({
191
- idBase,
192
178
  value: (0, _assetUtils.createAsset)(this.options.projectRoot, {
193
- idBase,
179
+ code,
194
180
  filePath,
195
181
  isSource: isSourceOverride ?? summarizedIsSource,
196
182
  type: _path().default.extname((0, _projectPath.fromProjectPathRelative)(filePath)).slice(1),
@@ -56,7 +56,7 @@ class UncommittedAsset {
56
56
  mapBuffer,
57
57
  ast,
58
58
  isASTDirty,
59
- idBase,
59
+ code,
60
60
  invalidations
61
61
  }) {
62
62
  this.value = value;
@@ -65,7 +65,7 @@ class UncommittedAsset {
65
65
  this.mapBuffer = mapBuffer;
66
66
  this.ast = ast;
67
67
  this.isASTDirty = isASTDirty || false;
68
- this.idBase = idBase;
68
+ this.code = code;
69
69
  this.invalidations = invalidations || (0, _utils2.createInvalidations)();
70
70
  }
71
71
 
@@ -289,7 +289,7 @@ class UncommittedAsset {
289
289
  let content = result.content ?? null;
290
290
  let asset = new UncommittedAsset({
291
291
  value: (0, _assetUtils.createAsset)(this.options.projectRoot, {
292
- idBase: this.idBase,
292
+ code: this.code,
293
293
  filePath: this.value.filePath,
294
294
  type: result.type,
295
295
  bundleBehavior: result.bundleBehavior ?? (this.value.bundleBehavior == null ? null : _types.BundleBehaviorNames[this.value.bundleBehavior]),
@@ -323,7 +323,7 @@ class UncommittedAsset {
323
323
  ast: result.ast,
324
324
  isASTDirty: result.ast === this.ast ? this.isASTDirty : true,
325
325
  mapBuffer: result.map ? result.map.toBuffer() : null,
326
- idBase: this.idBase,
326
+ code: this.code,
327
327
  invalidations: this.invalidations
328
328
  });
329
329
  let dependencies = result.dependencies;
package/lib/Validation.js CHANGED
@@ -46,13 +46,6 @@ function _profiler() {
46
46
  };
47
47
  return data;
48
48
  }
49
- function _rust() {
50
- const data = require("@atlaspack/rust");
51
- _rust = function () {
52
- return data;
53
- };
54
- return data;
55
- }
56
49
  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); }
57
50
  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; }
58
51
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -188,14 +181,9 @@ class Validation {
188
181
  } = await (0, _summarizeRequest.default)(this.options.inputFS, {
189
182
  filePath: (0, _projectPath.fromProjectPath)(this.options.projectRoot, request.filePath)
190
183
  });
191
-
192
- // If the transformer request passed code rather than a filename,
193
- // use a hash as the base for the id to ensure it is unique.
194
- let idBase = code != null ? (0, _rust().hashString)(code) : (0, _projectPath.fromProjectPathRelative)(filePath);
195
184
  return new _UncommittedAsset.default({
196
- idBase,
197
185
  value: (0, _assetUtils.createAsset)(this.options.projectRoot, {
198
- idBase,
186
+ code,
199
187
  filePath: filePath,
200
188
  isSource,
201
189
  type: _path().default.extname((0, _projectPath.fromProjectPathRelative)(filePath)).slice(1),
@@ -62,6 +62,13 @@ function _profiler() {
62
62
  };
63
63
  return data;
64
64
  }
65
+ function _utils() {
66
+ const data = require("@atlaspack/utils");
67
+ _utils = function () {
68
+ return data;
69
+ };
70
+ return data;
71
+ }
65
72
  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); }
66
73
  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; }
67
74
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -81,6 +88,15 @@ function nameRuntimeBundle(bundle, siblingBundle) {
81
88
  bundle.name = name;
82
89
  bundle.displayName = name.replace(hashReference, '[hash]');
83
90
  }
91
+
92
+ /**
93
+ * The applyRuntimes function is responsible for generating all the runtimes
94
+ * (assets created during the build that don't actually exist on disk) and then
95
+ * linking them into the bundle graph.
96
+ *
97
+ * Introduction of manifest bundles: https://github.com/parcel-bundler/parcel/pull/8837
98
+ * Introduction of reverse topology: https://github.com/parcel-bundler/parcel/pull/8981
99
+ */
84
100
  async function applyRuntimes({
85
101
  bundleGraph,
86
102
  config,
@@ -93,17 +109,27 @@ async function applyRuntimes({
93
109
  configs
94
110
  }) {
95
111
  let runtimes = await config.getRuntimes();
96
- let connections = [];
97
112
 
98
- // As manifest bundles may be added during runtimes we process them in reverse topological
99
- // sort order. This allows bundles to be added to their bundle groups before they are referenced
100
- // by other bundle groups by loader runtimes
113
+ /**
114
+ * Usually, the assets returned from a runtime will go in the same bundle. It is
115
+ * possible though, for a runtime to return an asset with a `parallel` priority,
116
+ * which allows it to be moved to a separate bundle. In practice, this is
117
+ * usually used to generate application manifest files.
118
+ *
119
+ * When adding a manifest bundle (a whole new separate bundle) during a runtime,
120
+ * it needs to be added to a bundle group which will be potentially referenced
121
+ * by another bundle group. To avoid trying to reference a manifest entry which
122
+ * hasn't been created yet, we process the bundles from the bottom up (topological
123
+ * order), so that children will always be available when parents try to reference
124
+ * them.
125
+ */
101
126
  let bundles = [];
102
127
  bundleGraph.traverseBundles({
103
128
  exit(bundle) {
104
129
  bundles.push(bundle);
105
130
  }
106
131
  });
132
+ let connectionMap = new (_utils().DefaultMap)(() => []);
107
133
  for (let bundle of bundles) {
108
134
  for (let runtime of runtimes) {
109
135
  let measurement;
@@ -144,6 +170,12 @@ async function applyRuntimes({
144
170
  isSource: true
145
171
  };
146
172
  let connectionBundle = bundle;
173
+
174
+ /**
175
+ * If a runtime asset is marked with a priority of `parallel` this
176
+ * means we need to create a new bundle for the asset and add it to
177
+ * all the same bundle groups.
178
+ */
147
179
  if (priority === 'parallel' && !bundle.needsStableName) {
148
180
  let bundleGroups = bundleGraph.getBundleGroupsContainingBundle(bundle);
149
181
  connectionBundle = (0, _nullthrows().default)(bundleGraph.createBundle({
@@ -158,9 +190,12 @@ async function applyRuntimes({
158
190
  bundleGraph.addBundleToBundleGroup(connectionBundle, bundleGroup);
159
191
  }
160
192
  bundleGraph.createBundleReference(bundle, connectionBundle);
193
+
194
+ // Ensure we name the bundle now as all other bundles have already
195
+ // been named as this point.
161
196
  nameRuntimeBundle(connectionBundle, bundle);
162
197
  }
163
- connections.push({
198
+ connectionMap.get(connectionBundle).push({
164
199
  bundle: connectionBundle,
165
200
  assetGroup,
166
201
  dependency,
@@ -180,8 +215,28 @@ async function applyRuntimes({
180
215
  }
181
216
  }
182
217
 
183
- // Correct connection order after generating runtimes in reverse order
184
- connections.reverse();
218
+ /**
219
+ * When merging the connections in to the bundle graph, the topological
220
+ * order can create module not found errors in some situations, often when HMR
221
+ * is enabled. To fix this, we put the connections into DFS order.
222
+ *
223
+ * Note: While DFS order seems to be the most reliable order to process the
224
+ * connections, this is likely due to it being close to the order that the bundles were
225
+ * inserted into the graph. There is a known issue where runtime assets marked
226
+ * as `isEntry` can create scenarios where there is no correct load order that
227
+ * won't error, as the entry runtime assets are added to many bundles in a
228
+ * single bundle group but their dependencies are not.
229
+ *
230
+ * This issue is almost exclusive to HMR scenarios as the two HMR runtime
231
+ * plugins (@atlaspack/runtime-browser-hmr and @atlaspack/runtime-react-refresh)
232
+ * are the only known cases where a runtime asset is marked as `isEntry`.
233
+ */
234
+ let connections = [];
235
+ bundleGraph.traverseBundles({
236
+ enter(bundle) {
237
+ connections.push(...connectionMap.get(bundle));
238
+ }
239
+ });
185
240
 
186
241
  // Add dev deps for runtime plugins AFTER running them, to account for lazy require().
187
242
  for (let runtime of runtimes) {
@@ -192,18 +247,29 @@ async function applyRuntimes({
192
247
  devDepRequests.set(`${devDepRequest.specifier}:${(0, _projectPath.fromProjectPathRelative)(devDepRequest.resolveFrom)}`, devDepRequest);
193
248
  await (0, _DevDepRequest.runDevDepRequest)(api, devDepRequest);
194
249
  }
250
+
251
+ // Create a new AssetGraph from the generated runtime assets which also runs
252
+ // transforms and resolves all dependencies.
195
253
  let {
196
254
  assetGraph: runtimesAssetGraph,
197
255
  changedAssets
198
256
  } = await reconcileNewRuntimes(api, connections, optionsRef);
199
- let runtimesGraph = _BundleGraph2.default.fromAssetGraph(runtimesAssetGraph, options.mode === 'production', bundleGraph._publicIdByAssetId, bundleGraph._assetPublicIds);
200
257
 
201
- // Merge the runtimes graph into the main bundle graph.
202
- bundleGraph.merge(runtimesGraph);
203
- for (let [assetId, publicId] of runtimesGraph._publicIdByAssetId) {
258
+ // Convert the runtime AssetGraph into a BundleGraph, this includes assigning
259
+ // the assets their public ids
260
+ let runtimesBundleGraph = _BundleGraph2.default.fromAssetGraph(runtimesAssetGraph, options.mode === 'production', bundleGraph._publicIdByAssetId, bundleGraph._assetPublicIds);
261
+
262
+ // Merge the runtimes bundle graph into the main bundle graph.
263
+ bundleGraph.merge(runtimesBundleGraph);
264
+
265
+ // Add the public id mappings from the runtumes bundlegraph to the main bundle graph
266
+ for (let [assetId, publicId] of runtimesBundleGraph._publicIdByAssetId) {
204
267
  bundleGraph._publicIdByAssetId.set(assetId, publicId);
205
268
  bundleGraph._assetPublicIds.add(publicId);
206
269
  }
270
+
271
+ // Connect each of the generated runtime assets to bundles in the main bundle
272
+ // graph. This is like a mini-bundling algorithm for runtime assets.
207
273
  for (let {
208
274
  bundle,
209
275
  assetGroup,
@@ -216,16 +282,24 @@ async function applyRuntimes({
216
282
  let runtimeNodeId = assetGroupAssetNodeIds[0];
217
283
  let runtimeNode = (0, _nullthrows().default)(runtimesAssetGraph.getNode(runtimeNodeId));
218
284
  (0, _assert().default)(runtimeNode.type === 'asset');
285
+
286
+ // Find the asset that the runtime asset should be connected from by resolving
287
+ // it's dependency.
219
288
  let resolution = dependency && bundleGraph.getResolvedAsset((0, _Dependency.dependencyToInternalDependency)(dependency), bundle);
220
- let runtimesGraphRuntimeNodeId = runtimesGraph._graph.getNodeIdByContentKey(runtimeNode.id);
289
+
290
+ // Walk all the dependencies of the runtime assets and check if they are
291
+ // already reachable from the bundle that the runtime asset is assigned to.
292
+ // If so, we add them to `duplicatedContentKeys` to be skipped when assigning
293
+ // assets to bundles.
294
+ let runtimesBundleGraphRuntimeNodeId = runtimesBundleGraph._graph.getNodeIdByContentKey(runtimeNode.id);
221
295
  let duplicatedContentKeys = new Set();
222
- runtimesGraph._graph.traverse((nodeId, _, actions) => {
223
- let node = (0, _nullthrows().default)(runtimesGraph._graph.getNode(nodeId));
296
+ runtimesBundleGraph._graph.traverse((nodeId, _, actions) => {
297
+ let node = (0, _nullthrows().default)(runtimesBundleGraph._graph.getNode(nodeId));
224
298
  if (node.type !== 'dependency') {
225
299
  return;
226
300
  }
227
- let assets = runtimesGraph._graph.getNodeIdsConnectedFrom(nodeId).map(assetNodeId => {
228
- let assetNode = (0, _nullthrows().default)(runtimesGraph._graph.getNode(assetNodeId));
301
+ let assets = runtimesBundleGraph._graph.getNodeIdsConnectedFrom(nodeId).map(assetNodeId => {
302
+ let assetNode = (0, _nullthrows().default)(runtimesBundleGraph._graph.getNode(assetNodeId));
229
303
  (0, _assert().default)(assetNode.type === 'asset');
230
304
  return assetNode.value;
231
305
  });
@@ -235,12 +309,14 @@ async function applyRuntimes({
235
309
  actions.skipChildren();
236
310
  }
237
311
  }
238
- }, runtimesGraphRuntimeNodeId);
312
+ }, runtimesBundleGraphRuntimeNodeId);
239
313
  let bundleNodeId = bundleGraph._graph.getNodeIdByContentKey(bundle.id);
240
314
  let bundleGraphRuntimeNodeId = bundleGraph._graph.getNodeIdByContentKey(runtimeNode.id); // the node id is not constant between graphs
241
315
 
242
- runtimesGraph._graph.traverse((nodeId, _, actions) => {
243
- let node = (0, _nullthrows().default)(runtimesGraph._graph.getNode(nodeId));
316
+ // Assign the runtime assets and all of it's depepdencies to the bundle unless
317
+ // we have detected it as already being reachable from this bundle via `duplicatedContentKeys`.
318
+ runtimesBundleGraph._graph.traverse((nodeId, _, actions) => {
319
+ let node = (0, _nullthrows().default)(runtimesBundleGraph._graph.getNode(nodeId));
244
320
  if (node.type === 'asset' || node.type === 'dependency') {
245
321
  if (duplicatedContentKeys.has(node.id)) {
246
322
  actions.skipChildren();
@@ -249,7 +325,7 @@ async function applyRuntimes({
249
325
  const bundleGraphNodeId = bundleGraph._graph.getNodeIdByContentKey(node.id); // the node id is not constant between graphs
250
326
  bundleGraph._graph.addEdge(bundleNodeId, bundleGraphNodeId, _BundleGraph2.bundleGraphEdgeTypes.contains);
251
327
  }
252
- }, runtimesGraphRuntimeNodeId);
328
+ }, runtimesBundleGraphRuntimeNodeId);
253
329
  if (isEntry) {
254
330
  bundleGraph._graph.addEdge(bundleNodeId, bundleGraphRuntimeNodeId);
255
331
  bundle.entryAssetIds.unshift(runtimeNode.id);
package/lib/assetUtils.js CHANGED
@@ -61,9 +61,15 @@ function _profiler() {
61
61
  }
62
62
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
63
63
  function createAssetIdFromOptions(options) {
64
- let uniqueKey = options.uniqueKey ?? '';
65
- let idBase = options.idBase != null ? options.idBase : (0, _projectPath.fromProjectPathRelative)(options.filePath);
66
- return (0, _rust().hashString)(idBase + options.type + options.env.id + uniqueKey + ':' + (options.pipeline ?? '') + ':' + (options.query ?? ''));
64
+ return (0, _rust().createAssetId)({
65
+ env: options.env,
66
+ filePath: options.filePath,
67
+ code: options.code,
68
+ pipeline: options.pipeline,
69
+ query: options.query,
70
+ uniqueKey: options.uniqueKey,
71
+ fileType: options.type
72
+ });
67
73
  }
68
74
  function createAsset(projectRoot, options) {
69
75
  return {
@@ -35,6 +35,12 @@ class AtlaspackV3 {
35
35
  threads,
36
36
  ...options
37
37
  }) {
38
+ options.logLevel = options.logLevel || 'error';
39
+ options.defaultTargetOptions = options.defaultTargetOptions || {};
40
+ // $FlowFixMe "engines" are readonly
41
+ options.defaultTargetOptions.engines = options.defaultTargetOptions.engines || {
42
+ browsers: []
43
+ };
38
44
  this._internal = new (_rust().AtlaspackNapi)({
39
45
  fs,
40
46
  nodeWorkers,
@@ -43,14 +49,6 @@ class AtlaspackV3 {
43
49
  options
44
50
  });
45
51
  }
46
- async build() {
47
- const [workers, registerWorker] = this.#createWorkers();
48
- let result = await this._internal.build({
49
- registerWorker
50
- });
51
- for (const worker of workers) worker.terminate();
52
- return result;
53
- }
54
52
  async buildAssetGraph() {
55
53
  const [workers, registerWorker] = this.#createWorkers();
56
54
  let result = await this._internal.buildAssetGraph({
@@ -11,7 +11,14 @@ function toFileSystemV3(fs) {
11
11
  canonicalize: (0, _jsCallable.jsCallable)(path => fs.realpathSync(path)),
12
12
  createDirectory: (0, _jsCallable.jsCallable)(path => fs.mkdirp(path)),
13
13
  cwd: (0, _jsCallable.jsCallable)(() => fs.cwd()),
14
- readFile: (0, _jsCallable.jsCallable)((path, encoding) => fs.readFileSync(path, encoding ?? 'utf8')),
14
+ readFile: (0, _jsCallable.jsCallable)((path, encoding) => {
15
+ if (!encoding) {
16
+ // $FlowFixMe
17
+ return [...fs.readFileSync(path)];
18
+ } else {
19
+ return fs.readFileSync(path, encoding);
20
+ }
21
+ }),
15
22
  isFile: path => {
16
23
  try {
17
24
  return fs.statSync(path).isFile();