@atlaspack/core 2.19.0 → 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,39 @@
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
+
21
+ ## 2.19.1
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies [[`13aef17`](https://github.com/atlassian-labs/atlaspack/commit/13aef177eea289a6e40d2113b5ec1ac9be18a33d)]:
26
+ - @atlaspack/feature-flags@2.19.1
27
+ - @atlaspack/cache@3.2.14
28
+ - @atlaspack/fs@2.15.14
29
+ - @atlaspack/graph@3.5.8
30
+ - @atlaspack/utils@2.17.1
31
+ - @atlaspack/package-manager@2.14.19
32
+ - @atlaspack/profiler@2.14.16
33
+ - @atlaspack/types@2.15.9
34
+ - @atlaspack/workers@2.14.19
35
+ - @atlaspack/plugin@2.14.19
36
+
3
37
  ## 2.19.0
4
38
 
5
39
  ### Minor 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();
package/lib/Atlaspack.js CHANGED
@@ -128,32 +128,23 @@ const INTERNAL_TRANSFORM = exports.INTERNAL_TRANSFORM = Symbol('internal_transfo
128
128
  const INTERNAL_RESOLVE = exports.INTERNAL_RESOLVE = Symbol('internal_resolve');
129
129
  const WORKER_PATH = exports.WORKER_PATH = _path().default.join(__dirname, 'worker.js');
130
130
  class Atlaspack {
131
- #requestTracker /*: RequestTracker*/;
132
- #config /*: AtlaspackConfig*/;
133
- #farm /*: WorkerFarm*/;
134
- #initialized /*: boolean*/ = false;
135
- #disposable /*: Disposable */;
136
- #initialOptions /*: InitialAtlaspackOptions */;
137
- #reporterRunner /*: ReporterRunner*/;
138
- #resolvedOptions /*: ?AtlaspackOptions*/ = null;
139
- #optionsRef /*: SharedReference */;
140
- #watchAbortController /*: AbortController*/;
141
- #watchQueue /*: PromiseQueue<?BuildEvent>*/ = new (_utils2().PromiseQueue)({
131
+ #requestTracker;
132
+ #config;
133
+ #farm;
134
+ #initialized = false;
135
+ #disposable;
136
+ #initialOptions;
137
+ #reporterRunner;
138
+ #resolvedOptions = null;
139
+ #optionsRef;
140
+ #watchAbortController;
141
+ #watchQueue = new (_utils2().PromiseQueue)({
142
142
  maxConcurrent: 1
143
143
  });
144
- #watchEvents /*: ValueEmitter<
145
- | {|
146
- +error: Error,
147
- +buildEvent?: void,
148
- |}
149
- | {|
150
- +buildEvent: BuildEvent,
151
- +error?: void,
152
- |},
153
- > */;
154
- #watcherSubscription /*: ?AsyncSubscription*/;
155
- #watcherCount /*: number*/ = 0;
156
- #requestedAssetIds /*: Set<string>*/ = new Set();
144
+ #watchEvents;
145
+ #watcherSubscription;
146
+ #watcherCount = 0;
147
+ #requestedAssetIds = new Set();
157
148
  constructor(options) {
158
149
  this.#initialOptions = options;
159
150
  }
@@ -45,8 +45,7 @@ function assetFromValue(value, options) {
45
45
  }
46
46
  class BaseAsset {
47
47
  #asset;
48
- #query /*: ?URLSearchParams */;
49
-
48
+ #query;
50
49
  constructor(asset) {
51
50
  this.#asset = asset;
52
51
  _assetToAssetValue.set(this, asset.value);
@@ -128,9 +127,8 @@ class BaseAsset {
128
127
  }
129
128
  }
130
129
  class Asset extends BaseAsset {
131
- #asset /*: CommittedAsset | UncommittedAsset */;
132
- #env /*: ?Environment */;
133
-
130
+ #asset;
131
+ #env;
134
132
  constructor(asset) {
135
133
  let assetValueToAsset = asset.value.committed ? committedAssetValueToAsset : uncommittedAssetValueToAsset;
136
134
  let existing = assetValueToAsset.get(asset.value);
@@ -152,8 +150,7 @@ class Asset extends BaseAsset {
152
150
  }
153
151
  exports.Asset = Asset;
154
152
  class MutableAsset extends BaseAsset {
155
- #asset /*: UncommittedAsset */;
156
-
153
+ #asset;
157
154
  constructor(asset) {
158
155
  let existing = assetValueToMutableAsset.get(asset.value);
159
156
  if (existing != null) {
@@ -62,9 +62,9 @@ function bundleToInternalBundleGraph(bundle) {
62
62
  // preventing others from using them. They should use the static `get` method.
63
63
  let _private = {};
64
64
  class Bundle {
65
- #bundle /*: InternalBundle */;
66
- #bundleGraph /*: BundleGraph */;
67
- #options /*: AtlaspackOptions */;
65
+ #bundle;
66
+ #bundleGraph;
67
+ #options;
68
68
 
69
69
  // $FlowFixMe
70
70
  [inspect]() {
@@ -159,10 +159,9 @@ class Bundle {
159
159
  }
160
160
  exports.Bundle = Bundle;
161
161
  class NamedBundle extends Bundle {
162
- #bundle /*: InternalBundle */;
163
- #bundleGraph /*: BundleGraph */;
164
- #options /*: AtlaspackOptions */;
165
-
162
+ #bundle;
163
+ #bundleGraph;
164
+ #options;
166
165
  constructor(sentinel, bundle, bundleGraph, options) {
167
166
  super(sentinel, bundle, bundleGraph, options);
168
167
  this.#bundle = bundle; // Repeating for flow
@@ -193,11 +192,10 @@ class NamedBundle extends Bundle {
193
192
  }
194
193
  exports.NamedBundle = NamedBundle;
195
194
  class PackagedBundle extends NamedBundle {
196
- #bundle /*: InternalBundle */;
197
- #bundleGraph /*: BundleGraph */;
198
- #options /*: AtlaspackOptions */;
199
- #bundleInfo /*: ?PackagedBundleInfo */;
200
-
195
+ #bundle;
196
+ #bundleGraph;
197
+ #options;
198
+ #bundleInfo;
201
199
  constructor(sentinel, bundle, bundleGraph, options) {
202
200
  super(sentinel, bundle, bundleGraph, options);
203
201
  this.#bundle = bundle; // Repeating for flow
@@ -21,9 +21,8 @@ function bundleGroupToInternalBundleGroup(target) {
21
21
  }
22
22
  const inspect = Symbol.for('nodejs.util.inspect.custom');
23
23
  class BundleGroup {
24
- #bundleGroup /*: InternalBundleGroup */;
25
- #options /*: AtlaspackOptions */;
26
-
24
+ #bundleGroup;
25
+ #options;
27
26
  constructor(bundleGroup, options) {
28
27
  let existing = internalBundleGroupToBundleGroup.get(bundleGroup);
29
28
  if (existing != null) {
@@ -97,11 +97,10 @@ function makeConfigProxy(onRead, config) {
97
97
  return makeProxy(config, []);
98
98
  }
99
99
  class PublicConfig {
100
- #config /*: Config */;
101
- #pkg /*: ?PackageJSON */;
102
- #pkgFilePath /*: ?FilePath */;
103
- #options /*: AtlaspackOptions */;
104
-
100
+ #config;
101
+ #pkg;
102
+ #pkgFilePath;
103
+ #options;
105
104
  constructor(config, options) {
106
105
  let existing = internalConfigToConfig.get(options).get(config);
107
106
  if (existing != null) {
@@ -37,9 +37,8 @@ function getPublicDependency(dep, options) {
37
37
  return new Dependency(dep, options);
38
38
  }
39
39
  class Dependency {
40
- #dep /*: InternalDependency */;
41
- #options /*: AtlaspackOptions */;
42
-
40
+ #dep;
41
+ #options;
43
42
  constructor(dep, options) {
44
43
  this.#dep = dep;
45
44
  this.#options = options;
@@ -127,9 +127,8 @@ function environmentToInternalEnvironment(environment) {
127
127
  return (0, _nullthrows().default)(_environmentToInternalEnvironment.get(environment));
128
128
  }
129
129
  class Environment {
130
- #environment /*: InternalEnvironment */;
131
- #options /*: AtlaspackOptions */;
132
-
130
+ #environment;
131
+ #options;
133
132
  constructor(env, options) {
134
133
  let existing = internalEnvironmentToEnvironment.get(env);
135
134
  if (existing != null) {
@@ -54,9 +54,9 @@ function createBundleId(data) {
54
54
  return id;
55
55
  }
56
56
  class MutableBundleGraph extends _BundleGraph.default {
57
- #graph /*: InternalBundleGraph */;
58
- #options /*: AtlaspackOptions */;
59
- #bundlePublicIds /*: Set<string> */ = new Set();
57
+ #graph;
58
+ #options;
59
+ #bundlePublicIds = new Set();
60
60
  constructor(graph, options) {
61
61
  super(graph, _Bundle.Bundle.get.bind(_Bundle.Bundle), options);
62
62
  this.#graph = graph;
@@ -6,8 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  let parcelOptionsToPluginOptions = new WeakMap();
8
8
  class PluginOptions {
9
- #options /*: AtlaspackOptions */;
10
-
9
+ #options;
11
10
  constructor(options) {
12
11
  let existing = parcelOptionsToPluginOptions.get(options);
13
12
  if (existing != null) {
@@ -24,9 +24,8 @@ function targetToInternalTarget(target) {
24
24
  return (0, _nullthrows().default)(_targetToInternalTarget.get(target));
25
25
  }
26
26
  class Target {
27
- #target /*: TargetValue */;
28
- #options /*: AtlaspackOptions */;
29
-
27
+ #target;
28
+ #options;
30
29
  constructor(target, options) {
31
30
  let existing = internalTargetToTarget.get(target);
32
31
  if (existing != null) {
@@ -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.0",
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.13",
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.0",
30
- "@atlaspack/fs": "2.15.13",
31
- "@atlaspack/graph": "3.5.7",
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.18",
34
- "@atlaspack/plugin": "2.14.18",
35
- "@atlaspack/profiler": "2.14.15",
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.8",
38
- "@atlaspack/utils": "2.17.0",
39
- "@atlaspack/workers": "2.14.18",
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();
package/src/Atlaspack.js CHANGED
@@ -72,20 +72,20 @@ export const INTERNAL_RESOLVE: symbol = Symbol('internal_resolve');
72
72
  export const WORKER_PATH: string = path.join(__dirname, 'worker.js');
73
73
 
74
74
  export default class Atlaspack {
75
- #requestTracker /*: RequestTracker*/;
76
- #config /*: AtlaspackConfig*/;
77
- #farm /*: WorkerFarm*/;
78
- #initialized /*: boolean*/ = false;
79
- #disposable /*: Disposable */;
80
- #initialOptions /*: InitialAtlaspackOptions */;
81
- #reporterRunner /*: ReporterRunner*/;
82
- #resolvedOptions /*: ?AtlaspackOptions*/ = null;
83
- #optionsRef /*: SharedReference */;
84
- #watchAbortController /*: AbortController*/;
85
- #watchQueue /*: PromiseQueue<?BuildEvent>*/ = new PromiseQueue<?BuildEvent>({
75
+ #requestTracker: RequestTracker;
76
+ #config: AtlaspackConfig;
77
+ #farm: WorkerFarm;
78
+ #initialized: boolean = false;
79
+ #disposable: Disposable;
80
+ #initialOptions: InitialAtlaspackOptions;
81
+ #reporterRunner: ReporterRunner;
82
+ #resolvedOptions: ?AtlaspackOptions = null;
83
+ #optionsRef: SharedReference;
84
+ #watchAbortController: AbortController;
85
+ #watchQueue: PromiseQueue<?BuildEvent> = new PromiseQueue<?BuildEvent>({
86
86
  maxConcurrent: 1,
87
87
  });
88
- #watchEvents /*: ValueEmitter<
88
+ #watchEvents: ValueEmitter<
89
89
  | {|
90
90
  +error: Error,
91
91
  +buildEvent?: void,
@@ -94,14 +94,14 @@ export default class Atlaspack {
94
94
  +buildEvent: BuildEvent,
95
95
  +error?: void,
96
96
  |},
97
- > */;
98
- #watcherSubscription /*: ?AsyncSubscription*/;
99
- #watcherCount /*: number*/ = 0;
100
- #requestedAssetIds /*: Set<string>*/ = new Set();
97
+ >;
98
+ #watcherSubscription: ?AsyncSubscription;
99
+ #watcherCount: number = 0;
100
+ #requestedAssetIds: Set<string> = new Set();
101
101
 
102
102
  rustAtlaspack: AtlaspackV3 | null | void;
103
103
 
104
- isProfiling /*: boolean */;
104
+ isProfiling: boolean;
105
105
 
106
106
  constructor(options: InitialAtlaspackOptions) {
107
107
  this.#initialOptions = options;
@@ -81,7 +81,7 @@ export function assetFromValue(
81
81
 
82
82
  class BaseAsset {
83
83
  #asset: CommittedAsset | UncommittedAsset;
84
- #query /*: ?URLSearchParams */;
84
+ #query: ?URLSearchParams;
85
85
 
86
86
  constructor(asset: CommittedAsset | UncommittedAsset) {
87
87
  this.#asset = asset;
@@ -195,8 +195,8 @@ class BaseAsset {
195
195
  }
196
196
 
197
197
  export class Asset extends BaseAsset implements IAsset {
198
- #asset /*: CommittedAsset | UncommittedAsset */;
199
- #env /*: ?Environment */;
198
+ #asset: CommittedAsset | UncommittedAsset;
199
+ #env: ?Environment;
200
200
 
201
201
  constructor(asset: CommittedAsset | UncommittedAsset): Asset {
202
202
  let assetValueToAsset = asset.value.committed
@@ -227,7 +227,7 @@ export class Asset extends BaseAsset implements IAsset {
227
227
  }
228
228
 
229
229
  export class MutableAsset extends BaseAsset implements IMutableAsset {
230
- #asset /*: UncommittedAsset */;
230
+ #asset: UncommittedAsset;
231
231
 
232
232
  constructor(asset: UncommittedAsset): MutableAsset {
233
233
  let existing = assetValueToMutableAsset.get(asset.value);
@@ -68,9 +68,9 @@ export function bundleToInternalBundleGraph(bundle: IBundle): BundleGraph {
68
68
  let _private = {};
69
69
 
70
70
  export class Bundle implements IBundle {
71
- #bundle /*: InternalBundle */;
72
- #bundleGraph /*: BundleGraph */;
73
- #options /*: AtlaspackOptions */;
71
+ #bundle: InternalBundle;
72
+ #bundleGraph: BundleGraph;
73
+ #options: AtlaspackOptions;
74
74
 
75
75
  // $FlowFixMe
76
76
  [inspect]() {
@@ -214,9 +214,9 @@ export class Bundle implements IBundle {
214
214
  }
215
215
 
216
216
  export class NamedBundle extends Bundle implements INamedBundle {
217
- #bundle /*: InternalBundle */;
218
- #bundleGraph /*: BundleGraph */;
219
- #options /*: AtlaspackOptions */;
217
+ #bundle: InternalBundle;
218
+ #bundleGraph: BundleGraph;
219
+ #options: AtlaspackOptions;
220
220
 
221
221
  constructor(
222
222
  sentinel: mixed,
@@ -268,10 +268,10 @@ export class NamedBundle extends Bundle implements INamedBundle {
268
268
  }
269
269
 
270
270
  export class PackagedBundle extends NamedBundle implements IPackagedBundle {
271
- #bundle /*: InternalBundle */;
272
- #bundleGraph /*: BundleGraph */;
273
- #options /*: AtlaspackOptions */;
274
- #bundleInfo /*: ?PackagedBundleInfo */;
271
+ #bundle: InternalBundle;
272
+ #bundleGraph: BundleGraph;
273
+ #options: AtlaspackOptions;
274
+ #bundleInfo: ?PackagedBundleInfo;
275
275
 
276
276
  constructor(
277
277
  sentinel: mixed,
@@ -28,8 +28,8 @@ export function bundleGroupToInternalBundleGroup(
28
28
  const inspect = Symbol.for('nodejs.util.inspect.custom');
29
29
 
30
30
  export default class BundleGroup implements IBundleGroup {
31
- #bundleGroup /*: InternalBundleGroup */;
32
- #options /*: AtlaspackOptions */;
31
+ #bundleGroup: InternalBundleGroup;
32
+ #options: AtlaspackOptions;
33
33
 
34
34
  constructor(
35
35
  bundleGroup: InternalBundleGroup,
@@ -104,10 +104,10 @@ export function makeConfigProxy<T>(
104
104
  }
105
105
 
106
106
  export default class PublicConfig implements IConfig {
107
- #config /*: Config */;
108
- #pkg /*: ?PackageJSON */;
109
- #pkgFilePath /*: ?FilePath */;
110
- #options /*: AtlaspackOptions */;
107
+ #config: Config;
108
+ #pkg: ?PackageJSON;
109
+ #pkgFilePath: ?FilePath;
110
+ #options: AtlaspackOptions;
111
111
 
112
112
  constructor(config: Config, options: AtlaspackOptions): PublicConfig {
113
113
  let existing = internalConfigToConfig.get(options).get(config);
@@ -59,8 +59,8 @@ export function getPublicDependency(
59
59
  }
60
60
 
61
61
  export default class Dependency implements IDependency {
62
- #dep /*: InternalDependency */;
63
- #options /*: AtlaspackOptions */;
62
+ #dep: InternalDependency;
63
+ #options: AtlaspackOptions;
64
64
 
65
65
  constructor(dep: InternalDependency, options: AtlaspackOptions): Dependency {
66
66
  this.#dep = dep;
@@ -156,8 +156,8 @@ export function environmentToInternalEnvironment(
156
156
  }
157
157
 
158
158
  export default class Environment implements IEnvironment {
159
- #environment /*: InternalEnvironment */;
160
- #options /*: AtlaspackOptions */;
159
+ #environment: InternalEnvironment;
160
+ #options: AtlaspackOptions;
161
161
 
162
162
  constructor(
163
163
  env: InternalEnvironment,
@@ -55,9 +55,9 @@ export default class MutableBundleGraph
55
55
  extends BundleGraph<IBundle>
56
56
  implements IMutableBundleGraph
57
57
  {
58
- #graph /*: InternalBundleGraph */;
59
- #options /*: AtlaspackOptions */;
60
- #bundlePublicIds /*: Set<string> */ = new Set<string>();
58
+ #graph: InternalBundleGraph;
59
+ #options: AtlaspackOptions;
60
+ #bundlePublicIds: Set<string> = new Set<string>();
61
61
 
62
62
  constructor(graph: InternalBundleGraph, options: AtlaspackOptions) {
63
63
  super(graph, Bundle.get.bind(Bundle), options);
@@ -18,7 +18,7 @@ let parcelOptionsToPluginOptions: WeakMap<AtlaspackOptions, PluginOptions> =
18
18
  new WeakMap();
19
19
 
20
20
  export default class PluginOptions implements IPluginOptions {
21
- #options /*: AtlaspackOptions */;
21
+ #options: AtlaspackOptions;
22
22
 
23
23
  constructor(options: AtlaspackOptions): PluginOptions {
24
24
  let existing = parcelOptionsToPluginOptions.get(options);
@@ -22,8 +22,8 @@ export function targetToInternalTarget(target: ITarget): TargetValue {
22
22
  }
23
23
 
24
24
  export default class Target implements ITarget {
25
- #target /*: TargetValue */;
26
- #options /*: AtlaspackOptions */;
25
+ #target: TargetValue;
26
+ #options: AtlaspackOptions;
27
27
 
28
28
  constructor(target: TargetValue, options: AtlaspackOptions): Target {
29
29
  let existing = internalTargetToTarget.get(target);
@@ -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', () => {