@atlaspack/core 2.16.2-canary.13 → 2.16.2-canary.131

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 (95) hide show
  1. package/CHANGELOG.md +300 -0
  2. package/index.d.ts +4 -0
  3. package/lib/AssetGraph.js +27 -7
  4. package/lib/Atlaspack.js +35 -27
  5. package/lib/AtlaspackConfig.schema.js +7 -1
  6. package/lib/BundleGraph.js +8 -5
  7. package/lib/Dependency.js +6 -2
  8. package/lib/Environment.js +5 -3
  9. package/lib/EnvironmentManager.js +137 -0
  10. package/lib/InternalConfig.js +3 -2
  11. package/lib/PackagerRunner.js +54 -16
  12. package/lib/RequestTracker.js +345 -132
  13. package/lib/SymbolPropagation.js +14 -0
  14. package/lib/Transformation.js +2 -2
  15. package/lib/UncommittedAsset.js +20 -2
  16. package/lib/applyRuntimes.js +2 -1
  17. package/lib/assetUtils.js +2 -1
  18. package/lib/atlaspack-v3/AtlaspackV3.js +16 -3
  19. package/lib/atlaspack-v3/worker/compat/environment.js +2 -2
  20. package/lib/atlaspack-v3/worker/compat/mutable-asset.js +6 -6
  21. package/lib/atlaspack-v3/worker/compat/plugin-config.js +5 -5
  22. package/lib/atlaspack-v3/worker/index.js +3 -0
  23. package/lib/atlaspack-v3/worker/worker.js +8 -0
  24. package/lib/dumpGraphToGraphViz.js +1 -1
  25. package/lib/index.js +29 -1
  26. package/lib/public/Asset.js +7 -9
  27. package/lib/public/Bundle.js +12 -13
  28. package/lib/public/BundleGraph.js +3 -2
  29. package/lib/public/BundleGroup.js +2 -3
  30. package/lib/public/Config.js +95 -8
  31. package/lib/public/Dependency.js +4 -4
  32. package/lib/public/Environment.js +2 -3
  33. package/lib/public/MutableBundleGraph.js +5 -4
  34. package/lib/public/PluginOptions.js +1 -2
  35. package/lib/public/Target.js +4 -4
  36. package/lib/requests/AssetGraphRequest.js +13 -1
  37. package/lib/requests/AssetGraphRequestRust.js +17 -2
  38. package/lib/requests/AssetRequest.js +2 -1
  39. package/lib/requests/BundleGraphRequest.js +13 -1
  40. package/lib/requests/ConfigRequest.js +27 -4
  41. package/lib/requests/DevDepRequest.js +11 -1
  42. package/lib/requests/PathRequest.js +10 -0
  43. package/lib/requests/TargetRequest.js +18 -16
  44. package/lib/requests/WriteBundleRequest.js +15 -3
  45. package/lib/requests/WriteBundlesRequest.js +22 -1
  46. package/lib/resolveOptions.js +7 -4
  47. package/lib/worker.js +18 -1
  48. package/package.json +18 -25
  49. package/src/AssetGraph.js +30 -7
  50. package/src/Atlaspack.js +40 -23
  51. package/src/BundleGraph.js +13 -8
  52. package/src/Dependency.js +13 -5
  53. package/src/Environment.js +9 -6
  54. package/src/EnvironmentManager.js +145 -0
  55. package/src/InternalConfig.js +6 -5
  56. package/src/PackagerRunner.js +72 -20
  57. package/src/RequestTracker.js +526 -157
  58. package/src/SymbolPropagation.js +13 -1
  59. package/src/UncommittedAsset.js +23 -3
  60. package/src/applyRuntimes.js +6 -1
  61. package/src/assetUtils.js +4 -3
  62. package/src/atlaspack-v3/AtlaspackV3.js +24 -3
  63. package/src/atlaspack-v3/worker/compat/plugin-config.js +9 -5
  64. package/src/atlaspack-v3/worker/index.js +2 -1
  65. package/src/atlaspack-v3/worker/worker.js +7 -0
  66. package/src/index.js +5 -1
  67. package/src/public/Asset.js +13 -6
  68. package/src/public/Bundle.js +12 -11
  69. package/src/public/BundleGraph.js +10 -2
  70. package/src/public/BundleGroup.js +2 -2
  71. package/src/public/Config.js +132 -18
  72. package/src/public/Dependency.js +4 -3
  73. package/src/public/Environment.js +2 -2
  74. package/src/public/MutableBundleGraph.js +8 -5
  75. package/src/public/PluginOptions.js +1 -1
  76. package/src/public/Target.js +4 -3
  77. package/src/requests/AssetGraphRequest.js +13 -3
  78. package/src/requests/AssetGraphRequestRust.js +14 -2
  79. package/src/requests/AssetRequest.js +2 -1
  80. package/src/requests/BundleGraphRequest.js +13 -3
  81. package/src/requests/ConfigRequest.js +33 -9
  82. package/src/requests/DevDepRequest.js +22 -9
  83. package/src/requests/PathRequest.js +4 -0
  84. package/src/requests/TargetRequest.js +19 -25
  85. package/src/requests/WriteBundleRequest.js +14 -8
  86. package/src/requests/WriteBundlesRequest.js +31 -3
  87. package/src/resolveOptions.js +4 -2
  88. package/src/types.js +10 -7
  89. package/test/Environment.test.js +43 -34
  90. package/test/EnvironmentManager.test.js +192 -0
  91. package/test/PublicEnvironment.test.js +10 -7
  92. package/test/RequestTracker.test.js +124 -29
  93. package/test/public/Config.test.js +108 -0
  94. package/test/requests/ConfigRequest.test.js +199 -7
  95. package/test/test-utils.js +4 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaspack/core",
