@atlaspack/core 2.19.1 → 2.19.2

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaspack/core
2
2
 
3
+ ## 2.19.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#707](https://github.com/atlassian-labs/atlaspack/pull/707) [`a0b959f`](https://github.com/atlassian-labs/atlaspack/commit/a0b959fbf61fc3f820ff03c7e8988945fe40a91a) Thanks [@yamadapc](https://github.com/yamadapc)! - Fix content key not found exceptions when bundling is aborted after a unsafe to incrementally bundle asset graph request
8
+
9
+ - Updated dependencies [[`daaa768`](https://github.com/atlassian-labs/atlaspack/commit/daaa7688786772d7e3713b71c5bba6b89ec704aa), [`1c7865a`](https://github.com/atlassian-labs/atlaspack/commit/1c7865a64451116d94015e248302435839d347c0), [`a0b959f`](https://github.com/atlassian-labs/atlaspack/commit/a0b959fbf61fc3f820ff03c7e8988945fe40a91a)]:
10
+ - @atlaspack/plugin@2.14.20
11
+ - @atlaspack/feature-flags@2.19.2
12
+ - @atlaspack/cache@3.2.15
13
+ - @atlaspack/fs@2.15.15
14
+ - @atlaspack/graph@3.5.9
15
+ - @atlaspack/utils@2.17.2
16
+ - @atlaspack/package-manager@2.14.20
17
+ - @atlaspack/profiler@2.14.17
18
+ - @atlaspack/types@2.15.10
19
+ - @atlaspack/workers@2.14.20
20
+
3
21
  ## 2.19.1
4
22
 
5
23
  ### Patch Changes
package/lib/AssetGraph.js CHANGED
@@ -102,15 +102,31 @@ function nodeFromEntryFile(entry) {
102
102
  };
103
103
  }
104
104
  class AssetGraph extends _graph().ContentGraph {
105
+ /**
106
+ * Incremented when the asset graph is modified such that it requires a bundling pass.
107
+ */
108
+ #bundlingVersion = 0;
109
+ /**
110
+ * Force incremental bundling to be disabled.
111
+ */
112
+ #disableIncrementalBundling = false;
113
+
114
+ /**
115
+ * @deprecated
116
+ */
105
117
  safeToIncrementallyBundle = true;
106
118
  constructor(opts) {
107
119
  if (opts) {
108
120
  let {
109
121
  hash,
122
+ bundlingVersion,
123
+ disableIncrementalBundling,
110
124
  ...rest
111
125
  } = opts;
112
126
  super(rest);
113
127
  this.hash = hash;
128
+ this.#bundlingVersion = bundlingVersion ?? 0;
129
+ this.#disableIncrementalBundling = disableIncrementalBundling ?? false;
114
130
  } else {
115
131
  super();
116
132
  this.setRootNodeId(this.addNode({
@@ -132,10 +148,59 @@ class AssetGraph extends _graph().ContentGraph {
132
148
  serialize() {
133
149
  return {
134
150
  ...super.serialize(),
151
+ bundlingVersion: this.#bundlingVersion,
152
+ disableIncrementalBundling: this.#disableIncrementalBundling,
135
153
  hash: this.hash
136
154
  };
137
155
  }
138
156
 
157
+ /**
158
+ * Force incremental bundling to be disabled.
159
+ */
160
+ setDisableIncrementalBundling(disable) {
161
+ this.#disableIncrementalBundling = disable;
162
+ }
163
+ testing_getDisableIncrementalBundling() {
164
+ return this.#disableIncrementalBundling;
165
+ }
166
+
167
+ /**
168
+ * Make sure this asset graph is marked as needing a full bundling pass.
169
+ */
170
+ setNeedsBundling() {
171
+ if (!(0, _featureFlags().getFeatureFlag)('incrementalBundlingVersioning')) {
172
+ // In legacy mode, we rely solely on safeToIncrementallyBundle to
173
+ // invalidate incremental bundling, so we skip bumping the version.
174
+ return;
175
+ }
176
+ this.#bundlingVersion += 1;
177
+ }
178
+
179
+ /**
180
+ * Get the current bundling version.
181
+ *
182
+ * Each bundle pass should keep this version around. Whenever an asset graph has a new version,
183
+ * bundling should be re-run.
184
+ */
185
+ getBundlingVersion() {
186
+ if (!(0, _featureFlags().getFeatureFlag)('incrementalBundlingVersioning')) {
187
+ return 0;
188
+ }
189
+ return this.#bundlingVersion;
190
+ }
191
+
192
+ /**
193
+ * If the `bundlingVersion` has not changed since the last bundling pass,
194
+ * we can incrementally bundle, which will not require a full bundling pass
195
+ * but just update assets into the bundle graph output.
196
+ */
197
+ canIncrementallyBundle(lastVersion) {
198
+ if (!(0, _featureFlags().getFeatureFlag)('incrementalBundlingVersioning')) {
199
+ return this.safeToIncrementallyBundle && !this.#disableIncrementalBundling;
200
+ }
201
+ return this.safeToIncrementallyBundle && this.#bundlingVersion === lastVersion && !this.#disableIncrementalBundling;
202
+ }
203
+
139
204
  // Deduplicates Environments by making them referentially equal
140
205
  normalizeEnvironment(input) {
141
206
  if ((0, _featureFlags().getFeatureFlag)('environmentDeduplication')) {
@@ -307,11 +372,13 @@ class AssetGraph extends _graph().ContentGraph {
307
372
  } else if (traversedNode.type === 'asset_group' && nodeId !== traversedNodeId) {
308
373
  if (!(ctx !== null && ctx !== void 0 && ctx.hasDeferred)) {
309
374
  this.safeToIncrementallyBundle = false;
375
+ this.setNeedsBundling();
310
376
  delete traversedNode.hasDeferred;
311
377
  }
312
378
  actions.skipChildren();
313
379
  } else if (traversedNode.type === 'dependency') {
314
380
  this.safeToIncrementallyBundle = false;
381
+ this.setNeedsBundling();
315
382
  traversedNode.hasDeferred = false;
316
383
  } else if (nodeId !== traversedNodeId) {
317
384
  actions.skipChildren();
@@ -76,6 +76,7 @@ function createAssetGraphRequest(requestInput) {
76
76
  let assetGraphRequest = await await builder.build();
77
77
 
78
78
  // early break for incremental bundling if production or flag is off;
79
+ assetGraphRequest.assetGraph.setDisableIncrementalBundling(!input.options.shouldBundleIncrementally || input.options.mode === 'production');
79
80
  if (!input.options.shouldBundleIncrementally || input.options.mode === 'production') {
80
81
  assetGraphRequest.assetGraph.safeToIncrementallyBundle = false;
81
82
  }
@@ -368,6 +369,7 @@ class AssetGraphBuilder {
368
369
  let didEntriesChange = prevEntries.length !== currentEntries.length || prevEntries.every((entryId, index) => entryId === currentEntries[index]);
369
370
  if (didEntriesChange) {
370
371
  this.assetGraph.safeToIncrementallyBundle = false;
372
+ this.assetGraph.setNeedsBundling();
371
373
  }
372
374
  }
373
375
  }
@@ -407,10 +409,12 @@ class AssetGraphBuilder {
407
409
  (0, _assert().default)(otherAsset.type === 'asset');
408
410
  if (!this._areDependenciesEqualForAssets(asset, otherAsset.value)) {
409
411
  this.assetGraph.safeToIncrementallyBundle = false;
412
+ this.assetGraph.setNeedsBundling();
410
413
  }
411
414
  } else {
412
415
  // adding a new entry or dependency
413
416
  this.assetGraph.safeToIncrementallyBundle = false;
417
+ this.assetGraph.setNeedsBundling();
414
418
  }
415
419
  }
416
420
  this.changedAssets.set(asset.id, asset);
@@ -419,6 +423,7 @@ class AssetGraphBuilder {
419
423
  this.assetGraph.resolveAssetGroup(input, assets, request.id);
420
424
  } else {
421
425
  this.assetGraph.safeToIncrementallyBundle = false;
426
+ this.assetGraph.setNeedsBundling();
422
427
  }
423
428
  this.isSingleChangeRebuild = false;
424
429
  }
@@ -190,6 +190,7 @@ function createBundleGraphRequest(input) {
190
190
  let subRequestsInvalid = Boolean(invalidateReason & _constants.OPTION_CHANGE) || input.api.getSubRequests().some(req => !input.api.canSkipSubrequest(req.id));
191
191
  if (subRequestsInvalid) {
192
192
  assetGraph.safeToIncrementallyBundle = false;
193
+ assetGraph.setNeedsBundling();
193
194
  }
194
195
  let configResult = (0, _nullthrows().default)(await input.api.runRequest((0, _AtlaspackConfigRequest.default)()));
195
196
  (0, _utils2.assertSignalNotAborted)(signal);
@@ -292,16 +293,11 @@ class BundlerRunner {
292
293
  } = plugin;
293
294
 
294
295
  // if a previous asset graph hash is passed in, check if the bundle graph is also available
295
- let previousBundleGraphResult;
296
- if (graph.safeToIncrementallyBundle) {
297
- try {
298
- previousBundleGraphResult = await this.api.getPreviousResult();
299
- } catch {
300
- // if the bundle graph had an error or was removed, don't fail the build
301
- }
302
- }
303
- if (previousBundleGraphResult == null) {
296
+ const previousBundleGraphResult = await this.api.getPreviousResult();
297
+ const canIncrementallyBundle = (previousBundleGraphResult === null || previousBundleGraphResult === void 0 ? void 0 : previousBundleGraphResult.assetGraphBundlingVersion) != null && graph.canIncrementallyBundle(previousBundleGraphResult.assetGraphBundlingVersion);
298
+ if (graph.safeToIncrementallyBundle && previousBundleGraphResult == null) {
304
299
  graph.safeToIncrementallyBundle = false;
300
+ graph.setNeedsBundling();
305
301
  }
306
302
  let internalBundleGraph;
307
303
  let logger = new (_logger().PluginLogger)({
@@ -312,7 +308,7 @@ class BundlerRunner {
312
308
  category: 'bundle'
313
309
  });
314
310
  try {
315
- if (previousBundleGraphResult) {
311
+ if (canIncrementallyBundle && previousBundleGraphResult) {
316
312
  internalBundleGraph = previousBundleGraphResult.bundleGraph;
317
313
  for (let changedAssetId of changedAssets.keys()) {
318
314
  // Copy over the whole node to also have correct symbol data
@@ -384,6 +380,7 @@ class BundlerRunner {
384
380
  if (internalBundleGraph != null) {
385
381
  this.api.storeResult({
386
382
  bundleGraph: internalBundleGraph,
383
+ assetGraphBundlingVersion: graph.getBundlingVersion(),
387
384
  changedAssets: new Map(),
388
385
  assetRequests: []
389
386
  }, this.cacheKey);
@@ -401,7 +398,7 @@ class BundlerRunner {
401
398
  }
402
399
  }
403
400
  let changedRuntimes = new Map();
404
- if (!previousBundleGraphResult) {
401
+ if (!previousBundleGraphResult || !canIncrementallyBundle) {
405
402
  let namers = await this.config.getNamers();
406
403
  // inline bundles must still be named so the PackagerRunner
407
404
  // can match them to the correct packager/optimizer plugins.
@@ -439,11 +436,13 @@ class BundlerRunner {
439
436
  internalBundleGraph._graph, 'after_runtimes', _BundleGraph2.bundleGraphEdgeTypes);
440
437
  this.api.storeResult({
441
438
  bundleGraph: internalBundleGraph,
439
+ assetGraphBundlingVersion: graph.getBundlingVersion(),
442
440
  changedAssets: new Map(),
443
441
  assetRequests: []
444
442
  }, this.cacheKey);
445
443
  return {
446
444
  bundleGraph: internalBundleGraph,
445
+ assetGraphBundlingVersion: graph.getBundlingVersion(),
447
446
  changedAssets: changedRuntimes,
448
447
  assetRequests
449
448
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaspack/core",
3
- "version": "2.19.1",
3
+ "version": "2.19.2",
4
4
  "license": "(MIT OR Apache-2.0)",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -23,20 +23,20 @@
23
23
  "dependencies": {
24
24
  "@mischnic/json-sourcemap": "^0.1.0",
25
25
  "@atlaspack/build-cache": "2.13.3",
26
- "@atlaspack/cache": "3.2.14",
26
+ "@atlaspack/cache": "3.2.15",
27
27
  "@atlaspack/diagnostic": "2.14.1",
28
28
  "@atlaspack/events": "2.14.1",
29
- "@atlaspack/feature-flags": "2.19.1",
30
- "@atlaspack/fs": "2.15.14",
31
- "@atlaspack/graph": "3.5.8",
29
+ "@atlaspack/feature-flags": "2.19.2",
30
+ "@atlaspack/fs": "2.15.15",
31
+ "@atlaspack/graph": "3.5.9",
32
32
  "@atlaspack/logger": "2.14.13",
33
- "@atlaspack/package-manager": "2.14.19",
34
- "@atlaspack/plugin": "2.14.19",
35
- "@atlaspack/profiler": "2.14.16",
33
+ "@atlaspack/package-manager": "2.14.20",
34
+ "@atlaspack/plugin": "2.14.20",
35
+ "@atlaspack/profiler": "2.14.17",
36
36
  "@atlaspack/rust": "3.4.1",
37
- "@atlaspack/types": "2.15.9",
38
- "@atlaspack/utils": "2.17.1",
39
- "@atlaspack/workers": "2.14.19",
37
+ "@atlaspack/types": "2.15.10",
38
+ "@atlaspack/utils": "2.17.2",
39
+ "@atlaspack/workers": "2.14.20",
40
40
  "@parcel/source-map": "^2.1.1",
41
41
  "base-x": "^3.0.8",
42
42
  "browserslist": "^4.6.6",
package/src/AssetGraph.js CHANGED
@@ -44,11 +44,15 @@ type InitOpts = {|
44
44
 
45
45
  type AssetGraphOpts = {|
46
46
  ...ContentGraphOpts<AssetGraphNode>,
47
+ bundlingVersion?: number,
48
+ disableIncrementalBundling?: boolean,
47
49
  hash?: ?string,
48
50
  |};
49
51
 
50
52
  type SerializedAssetGraph = {|
51
53
  ...SerializedContentGraph<AssetGraphNode>,
54
+ bundlingVersion: number,
55
+ disableIncrementalBundling: boolean,
52
56
  hash?: ?string,
53
57
  |};
54
58
 
@@ -117,14 +121,30 @@ export default class AssetGraph extends ContentGraph<AssetGraphNode> {
117
121
  onNodeRemoved: ?(nodeId: NodeId) => mixed;
118
122
  hash: ?string;
119
123
  envCache: Map<string, Environment>;
124
+
125
+ /**
126
+ * Incremented when the asset graph is modified such that it requires a bundling pass.
127
+ */
128
+ #bundlingVersion: number = 0;
129
+ /**
130
+ * Force incremental bundling to be disabled.
131
+ */
132
+ #disableIncrementalBundling: boolean = false;
133
+
134
+ /**
135
+ * @deprecated
136
+ */
120
137
  safeToIncrementallyBundle: boolean = true;
138
+
121
139
  undeferredDependencies: Set<Dependency>;
122
140
 
123
141
  constructor(opts: ?AssetGraphOpts) {
124
142
  if (opts) {
125
- let {hash, ...rest} = opts;
143
+ let {hash, bundlingVersion, disableIncrementalBundling, ...rest} = opts;
126
144
  super(rest);
127
145
  this.hash = hash;
146
+ this.#bundlingVersion = bundlingVersion ?? 0;
147
+ this.#disableIncrementalBundling = disableIncrementalBundling ?? false;
128
148
  } else {
129
149
  super();
130
150
  this.setRootNodeId(
@@ -149,10 +169,66 @@ export default class AssetGraph extends ContentGraph<AssetGraphNode> {
149
169
  serialize(): SerializedAssetGraph {
150
170
  return {
151
171
  ...super.serialize(),
172
+ bundlingVersion: this.#bundlingVersion,
173
+ disableIncrementalBundling: this.#disableIncrementalBundling,
152
174
  hash: this.hash,
153
175
  };
154
176
  }
155
177
 
178
+ /**
179
+ * Force incremental bundling to be disabled.
180
+ */
181
+ setDisableIncrementalBundling(disable: boolean) {
182
+ this.#disableIncrementalBundling = disable;
183
+ }
184
+
185
+ testing_getDisableIncrementalBundling(): boolean {
186
+ return this.#disableIncrementalBundling;
187
+ }
188
+
189
+ /**
190
+ * Make sure this asset graph is marked as needing a full bundling pass.
191
+ */
192
+ setNeedsBundling() {
193
+ if (!getFeatureFlag('incrementalBundlingVersioning')) {
194
+ // In legacy mode, we rely solely on safeToIncrementallyBundle to
195
+ // invalidate incremental bundling, so we skip bumping the version.
196
+ return;
197
+ }
198
+ this.#bundlingVersion += 1;
199
+ }
200
+
201
+ /**
202
+ * Get the current bundling version.
203
+ *
204
+ * Each bundle pass should keep this version around. Whenever an asset graph has a new version,
205
+ * bundling should be re-run.
206
+ */
207
+ getBundlingVersion(): number {
208
+ if (!getFeatureFlag('incrementalBundlingVersioning')) {
209
+ return 0;
210
+ }
211
+ return this.#bundlingVersion;
212
+ }
213
+
214
+ /**
215
+ * If the `bundlingVersion` has not changed since the last bundling pass,
216
+ * we can incrementally bundle, which will not require a full bundling pass
217
+ * but just update assets into the bundle graph output.
218
+ */
219
+ canIncrementallyBundle(lastVersion: number): boolean {
220
+ if (!getFeatureFlag('incrementalBundlingVersioning')) {
221
+ return (
222
+ this.safeToIncrementallyBundle && !this.#disableIncrementalBundling
223
+ );
224
+ }
225
+ return (
226
+ this.safeToIncrementallyBundle &&
227
+ this.#bundlingVersion === lastVersion &&
228
+ !this.#disableIncrementalBundling
229
+ );
230
+ }
231
+
156
232
  // Deduplicates Environments by making them referentially equal
157
233
  normalizeEnvironment(input: Asset | Dependency | AssetGroup) {
158
234
  if (getFeatureFlag('environmentDeduplication')) {
@@ -369,11 +445,13 @@ export default class AssetGraph extends ContentGraph<AssetGraphNode> {
369
445
  ) {
370
446
  if (!ctx?.hasDeferred) {
371
447
  this.safeToIncrementallyBundle = false;
448
+ this.setNeedsBundling();
372
449
  delete traversedNode.hasDeferred;
373
450
  }
374
451
  actions.skipChildren();
375
452
  } else if (traversedNode.type === 'dependency') {
376
453
  this.safeToIncrementallyBundle = false;
454
+ this.setNeedsBundling();
377
455
  traversedNode.hasDeferred = false;
378
456
  } else if (nodeId !== traversedNodeId) {
379
457
  actions.skipChildren();
@@ -84,6 +84,11 @@ export default function createAssetGraphRequest(
84
84
  let assetGraphRequest = await await builder.build();
85
85
 
86
86
  // early break for incremental bundling if production or flag is off;
87
+ assetGraphRequest.assetGraph.setDisableIncrementalBundling(
88
+ !input.options.shouldBundleIncrementally ||
89
+ input.options.mode === 'production',
90
+ );
91
+
87
92
  if (
88
93
  !input.options.shouldBundleIncrementally ||
89
94
  input.options.mode === 'production'
@@ -511,6 +516,7 @@ export class AssetGraphBuilder {
511
516
 
512
517
  if (didEntriesChange) {
513
518
  this.assetGraph.safeToIncrementallyBundle = false;
519
+ this.assetGraph.setNeedsBundling();
514
520
  }
515
521
  }
516
522
  }
@@ -554,10 +560,12 @@ export class AssetGraphBuilder {
554
560
  invariant(otherAsset.type === 'asset');
555
561
  if (!this._areDependenciesEqualForAssets(asset, otherAsset.value)) {
556
562
  this.assetGraph.safeToIncrementallyBundle = false;
563
+ this.assetGraph.setNeedsBundling();
557
564
  }
558
565
  } else {
559
566
  // adding a new entry or dependency
560
567
  this.assetGraph.safeToIncrementallyBundle = false;
568
+ this.assetGraph.setNeedsBundling();
561
569
  }
562
570
  }
563
571
  this.changedAssets.set(asset.id, asset);
@@ -566,6 +574,7 @@ export class AssetGraphBuilder {
566
574
  this.assetGraph.resolveAssetGroup(input, assets, request.id);
567
575
  } else {
568
576
  this.assetGraph.safeToIncrementallyBundle = false;
577
+ this.assetGraph.setNeedsBundling();
569
578
  }
570
579
 
571
580
  this.isSingleChangeRebuild = false;
@@ -72,10 +72,6 @@ type BundleGraphRequestInput = {|
72
72
  optionsRef: SharedReference,
73
73
  |};
74
74
 
75
- type BundleGraphRequestResult = {|
76
- bundleGraph: InternalBundleGraph,
77
- |};
78
-
79
75
  type RunInput = {|
80
76
  input: BundleGraphRequestInput,
81
77
  ...StaticRunOpts<BundleGraphResult>,
@@ -84,6 +80,7 @@ type RunInput = {|
84
80
  // TODO: Rename to BundleGraphRequestResult
85
81
  export type BundleGraphResult = {|
86
82
  bundleGraph: InternalBundleGraph,
83
+ assetGraphBundlingVersion: number,
87
84
  changedAssets: Map<string, Asset>,
88
85
  assetRequests: Array<AssetGroup>,
89
86
  |};
@@ -215,6 +212,7 @@ export default function createBundleGraphRequest(
215
212
 
216
213
  if (subRequestsInvalid) {
217
214
  assetGraph.safeToIncrementallyBundle = false;
215
+ assetGraph.setNeedsBundling();
218
216
  }
219
217
 
220
218
  let configResult = nullthrows(
@@ -363,16 +361,17 @@ class BundlerRunner {
363
361
  let {plugin: bundler, name, resolveFrom} = plugin;
364
362
 
365
363
  // if a previous asset graph hash is passed in, check if the bundle graph is also available
366
- let previousBundleGraphResult: ?BundleGraphRequestResult;
367
- if (graph.safeToIncrementallyBundle) {
368
- try {
369
- previousBundleGraphResult = await this.api.getPreviousResult();
370
- } catch {
371
- // if the bundle graph had an error or was removed, don't fail the build
372
- }
373
- }
374
- if (previousBundleGraphResult == null) {
364
+ const previousBundleGraphResult: ?BundleGraphResult =
365
+ await this.api.getPreviousResult();
366
+ const canIncrementallyBundle =
367
+ previousBundleGraphResult?.assetGraphBundlingVersion != null &&
368
+ graph.canIncrementallyBundle(
369
+ previousBundleGraphResult.assetGraphBundlingVersion,
370
+ );
371
+
372
+ if (graph.safeToIncrementallyBundle && previousBundleGraphResult == null) {
375
373
  graph.safeToIncrementallyBundle = false;
374
+ graph.setNeedsBundling();
376
375
  }
377
376
 
378
377
  let internalBundleGraph;
@@ -383,7 +382,7 @@ class BundlerRunner {
383
382
  category: 'bundle',
384
383
  });
385
384
  try {
386
- if (previousBundleGraphResult) {
385
+ if (canIncrementallyBundle && previousBundleGraphResult) {
387
386
  internalBundleGraph = previousBundleGraphResult.bundleGraph;
388
387
  for (let changedAssetId of changedAssets.keys()) {
389
388
  // Copy over the whole node to also have correct symbol data
@@ -485,6 +484,7 @@ class BundlerRunner {
485
484
  this.api.storeResult(
486
485
  {
487
486
  bundleGraph: internalBundleGraph,
487
+ assetGraphBundlingVersion: graph.getBundlingVersion(),
488
488
  changedAssets: new Map(),
489
489
  assetRequests: [],
490
490
  },
@@ -509,7 +509,7 @@ class BundlerRunner {
509
509
  }
510
510
 
511
511
  let changedRuntimes = new Map();
512
- if (!previousBundleGraphResult) {
512
+ if (!previousBundleGraphResult || !canIncrementallyBundle) {
513
513
  let namers = await this.config.getNamers();
514
514
  // inline bundles must still be named so the PackagerRunner
515
515
  // can match them to the correct packager/optimizer plugins.
@@ -561,6 +561,7 @@ class BundlerRunner {
561
561
  this.api.storeResult(
562
562
  {
563
563
  bundleGraph: internalBundleGraph,
564
+ assetGraphBundlingVersion: graph.getBundlingVersion(),
564
565
  changedAssets: new Map(),
565
566
  assetRequests: [],
566
567
  },
@@ -569,6 +570,7 @@ class BundlerRunner {
569
570
 
570
571
  return {
571
572
  bundleGraph: internalBundleGraph,
573
+ assetGraphBundlingVersion: graph.getBundlingVersion(),
572
574
  changedAssets: changedRuntimes,
573
575
  assetRequests,
574
576
  };
@@ -2,6 +2,7 @@
2
2
  import assert from 'assert';
3
3
  import invariant from 'assert';
4
4
  import nullthrows from 'nullthrows';
5
+ import {serialize, deserialize} from '@atlaspack/build-cache';
5
6
  import AssetGraph, {
6
7
  nodeFromAssetGroup,
7
8
  nodeFromDep,
@@ -690,4 +691,36 @@ describe('AssetGraph', () => {
690
691
  invariant(node.type === 'asset_group');
691
692
  assert(!node.hasDeferred);
692
693
  });
694
+
695
+ it('should serialize the bundling version and incremental bundling flag', () => {
696
+ const graph = new AssetGraph();
697
+ graph.setDisableIncrementalBundling(true);
698
+ graph.setNeedsBundling();
699
+ const serialized = serialize(graph);
700
+ const deserialized = deserialize(serialized);
701
+
702
+ assert.equal(deserialized.getBundlingVersion(), 1);
703
+ assert.equal(deserialized.testing_getDisableIncrementalBundling(), true);
704
+ });
705
+
706
+ describe('setNeedsBundling', () => {
707
+ it('should increment the bundling version', () => {
708
+ const graph = new AssetGraph();
709
+ assert.equal(graph.getBundlingVersion(), 0);
710
+ graph.setNeedsBundling();
711
+ assert.equal(graph.getBundlingVersion(), 1);
712
+ graph.setNeedsBundling();
713
+ assert.equal(graph.getBundlingVersion(), 2);
714
+ });
715
+ });
716
+
717
+ describe('canIncrementallyBundle', () => {
718
+ it('should return true if the bundling version has changed', () => {
719
+ const graph = new AssetGraph();
720
+ const lastVersion = graph.getBundlingVersion();
721
+ assert.equal(graph.canIncrementallyBundle(lastVersion), true);
722
+ graph.setNeedsBundling();
723
+ assert.equal(graph.canIncrementallyBundle(lastVersion), false);
724
+ });
725
+ });
693
726
  });
@@ -8,6 +8,7 @@ import RequestTracker, {
8
8
  runInvalidation,
9
9
  getBiggestFSEventsInvalidations,
10
10
  invalidateRequestGraphFSEvents,
11
+ requestTypes,
11
12
  } from '../src/RequestTracker';
12
13
  import {Graph} from '@atlaspack/graph';
13
14
  import {LMDBLiteCache} from '@atlaspack/cache';
@@ -19,6 +20,12 @@ import {toProjectPath} from '../src/projectPath';
19
20
  import {DEFAULT_FEATURE_FLAGS, setFeatureFlags} from '../../feature-flags/src';
20
21
  import sinon from 'sinon';
21
22
  import type {AtlaspackOptions} from '../src/types';
23
+ import createAtlaspackBuildRequest from '../src/requests/AtlaspackBuildRequest';
24
+ import Atlaspack from '../src/Atlaspack';
25
+ import {MemoryFS, NodeFS} from '@atlaspack/fs';
26
+ import {OverlayFS} from '../../fs/src/OverlayFS';
27
+ import path from 'path';
28
+ import createAssetGraphRequest from '../src/requests/AssetGraphRequest';
22
29
 
23
30
  const options = {
24
31
  ...DEFAULT_OPTIONS,
@@ -542,6 +549,169 @@ describe('RequestTracker', () => {
542
549
  });
543
550
  });
544
551
  });
552
+
553
+ describe('incremental bundling', () => {
554
+ async function runIncrementalBundlingScenario(
555
+ incrementalBundlingVersioning: boolean,
556
+ ) {
557
+ const fs = new OverlayFS(new MemoryFS(farm), new NodeFS());
558
+ const appRoot = __dirname;
559
+ await fs.mkdirp(path.join(appRoot, 'app'));
560
+ await fs.writeFile(path.join(appRoot, 'app', 'package.json'), '{}');
561
+ await fs.writeFile(path.join(appRoot, 'app', '.git'), '');
562
+ await fs.writeFile(
563
+ path.join(appRoot, 'app', '.parcelrc'),
564
+ '{"extends":"@atlaspack/config-default"}',
565
+ );
566
+ await fs.writeFile(
567
+ path.join(appRoot, 'app', 'target.js'),
568
+ 'console.log("hello")',
569
+ );
570
+
571
+ const atlaspack = new Atlaspack({
572
+ featureFlags: {
573
+ incrementalBundlingVersioning,
574
+ },
575
+ workerFarm: farm,
576
+ entries: [path.join(appRoot, 'app', 'target.js')],
577
+ cache: new LMDBLiteCache(DEFAULT_OPTIONS.cacheDir),
578
+ inputFS: fs,
579
+ outputFS: fs,
580
+ });
581
+ await atlaspack._init();
582
+ const options = atlaspack._getResolvedAtlaspackOptions();
583
+ const tracker = new RequestTracker({farm, options});
584
+ let {ref: optionsRef} = await farm.createSharedReference(options, false);
585
+
586
+ const getAssetRequests = () =>
587
+ runRequestSpy
588
+ .getCalls()
589
+ .map((call) => call.args[0])
590
+ .filter((request) => request.type === requestTypes.asset_request);
591
+
592
+ // Running the build once builds one asset
593
+ const runRequestSpy = sinon.spy(tracker, 'runRequest');
594
+ await tracker.runRequest(
595
+ createAtlaspackBuildRequest({
596
+ optionsRef,
597
+ requestedAssetIds: new Set(),
598
+ }),
599
+ );
600
+ assert.equal(getAssetRequests().length, 1);
601
+ runRequestSpy.resetHistory();
602
+
603
+ // Running the build again with no invalidations does not build any assets
604
+ await tracker.runRequest(
605
+ createAtlaspackBuildRequest({
606
+ optionsRef,
607
+ requestedAssetIds: new Set(),
608
+ }),
609
+ );
610
+ assert.equal(getAssetRequests().length, 0);
611
+ runRequestSpy.resetHistory();
612
+
613
+ // Running the build again with a file change builds the asset again
614
+ tracker.respondToFSEvents(
615
+ [
616
+ {
617
+ type: 'update',
618
+ path: path.join(appRoot, 'app', 'target.js'),
619
+ },
620
+ ],
621
+ Number.MAX_VALUE,
622
+ );
623
+ await tracker.runRequest(
624
+ createAtlaspackBuildRequest({
625
+ optionsRef,
626
+ requestedAssetIds: new Set(),
627
+ }),
628
+ );
629
+ assert.equal(getAssetRequests().length, 1);
630
+ runRequestSpy.resetHistory();
631
+
632
+ // Run the asset graph request, but not bundling
633
+ await fs.writeFile(
634
+ path.join(appRoot, 'app', 'target.js'),
635
+ 'require("./dep.js")',
636
+ );
637
+ await fs.writeFile(
638
+ path.join(appRoot, 'app', 'dep.js'),
639
+ 'console.log("dep")',
640
+ );
641
+ tracker.respondToFSEvents(
642
+ [
643
+ {
644
+ type: 'update',
645
+ path: path.join(appRoot, 'app', 'target.js'),
646
+ },
647
+ ],
648
+ Number.MAX_VALUE,
649
+ );
650
+ const assetGraphRequestResult = await tracker.runRequest(
651
+ createAssetGraphRequest({
652
+ name: 'Main',
653
+ entries: [
654
+ toProjectPath(
655
+ path.join(appRoot, 'app'),
656
+ path.join(appRoot, 'app', 'target.js'),
657
+ ),
658
+ ],
659
+ optionsRef,
660
+ shouldBuildLazily: false,
661
+ lazyIncludes: [],
662
+ lazyExcludes: [],
663
+ requestedAssetIds: new Set(),
664
+ }),
665
+ );
666
+ assert.equal(getAssetRequests().length, 2);
667
+ assert.equal(
668
+ assetGraphRequestResult.assetGraph.safeToIncrementallyBundle,
669
+ false,
670
+ );
671
+
672
+ // Now make another change
673
+ tracker.respondToFSEvents(
674
+ [
675
+ {
676
+ type: 'update',
677
+ path: path.join(appRoot, 'app', 'target.js'),
678
+ },
679
+ {
680
+ type: 'update',
681
+ path: path.join(appRoot, 'app', 'dep.js'),
682
+ },
683
+ ],
684
+ Number.MAX_VALUE,
685
+ );
686
+ // And run the build again
687
+
688
+ if (!incrementalBundlingVersioning) {
689
+ await assert.rejects(async () => {
690
+ await tracker.runRequest(
691
+ createAtlaspackBuildRequest({
692
+ optionsRef,
693
+ requestedAssetIds: new Set(),
694
+ }),
695
+ );
696
+ });
697
+ } else {
698
+ await tracker.runRequest(
699
+ createAtlaspackBuildRequest({
700
+ optionsRef,
701
+ requestedAssetIds: new Set(),
702
+ }),
703
+ );
704
+ }
705
+ }
706
+
707
+ it('throws a content key not found exception without bundling versioning', async () => {
708
+ await runIncrementalBundlingScenario(false);
709
+ });
710
+
711
+ it('works fine with bundling versioning', async () => {
712
+ await runIncrementalBundlingScenario(true);
713
+ });
714
+ });
545
715
  });
546
716
 
547
717
  describe('cleanUpOrphans', () => {