3
- "version": "2.16.2-canary.13+e0f533757",
3
+ "version": "2.16.2-canary.131+75286ffe8",
4
4
  "license": "(MIT OR Apache-2.0)",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -10,6 +10,7 @@
10
10
  "url": "https://github.com/atlassian-labs/atlaspack.git"
11
11
  },
12
12
  "main": "lib/index.js",
13
+ "types": "index.d.ts",
13
14
  "source": "src/index.js",
14
15
  "engines": {
15
16
  "node": ">= 16.0.0"
@@ -20,21 +21,21 @@
20
21
  "check-ts": "tsc --noEmit index.d.ts"
21
22
  },
22
23
  "dependencies": {
23
- "@atlaspack/build-cache": "2.13.3-canary.81+e0f533757",
24
- "@atlaspack/cache": "3.1.1-canary.13+e0f533757",
25
- "@atlaspack/diagnostic": "2.14.1-canary.81+e0f533757",
26
- "@atlaspack/events": "2.14.1-canary.81+e0f533757",
27
- "@atlaspack/feature-flags": "2.14.1-canary.81+e0f533757",
28
- "@atlaspack/fs": "2.14.5-canary.13+e0f533757",
29
- "@atlaspack/graph": "3.4.1-canary.81+e0f533757",
30
- "@atlaspack/logger": "2.14.5-canary.13+e0f533757",
31
- "@atlaspack/package-manager": "2.14.5-canary.13+e0f533757",
32
- "@atlaspack/plugin": "2.14.5-canary.13+e0f533757",
33
- "@atlaspack/profiler": "2.14.1-canary.81+e0f533757",
34
- "@atlaspack/rust": "3.2.1-canary.13+e0f533757",
35
- "@atlaspack/types": "2.14.5-canary.13+e0f533757",
36
- "@atlaspack/utils": "2.14.5-canary.13+e0f533757",
37
- "@atlaspack/workers": "2.14.5-canary.13+e0f533757",
24
+ "@atlaspack/build-cache": "2.13.3-canary.199+75286ffe8",
25
+ "@atlaspack/cache": "3.1.1-canary.131+75286ffe8",
26
+ "@atlaspack/diagnostic": "2.14.1-canary.199+75286ffe8",
27
+ "@atlaspack/events": "2.14.1-canary.199+75286ffe8",
28
+ "@atlaspack/feature-flags": "2.14.1-canary.199+75286ffe8",
29
+ "@atlaspack/fs": "2.14.5-canary.131+75286ffe8",
30
+ "@atlaspack/graph": "3.4.1-canary.199+75286ffe8",
31
+ "@atlaspack/logger": "2.14.5-canary.131+75286ffe8",
32
+ "@atlaspack/package-manager": "2.14.5-canary.131+75286ffe8",
33
+ "@atlaspack/plugin": "2.14.5-canary.131+75286ffe8",
34
+ "@atlaspack/profiler": "2.14.1-canary.199+75286ffe8",
35
+ "@atlaspack/rust": "3.2.1-canary.131+75286ffe8",
36
+ "@atlaspack/types": "2.14.5-canary.131+75286ffe8",
37
+ "@atlaspack/utils": "2.14.5-canary.131+75286ffe8",
38
+ "@atlaspack/workers": "2.14.5-canary.131+75286ffe8",
38
39
  "@mischnic/json-sourcemap": "^0.1.0",
39
40
  "@parcel/source-map": "^2.1.1",
40
41
  "base-x": "^3.0.8",
@@ -55,17 +56,9 @@
55
56
  "rfdc": "1",
56
57
  "tempy": "^0.2.1"
57
58
  },
58
- "exports": {
59
- "./*": "./*",
60
- ".": "./lib/index.js",
61
- "./worker": {
62
- "@atlaspack::sources": "./src/worker.js",
63
- "default": "./lib/worker.js"
64
- }
65
- },
66
59
  "browser": {
67
60
  "./src/serializerCore.js": "./src/serializerCore.browser.js"
68
61
  },
69
62
  "type": "commonjs",
70
- "gitHead": "e0f533757bd1019dbd108a04952c87da15286e09"
63
+ "gitHead": "75286ffe8068fae73afa5954a6d2a0f53fbf5e0d"
71
64
  }
package/src/AssetGraph.js CHANGED
@@ -29,6 +29,12 @@ import nullthrows from 'nullthrows';
29
29
  import {ContentGraph} from '@atlaspack/graph';
30
30
  import {createDependency} from './Dependency';
31
31
  import {type ProjectPath, fromProjectPathRelative} from './projectPath';
32
+ import {
33
+ fromEnvironmentId,
34
+ toEnvironmentId,
35
+ toEnvironmentRef,
36
+ } from './EnvironmentManager';
37
+ import {getFeatureFlag} from '@atlaspack/feature-flags';
32
38
 
33
39
  type InitOpts = {|
34
40
  entries?: Array<ProjectPath>,
@@ -65,7 +71,7 @@ export function nodeFromAssetGroup(assetGroup: AssetGroup): AssetGroupNode {
65
71
  return {
66
72
  id: hashString(
67
73
  fromProjectPathRelative(assetGroup.filePath) +
68
- assetGroup.env.id +
74
+ toEnvironmentId(assetGroup.env) +
69
75
  String(assetGroup.isSource) +
70
76
  String(assetGroup.sideEffects) +
71
77
  (assetGroup.code ?? '') +
@@ -149,14 +155,18 @@ export default class AssetGraph extends ContentGraph<AssetGraphNode> {
149
155
 
150
156
  // Deduplicates Environments by making them referentially equal
151
157
  normalizeEnvironment(input: Asset | Dependency | AssetGroup) {
152
- let {id, context} = input.env;
158
+ if (getFeatureFlag('environmentDeduplication')) {
159
+ return;
160
+ }
161
+
162
+ let {id, context} = fromEnvironmentId(input.env);
153
163
  let idAndContext = `${id}-${context}`;
154
164
 
155
165
  let env = this.envCache.get(idAndContext);
156
166
  if (env) {
157
- input.env = env;
167
+ input.env = toEnvironmentRef(env);
158
168
  } else {
159
- this.envCache.set(idAndContext, input.env);
169
+ this.envCache.set(idAndContext, fromEnvironmentId(input.env));
160
170
  }
161
171
  }
162
172
 
@@ -235,13 +245,13 @@ export default class AssetGraph extends ContentGraph<AssetGraphNode> {
235
245
  env: target.env,
236
246
  isEntry: true,
237
247
  needsStableName: true,
238
- symbols: target.env.isLibrary
248
+ symbols: fromEnvironmentId(target.env).isLibrary
239
249
  ? new Map([['*', {local: '*', isWeak: true, loc: null}]])
240
250
  : undefined,
241
251
  }),
242
252
  );
243
253
 
244
- if (node.value.env.isLibrary) {
254
+ if (fromEnvironmentId(node.value.env).isLibrary) {
245
255
  // in library mode, all of the entry's symbols are "used"
246
256
  node.usedSymbolsDown.add('*');
247
257
  node.usedSymbolsUp.set('*', undefined);
@@ -428,7 +438,7 @@ export default class AssetGraph extends ContentGraph<AssetGraphNode> {
428
438
 
429
439
  let depIsDeferrable =
430
440
  d.symbols &&
431
- !(d.env.isLibrary && d.isEntry) &&
441
+ !(fromEnvironmentId(d.env).isLibrary && d.isEntry) &&
432
442
  !d.symbols.has('*') &&
433
443
  ![...d.symbols.keys()].some((symbol) => {
434
444
  let assetSymbol = resolvedAsset.symbols?.get(symbol)?.local;
@@ -532,6 +542,19 @@ export default class AssetGraph extends ContentGraph<AssetGraphNode> {
532
542
  ...depNode.value.meta,
533
543
  ...existing.value.resolverMeta,
534
544
  };
545
+
546
+ if (getFeatureFlag('hmrImprovements')) {
547
+ depNode.value.resolverMeta = existing.value.resolverMeta;
548
+ }
549
+ }
550
+ if (getFeatureFlag('hmrImprovements')) {
551
+ if (
552
+ existing?.type === 'dependency' &&
553
+ existing.value.resolverPriority != null
554
+ ) {
555
+ depNode.value.priority = existing.value.resolverPriority;
556
+ depNode.value.resolverPriority = existing.value.resolverPriority;
557
+ }
535
558
  }
536
559
  let dependentAsset = dependentAssets.find(
537
560
  (a) => a.uniqueKey === dep.specifier,
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;
@@ -165,10 +165,17 @@ export default class Atlaspack {
165
165
  const version = require('../package.json').version;
166
166
  await lmdb.put('current_session_version', Buffer.from(version));
167
167
 
168
+ let threads = undefined;
169
+ if (process.env.ATLASPACK_NATIVE_THREADS !== undefined) {
170
+ threads = parseInt(process.env.ATLASPACK_NATIVE_THREADS, 10);
171
+ } else if (process.env.NODE_ENV === 'test') {
172
+ threads = 2;
173
+ }
174
+
168
175
  rustAtlaspack = await AtlaspackV3.create({
169
176
  ...options,
170
177
  corePath: path.join(__dirname, '..'),
171
- threads: process.env.NODE_ENV === 'test' ? 2 : undefined,
178
+ threads,
172
179
  entries: Array.isArray(entries)
173
180
  ? entries
174
181
  : entries == null
@@ -180,6 +187,11 @@ export default class Atlaspack {
180
187
  defaultTargetOptions: resolvedOptions.defaultTargetOptions,
181
188
  lmdb,
182
189
  });
190
+ if (featureFlags.atlaspackV3CleanShutdown) {
191
+ this.#disposable.add(() => {
192
+ rustAtlaspack.end();
193
+ });
194
+ }
183
195
  }
184
196
  this.rustAtlaspack = rustAtlaspack;
185
197
 
@@ -371,7 +383,6 @@ export default class Atlaspack {
371
383
  |} = {
372
384
  /*::...null*/
373
385
  }): Promise<BuildEvent> {
374
- this.#requestTracker.setSignal(signal);
375
386
  let options = nullthrows(this.#resolvedOptions);
376
387
  try {
377
388
  if (options.shouldProfile) {
@@ -379,6 +390,11 @@ export default class Atlaspack {
379
390
  }
380
391
  if (options.shouldTrace) {
381
392
  tracer.enable();
393
+ // We need to ensure the tracer is disabled when Atlaspack is disposed as it is a module level object.
394
+ // While rare (except for tests), if another instance is created later it should not have tracing enabled.
395
+ this.#disposable.add(() => {
396
+ tracer.disable();
397
+ });
382
398
  }
383
399
  await this.#reporterRunner.report({
384
400
  type: 'buildStart',
@@ -526,10 +542,11 @@ export default class Atlaspack {
526
542
  nativeInvalid = await this.rustAtlaspack.respondToFsEvents(events);
527
543
  }
528
544
 
529
- let isInvalid = await this.#requestTracker.respondToFSEvents(
530
- events,
531
- Number.POSITIVE_INFINITY,
532
- );
545
+ let {didInvalidate: isInvalid} =
546
+ await this.#requestTracker.respondToFSEvents(
547
+ events,
548
+ Number.POSITIVE_INFINITY,
549
+ );
533
550
 
534
551
  if (
535
552
  (nativeInvalid || isInvalid) &&
@@ -24,7 +24,6 @@ import type {
24
24
  BundleNode,
25
25
  Dependency,
26
26
  DependencyNode,
27
- Environment,
28
27
  InternalSourceLocation,
29
28
  Target,
30
29
  Condition,
@@ -49,6 +48,8 @@ import {ISOLATED_ENVS} from './public/Environment';
49
48
  import {fromProjectPath, fromProjectPathRelative} from './projectPath';
50
49
  import {HASH_REF_PREFIX} from './constants';
51
50
  import {getFeatureFlag} from '@atlaspack/feature-flags';
51
+ import {fromEnvironmentId} from './EnvironmentManager';
52
+ import type {EnvironmentRef} from './EnvironmentManager';
52
53
 
53
54
  export const bundleGraphEdgeTypes = {
54
55
  // A lack of an edge type indicates to follow the edge while traversing
@@ -283,7 +284,7 @@ export default class BundleGraph {
283
284
  if (
284
285
  node.type === 'dependency' &&
285
286
  node.value.symbols != null &&
286
- node.value.env.shouldScopeHoist &&
287
+ fromEnvironmentId(node.value.env).shouldScopeHoist &&
287
288
  // Disable in dev mode because this feature is at odds with safeToIncrementallyBundle
288
289
  isProduction
289
290
  ) {
@@ -555,11 +556,11 @@ export default class BundleGraph {
555
556
  +needsStableName?: ?boolean,
556
557
  +bundleBehavior?: ?IBundleBehavior,
557
558
  +shouldContentHash: boolean,
558
- +env: Environment,
559
+ +env: EnvironmentRef,
559
560
  |}
560
561
  | {|
561
562
  +type: string,
562
- +env: Environment,
563
+ +env: EnvironmentRef,
563
564
  +uniqueKey: string,
564
565
  +target: Target,
565
566
  +needsStableName?: ?boolean,
@@ -1359,7 +1360,8 @@ export default class BundleGraph {
1359
1360
 
1360
1361
  if (
1361
1362
  descendant.type !== bundle.type ||
1362
- descendant.env.context !== bundle.env.context
1363
+ fromEnvironmentId(descendant.env).context !==
1364
+ fromEnvironmentId(bundle.env).context
1363
1365
  ) {
1364
1366
  actions.skipChildren();
1365
1367
  return;
@@ -1400,7 +1402,7 @@ export default class BundleGraph {
1400
1402
  // If a bundle's environment is isolated, it can't access assets present
1401
1403
  // in any ancestor bundles. Don't consider any assets reachable.
1402
1404
  if (
1403
- ISOLATED_ENVS.has(bundle.env.context) ||
1405
+ ISOLATED_ENVS.has(fromEnvironmentId(bundle.env).context) ||
1404
1406
  !bundle.isSplittable ||
1405
1407
  bundle.bundleBehavior === BundleBehavior.isolated ||
1406
1408
  bundle.bundleBehavior === BundleBehavior.inline
@@ -1454,7 +1456,8 @@ export default class BundleGraph {
1454
1456
  node.type === 'root' ||
1455
1457
  (node.type === 'bundle' &&
1456
1458
  (node.value.id === bundle.id ||
1457
- node.value.env.context !== bundle.env.context))
1459
+ fromEnvironmentId(node.value.env).context !==
1460
+ fromEnvironmentId(bundle.env).context))
1458
1461
  ) {
1459
1462
  isReachable = false;
1460
1463
  actions.stop();
@@ -2128,7 +2131,9 @@ export default class BundleGraph {
2128
2131
  hash.writeString(referencedBundle.id);
2129
2132
  }
2130
2133
 
2131
- hash.writeString(JSON.stringify(objectSortedEntriesDeep(bundle.env)));
2134
+ hash.writeString(
2135
+ JSON.stringify(objectSortedEntriesDeep(fromEnvironmentId(bundle.env))),
2136
+ );
2132
2137
  return hash.finish();
2133
2138
  }
2134
2139
 
package/src/Dependency.js CHANGED
@@ -8,7 +8,7 @@ import type {
8
8
  BundleBehavior as IBundleBehavior,
9
9
  SemverRange,
10
10
  } from '@atlaspack/types';
11
- import type {Dependency, Environment, Target} from './types';
11
+ import type {Dependency, Target} from './types';
12
12
  import {createDependencyId as createDependencyIdRust} from '@atlaspack/rust';
13
13
  import {
14
14
  SpecifierType,
@@ -21,6 +21,8 @@ import {toInternalSourceLocation} from './utils';
21
21
  import {toProjectPath} from './projectPath';
22
22
  import assert from 'assert';
23
23
  import {identifierRegistry} from './IdentifierRegistry';
24
+ import {fromEnvironmentId, toEnvironmentId} from './EnvironmentManager';
25
+ import type {EnvironmentRef} from './EnvironmentManager';
24
26
 
25
27
  type DependencyOpts = {|
26
28
  id?: string,
@@ -34,7 +36,7 @@ type DependencyOpts = {|
34
36
  isEntry?: boolean,
35
37
  isOptional?: boolean,
36
38
  loc?: SourceLocation,
37
- env: Environment,
39
+ env: EnvironmentRef,
38
40
  packageConditions?: Array<string>,
39
41
  meta?: Meta,
40
42
  resolveFrom?: FilePath,
@@ -60,7 +62,7 @@ export function createDependencyId({
60
62
  }: {|
61
63
  sourceAssetId?: string | void,
62
64
  specifier: DependencySpecifier,
63
- env: Environment,
65
+ env: EnvironmentRef,
64
66
  target?: Target | void,
65
67
  pipeline?: ?string,
66
68
  specifierType: $Keys<typeof SpecifierType>,
@@ -73,8 +75,14 @@ export function createDependencyId({
73
75
  const params = {
74
76
  sourceAssetId,
75
77
  specifier,
76
- environmentId: env.id,
77
- target,
78
+ environmentId: toEnvironmentId(env),
79
+ target:
80
+ target != null
81
+ ? {
82
+ ...target,
83
+ env: fromEnvironmentId(target.env),
84
+ }
85
+ : null,
78
86
  pipeline,
79
87
  specifierType: SpecifierType[specifierType],
80
88
  bundleBehavior,
@@ -10,6 +10,8 @@ import {toInternalSourceLocation} from './utils';
10
10
  import PublicEnvironment from './public/Environment';
11
11
  import {environmentToInternalEnvironment} from './public/Environment';
12
12
  import {identifierRegistry} from './IdentifierRegistry';
13
+ import {toEnvironmentRef} from './EnvironmentManager';
14
+ import type {EnvironmentRef} from './EnvironmentManager';
13
15
 
14
16
  const DEFAULT_ENGINES = {
15
17
  browsers: ['> 0.25%'],
@@ -35,7 +37,7 @@ export function createEnvironment({
35
37
  loc,
36
38
  }: EnvironmentOpts = {
37
39
  /*::...null*/
38
- }): Environment {
40
+ }): EnvironmentRef {
39
41
  if (context == null) {
40
42
  if (engines?.node) {
41
43
  context = 'node';
@@ -112,21 +114,22 @@ export function createEnvironment({
112
114
  };
113
115
 
114
116
  res.id = getEnvironmentHash(res);
115
- return Object.freeze(res);
117
+
118
+ return toEnvironmentRef(Object.freeze(res));
116
119
  }
117
120
 
118
121
  export function mergeEnvironments(
119
122
  projectRoot: FilePath,
120
123
  a: Environment,
121
124
  b: ?(EnvironmentOptions | IEnvironment),
122
- ): Environment {
125
+ ): EnvironmentRef {
123
126
  // If merging the same object, avoid copying.
124
127
  if (a === b || !b) {
125
- return a;
128
+ return toEnvironmentRef(a);
126
129
  }
127
130
 
128
131
  if (b instanceof PublicEnvironment) {
129
- return environmentToInternalEnvironment(b);
132
+ return toEnvironmentRef(environmentToInternalEnvironment(b));
130
133
  }
131
134
 
132
135
  // $FlowFixMe - ignore the `id` that is already on a
@@ -137,7 +140,7 @@ export function mergeEnvironments(
137
140
  });
138
141
  }
139
142
 
140
- function getEnvironmentHash(env: Environment): string {
143
+ export function getEnvironmentHash(env: Environment): string {
141
144
  const data = {
142
145
  context: env.context,
143
146
  engines: env.engines,
@@ -0,0 +1,145 @@
1
+ // @flow strict-local
2
+ /*!
3
+ * At the moment we're doing this change for `CoreEnvironment`,
4
+ * but the same change must be made for `TypesEnvironment` in @atlaspack/types.
5
+ */
6
+ import type {Environment as CoreEnvironment} from './types';
7
+ import {type Cache} from '@atlaspack/cache';
8
+ import {
9
+ addEnvironment,
10
+ getEnvironment,
11
+ getAllEnvironments,
12
+ setAllEnvironments,
13
+ } from '@atlaspack/rust';
14
+ import {getFeatureFlag} from '@atlaspack/feature-flags';
15
+ import {instrument} from '@atlaspack/logger';
16
+ import {ATLASPACK_VERSION} from './constants';
17
+
18
+ const localEnvironmentCache = new Map<string, CoreEnvironment>();
19
+
20
+ export opaque type EnvironmentId = string;
21
+ /**
22
+ * When deduplication is cleaned-up this will always be a string.
23
+ */
24
+ export opaque type EnvironmentRef = EnvironmentId | CoreEnvironment;
25
+
26
+ /**
27
+ * Convert environment to a ref.
28
+ * This is what we should be using to store environments.
29
+ */
30
+ export function toEnvironmentRef(env: CoreEnvironment): EnvironmentRef {
31
+ if (!getFeatureFlag('environmentDeduplication')) {
32
+ return env;
33
+ }
34
+
35
+ const id = toEnvironmentId(env);
36
+ return id;
37
+ }
38
+
39
+ /**
40
+ * Convert environment to a string ID
41
+ */
42
+ export function toEnvironmentId(
43
+ /**
44
+ * Redundant type during roll-out
45
+ */
46
+ env: CoreEnvironment | EnvironmentRef,
47
+ ): string {
48
+ if (!getFeatureFlag('environmentDeduplication')) {
49
+ return typeof env === 'string' ? env : env.id;
50
+ }
51
+
52
+ if (typeof env === 'string') {
53
+ return env;
54
+ }
55
+
56
+ addEnvironment(env);
57
+ return env.id;
58
+ }
59
+
60
+ export function fromEnvironmentId(id: EnvironmentRef): CoreEnvironment {
61
+ if (!getFeatureFlag('environmentDeduplication')) {
62
+ if (typeof id === 'string') {
63
+ throw new Error(
64
+ 'This should never happen when environmentDeduplication feature-flag is off',
65
+ );
66
+ } else {
67
+ return id;
68
+ }
69
+ }
70
+
71
+ if (typeof id !== 'string') {
72
+ return id;
73
+ }
74
+
75
+ const localEnv = localEnvironmentCache.get(id);
76
+
77
+ if (localEnv) {
78
+ return localEnv;
79
+ }
80
+
81
+ const env = Object.freeze(getEnvironment(id));
82
+ localEnvironmentCache.set(id, env);
83
+ return env;
84
+ }
85
+
86
+ /**
87
+ * Writes all environments and their IDs to the cache
88
+ * @param {Cache} cache
89
+ * @returns {Promise<void>}
90
+ */
91
+ export async function writeEnvironmentsToCache(cache: Cache): Promise<void> {
92
+ const environments = getAllEnvironments();
93
+ const environmentIds = new Set<string>();
94
+
95
+ // Store each environment individually
96
+ for (const env of environments) {
97
+ environmentIds.add(env.id);
98
+ const envKey = `Environment/${ATLASPACK_VERSION}/${env.id}`;
99
+
100
+ await instrument(
101
+ `RequestTracker::writeToCache::cache.put(${envKey})`,
102
+ async () => {
103
+ await cache.set(envKey, env);
104
+ },
105
+ );
106
+ }
107
+
108
+ // Store the list of environment IDs
109
+ await instrument(
110
+ `RequestTracker::writeToCache::cache.put(${`EnvironmentManager/${ATLASPACK_VERSION}`})`,
111
+ async () => {
112
+ await cache.set(
113
+ `EnvironmentManager/${ATLASPACK_VERSION}`,
114
+ Array.from(environmentIds),
115
+ );
116
+ },
117
+ );
118
+ }
119
+
120
+ /**
121
+ * Loads all environments and their IDs from the cache
122
+ * @param {Cache} cache
123
+ * @returns {Promise<void>}
124
+ */
125
+ export async function loadEnvironmentsFromCache(cache: Cache): Promise<void> {
126
+ const cachedEnvIds = await cache.get(
127
+ `EnvironmentManager/${ATLASPACK_VERSION}`,
128
+ );
129
+
130
+ if (cachedEnvIds == null) {
131
+ return;
132
+ }
133
+
134
+ const environments = [];
135
+ for (const envId of cachedEnvIds) {
136
+ const envKey = `Environment/${ATLASPACK_VERSION}/${envId}`;
137
+ const cachedEnv = await cache.get(envKey);
138
+ if (cachedEnv != null) {
139
+ environments.push(cachedEnv);
140
+ }
141
+ }
142
+ if (environments.length > 0) {
143
+ setAllEnvironments(environments);
144
+ }
145
+ }
@@ -3,7 +3,6 @@
3
3
  import type {PackageName, ConfigResult} from '@atlaspack/types';
4
4
  import type {
5
5
  Config,
6
- Environment,
7
6
  InternalFileCreateInvalidation,
8
7
  InternalDevDepOptions,
9
8
  } from './types';
@@ -13,17 +12,19 @@ import {fromProjectPathRelative} from './projectPath';
13
12
  import {createEnvironment} from './Environment';
14
13
  import {hashString} from '@atlaspack/rust';
15
14
  import {identifierRegistry} from './IdentifierRegistry';
15
+ import type {EnvironmentRef} from './EnvironmentManager';
16
+ import {toEnvironmentId} from './EnvironmentManager';
16
17
 
17
18
  type ConfigOpts = {|
18
19
  plugin: PackageName,
19
20
  searchPath: ProjectPath,
20
21
  isSource?: boolean,
21
- env?: Environment,
22
+ env?: EnvironmentRef,
22
23
  result?: ConfigResult,
23
24
  invalidateOnFileChange?: Set<ProjectPath>,
24
25
  invalidateOnConfigKeyChange?: Array<{|
25
26
  filePath: ProjectPath,
26
- configKey: string,
27
+ configKey: string[],
27
28
  |}>,
28
29
  invalidateOnFileCreate?: Array<InternalFileCreateInvalidation>,
29
30
  invalidateOnEnvChange?: Set<string>,
@@ -52,13 +53,13 @@ export function createConfig({
52
53
  const configId = hashString(
53
54
  plugin +
54
55
  fromProjectPathRelative(searchPath) +
55
- environment.id +
56
+ toEnvironmentId(environment) +
56
57
  String(isSource),
57
58
  );
58
59
  identifierRegistry.addIdentifier('config_request', configId, {
59
60
  plugin,
60
61
  searchPath,
61
- environmentId: environment.id,
62
+ environmentId: toEnvironmentId(environment),
62
63
  isSource,
63
64
  });
64
65
  return {