@atlaspack/core 2.17.4 → 2.18.0

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 (54) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/lib/AssetGraph.js +17 -6
  3. package/lib/BundleGraph.js +6 -5
  4. package/lib/Dependency.js +6 -2
  5. package/lib/Environment.js +4 -3
  6. package/lib/EnvironmentManager.js +137 -0
  7. package/lib/InternalConfig.js +3 -2
  8. package/lib/PackagerRunner.js +10 -7
  9. package/lib/RequestTracker.js +20 -5
  10. package/lib/UncommittedAsset.js +3 -2
  11. package/lib/applyRuntimes.js +2 -1
  12. package/lib/assetUtils.js +2 -1
  13. package/lib/public/Asset.js +3 -2
  14. package/lib/public/Bundle.js +2 -1
  15. package/lib/public/Config.js +86 -19
  16. package/lib/public/Dependency.js +2 -1
  17. package/lib/public/MutableBundleGraph.js +2 -1
  18. package/lib/public/Target.js +2 -1
  19. package/lib/requests/AssetRequest.js +2 -1
  20. package/lib/requests/ConfigRequest.js +27 -4
  21. package/lib/requests/TargetRequest.js +18 -16
  22. package/lib/requests/WriteBundleRequest.js +5 -2
  23. package/lib/requests/WriteBundlesRequest.js +1 -0
  24. package/package.json +11 -11
  25. package/src/AssetGraph.js +12 -6
  26. package/src/BundleGraph.js +13 -8
  27. package/src/Dependency.js +13 -5
  28. package/src/Environment.js +8 -5
  29. package/src/EnvironmentManager.js +145 -0
  30. package/src/InternalConfig.js +6 -5
  31. package/src/PackagerRunner.js +12 -11
  32. package/src/RequestTracker.js +39 -13
  33. package/src/UncommittedAsset.js +7 -2
  34. package/src/applyRuntimes.js +6 -1
  35. package/src/assetUtils.js +4 -3
  36. package/src/atlaspack-v3/worker/compat/plugin-config.js +1 -1
  37. package/src/public/Asset.js +9 -2
  38. package/src/public/Bundle.js +2 -1
  39. package/src/public/Config.js +110 -29
  40. package/src/public/Dependency.js +2 -1
  41. package/src/public/MutableBundleGraph.js +2 -1
  42. package/src/public/Target.js +2 -1
  43. package/src/requests/AssetRequest.js +2 -1
  44. package/src/requests/ConfigRequest.js +33 -9
  45. package/src/requests/TargetRequest.js +19 -25
  46. package/src/requests/WriteBundleRequest.js +6 -7
  47. package/src/requests/WriteBundlesRequest.js +1 -0
  48. package/src/types.js +9 -7
  49. package/test/Environment.test.js +43 -34
  50. package/test/EnvironmentManager.test.js +192 -0
  51. package/test/PublicEnvironment.test.js +10 -7
  52. package/test/public/Config.test.js +108 -0
  53. package/test/requests/ConfigRequest.test.js +187 -3
  54. package/test/test-utils.js +3 -2
@@ -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
@@ -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 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 {
@@ -63,6 +63,7 @@ import {getInvalidationId, getInvalidationHash} from './assetUtils';
63
63
  import {optionsProxy} from './utils';
64
64
  import {invalidateDevDeps} from './requests/DevDepRequest';
65
65
  import {tracer, PluginTracer} from '@atlaspack/profiler';
66
+ import {fromEnvironmentId} from './EnvironmentManager';
66
67
  import {getFeatureFlag} from '@atlaspack/feature-flags';
67
68
 
68
69
  type Opts = {|
@@ -578,32 +579,32 @@ export default class PackagerRunner {
578
579
  );
579
580
  let inlineSources = false;
580
581
 
582
+ const bundleEnv = fromEnvironmentId(bundle.env);
581
583
  if (bundle.target) {
582
- if (
583
- bundle.env.sourceMap &&
584
- bundle.env.sourceMap.sourceRoot !== undefined
585
- ) {
586
- sourceRoot = bundle.env.sourceMap.sourceRoot;
584
+ const bundleTargetEnv = fromEnvironmentId(bundle.target.env);
585
+
586
+ if (bundleEnv.sourceMap && bundleEnv.sourceMap.sourceRoot !== undefined) {
587
+ sourceRoot = bundleEnv.sourceMap.sourceRoot;
587
588
  } else if (
588
589
  this.options.serveOptions &&
589
- bundle.target.env.context === 'browser'
590
+ bundleTargetEnv.context === 'browser'
590
591
  ) {
591
592
  sourceRoot = '/__parcel_source_root';
592
593
  }
593
594
 
594
595
  if (
595
- bundle.env.sourceMap &&
596
- bundle.env.sourceMap.inlineSources !== undefined
596
+ bundleEnv.sourceMap &&
597
+ bundleEnv.sourceMap.inlineSources !== undefined
597
598
  ) {
598
- inlineSources = bundle.env.sourceMap.inlineSources;
599
- } else if (bundle.target.env.context !== 'node') {
599
+ inlineSources = bundleEnv.sourceMap.inlineSources;
600
+ } else if (bundleTargetEnv.context !== 'node') {
600
601
  // inlining should only happen in production for browser targets by default
601
602
  inlineSources = this.options.mode === 'production';
602
603
  }
603
604
  }
604
605
 
605
606
  let mapFilename = fullPath + '.map';
606
- let isInlineMap = bundle.env.sourceMap && bundle.env.sourceMap.inline;
607
+ let isInlineMap = bundleEnv.sourceMap && bundleEnv.sourceMap.inline;
607
608
 
608
609
  let stringified = await map.stringify({
609
610
  file: path.basename(mapFilename),
@@ -30,15 +30,15 @@ import nullthrows from 'nullthrows';
30
30
 
31
31
  import {
32
32
  ATLASPACK_VERSION,
33
- VALID,
34
- INITIAL_BUILD,
35
33
  FILE_CREATE,
36
- FILE_UPDATE,
37
34
  FILE_DELETE,
35
+ FILE_UPDATE,
38
36
  ENV_CHANGE,
37
+ ERROR,
38
+ INITIAL_BUILD,
39
39
  OPTION_CHANGE,
40
40
  STARTUP,
41
- ERROR,
41
+ VALID,
42
42
  } from './constants';
43
43
  import type {AtlaspackV3} from './atlaspack-v3/AtlaspackV3';
44
44
  import {
@@ -71,6 +71,11 @@ import type {
71
71
  import {BuildAbortError, assertSignalNotAborted, hashFromOption} from './utils';
72
72
  import {performance} from 'perf_hooks';
73
73
 
74
+ import {
75
+ loadEnvironmentsFromCache,
76
+ writeEnvironmentsToCache,
77
+ } from './EnvironmentManager';
78
+
74
79
  export const requestGraphEdgeTypes = {
75
80
  subrequest: 2,
76
81
  invalidated_by_update: 3,
@@ -144,7 +149,7 @@ type OptionNode = {|
144
149
  type ConfigKeyNode = {|
145
150
  id: ContentKey,
146
151
  +type: typeof CONFIG_KEY,
147
- configKey: string,
152
+ configKey: string[],
148
153
  contentHash: string,
149
154
  |};
150
155
 
@@ -216,7 +221,7 @@ export type RunAPI<TResult: RequestResult> = {|
216
221
  invalidateOnFileUpdate: (ProjectPath) => void,
217
222
  invalidateOnConfigKeyChange: (
218
223
  filePath: ProjectPath,
219
- configKey: string,
224
+ configKey: string[],
220
225
  contentHash: string,
221
226
  ) => void,
222
227
  invalidateOnStartup: () => void,
@@ -283,10 +288,12 @@ const nodeFromOption = (option: string, value: mixed): RequestGraphNode => ({
283
288
 
284
289
  const nodeFromConfigKey = (
285
290
  fileName: ProjectPath,
286
- configKey: string,
291
+ configKey: string[],
287
292
  contentHash: string,
288
293
  ): RequestGraphNode => ({
289
- id: `config_key:${fromProjectPathRelative(fileName)}:${configKey}`,
294
+ id: `config_key:${fromProjectPathRelative(fileName)}:${JSON.stringify(
295
+ configKey,
296
+ )}`,
290
297
  type: CONFIG_KEY,
291
298
  configKey,
292
299
  contentHash,
@@ -527,7 +534,7 @@ export class RequestGraph extends ContentGraph<
527
534
  invalidateOnConfigKeyChange(
528
535
  requestNodeId: NodeId,
529
536
  filePath: ProjectPath,
530
- configKey: string,
537
+ configKey: string[],
531
538
  contentHash: string,
532
539
  ) {
533
540
  let configKeyNodeId = this.addNode(
@@ -714,8 +721,8 @@ export class RequestGraph extends ContentGraph<
714
721
  env: string,
715
722
  value: string | void,
716
723
  ) {
717
- let envNode = nodeFromEnv(env, value);
718
- let envNodeId = this.addNode(envNode);
724
+ const envNode = nodeFromEnv(env, value);
725
+ const envNodeId = this.addNode(envNode);
719
726
 
720
727
  if (
721
728
  !this.hasEdge(
@@ -1109,11 +1116,22 @@ export class RequestGraph extends ContentGraph<
1109
1116
  }
1110
1117
 
1111
1118
  let configKeyNodes = this.configKeyNodes.get(_filePath);
1112
- if (configKeyNodes && (type === 'delete' || type === 'update')) {
1119
+
1120
+ // With granular invalidations we will always run this block,
1121
+ // so even if we get a create event (for whatever reason), we will still
1122
+ // try to limit invalidations from config key changes through hashing.
1123
+ //
1124
+ // Currently create events can invalidate a large number of nodes due to
1125
+ // "create above" invalidations.
1126
+ const isConfigKeyChange =
1127
+ getFeatureFlag('granularTsConfigInvalidation') ||
1128
+ type === 'delete' ||
1129
+ type === 'update';
1130
+ if (configKeyNodes && isConfigKeyChange) {
1113
1131
  for (let nodeId of configKeyNodes) {
1114
1132
  let isInvalid = type === 'delete';
1115
1133
 
1116
- if (type === 'update') {
1134
+ if (type !== 'delete') {
1117
1135
  let node = this.getNode(nodeId);
1118
1136
  invariant(node && node.type === CONFIG_KEY);
1119
1137
 
@@ -1559,6 +1577,10 @@ export default class RequestTracker {
1559
1577
  size: this.graph.nodes.length,
1560
1578
  });
1561
1579
 
1580
+ if (getFeatureFlag('environmentDeduplication')) {
1581
+ await writeEnvironmentsToCache(options.cache);
1582
+ }
1583
+
1562
1584
  let serialisedGraph = this.graph.serialize();
1563
1585
 
1564
1586
  // Delete an existing request graph cache, to prevent invalid states
@@ -1843,6 +1865,10 @@ async function loadRequestGraph(options): Async<RequestGraph> {
1843
1865
  },
1844
1866
  });
1845
1867
 
1868
+ if (getFeatureFlag('environmentDeduplication')) {
1869
+ await loadEnvironmentsFromCache(options.cache);
1870
+ }
1871
+
1846
1872
  const hasRequestGraphInCache = getFeatureFlag('cachePerformanceImprovements')
1847
1873
  ? await options.cache.has(requestGraphKey)
1848
1874
  : await options.cache.hasLargeBlob(requestGraphKey);
@@ -36,6 +36,7 @@ import {
36
36
  fromProjectPathRelative,
37
37
  } from './projectPath';
38
38
  import {getFeatureFlag} from '@atlaspack/feature-flags';
39
+ import {fromEnvironmentId} from './EnvironmentManager';
39
40
 
40
41
  type UncommittedAssetOptions = {|
41
42
  value: Asset,
@@ -321,7 +322,11 @@ export default class UncommittedAsset {
321
322
  ...rest,
322
323
  // $FlowFixMe "convert" the $ReadOnlyMaps to the interal mutable one
323
324
  symbols,
324
- env: mergeEnvironments(this.options.projectRoot, this.value.env, env),
325
+ env: mergeEnvironments(
326
+ this.options.projectRoot,
327
+ fromEnvironmentId(this.value.env),
328
+ env,
329
+ ),
325
330
  sourceAssetId: this.value.id,
326
331
  sourcePath: fromProjectPath(
327
332
  this.options.projectRoot,
@@ -386,7 +391,7 @@ export default class UncommittedAsset {
386
391
  isSource: this.value.isSource,
387
392
  env: mergeEnvironments(
388
393
  this.options.projectRoot,
389
- this.value.env,
394
+ fromEnvironmentId(this.value.env),
390
395
  result.env,
391
396
  ),
392
397
  dependencies:
@@ -34,6 +34,7 @@ import {createDevDependency, runDevDepRequest} from './requests/DevDepRequest';
34
34
  import {toProjectPath, fromProjectPathRelative} from './projectPath';
35
35
  import {tracer, PluginTracer} from '@atlaspack/profiler';
36
36
  import {DefaultMap} from '@atlaspack/utils';
37
+ import {fromEnvironmentId} from './EnvironmentManager';
37
38
 
38
39
  type RuntimeConnection = {|
39
40
  bundle: InternalBundle,
@@ -159,7 +160,11 @@ export default async function applyRuntimes<TResult: RequestResult>({
159
160
  let assetGroup = {
160
161
  code,
161
162
  filePath: toProjectPath(options.projectRoot, sourceName),
162
- env: mergeEnvironments(options.projectRoot, bundle.env, env),
163
+ env: mergeEnvironments(
164
+ options.projectRoot,
165
+ fromEnvironmentId(bundle.env),
166
+ env,
167
+ ),
163
168
  // Runtime assets should be considered source, as they should be
164
169
  // e.g. compiled to run in the target environment
165
170
  isSource: true,
package/src/assetUtils.js CHANGED
@@ -16,7 +16,6 @@ import type {
16
16
  Asset,
17
17
  RequestInvalidation,
18
18
  Dependency,
19
- Environment,
20
19
  AtlaspackOptions,
21
20
  } from './types';
22
21
 
@@ -40,6 +39,8 @@ import {hashString, createAssetId as createAssetIdRust} from '@atlaspack/rust';
40
39
  import {BundleBehavior as BundleBehaviorMap} from './types';
41
40
  import {PluginTracer} from '@atlaspack/profiler';
42
41
  import {identifierRegistry} from './IdentifierRegistry';
42
+ import type {EnvironmentRef} from './EnvironmentManager';
43
+ import {toEnvironmentId} from './EnvironmentManager';
43
44
 
44
45
  export type AssetOptions = {|
45
46
  id?: string,
@@ -56,7 +57,7 @@ export type AssetOptions = {|
56
57
  bundleBehavior?: ?BundleBehavior,
57
58
  isBundleSplittable?: ?boolean,
58
59
  isSource: boolean,
59
- env: Environment,
60
+ env: EnvironmentRef,
60
61
  meta?: Meta,
61
62
  outputHash?: ?string,
62
63
  pipeline?: ?string,
@@ -71,7 +72,7 @@ export type AssetOptions = {|
71
72
 
72
73
  export function createAssetIdFromOptions(options: AssetOptions): string {
73
74
  const data = {
74
- environmentId: options.env.id,
75
+ environmentId: toEnvironmentId(options.env),
75
76
  filePath: options.filePath,
76
77
  code: options.code,
77
78
  pipeline: options.pipeline,
@@ -107,7 +107,7 @@ export class PluginConfig implements IPluginConfig {
107
107
  exclude?: boolean,
108
108
  |}
109
109
  | {|
110
- configKey?: string,
110
+ readTracking?: boolean,
111
111
  |},
112
112
  ): Promise<?ConfigResultWithFilePath<T>> {
113
113
  return this.#inner.getConfigFrom(searchPath, filePaths, options);
@@ -36,6 +36,7 @@ import {
36
36
  BundleBehaviorNames,
37
37
  } from '../types';
38
38
  import {toInternalSourceLocation} from '../utils';
39
+ import {fromEnvironmentId} from '../EnvironmentManager';
39
40
 
40
41
  const inspect = Symbol.for('nodejs.util.inspect.custom');
41
42
 
@@ -101,7 +102,10 @@ class BaseAsset {
101
102
  }
102
103
 
103
104
  get env(): IEnvironment {
104
- return new Environment(this.#asset.value.env, this.#asset.options);
105
+ return new Environment(
106
+ fromEnvironmentId(this.#asset.value.env),
107
+ this.#asset.options,
108
+ );
105
109
  }
106
110
 
107
111
  get fs(): FileSystem {
@@ -210,7 +214,10 @@ export class Asset extends BaseAsset implements IAsset {
210
214
  }
211
215
 
212
216
  get env(): IEnvironment {
213
- this.#env ??= new Environment(this.#asset.value.env, this.#asset.options);
217
+ this.#env ??= new Environment(
218
+ fromEnvironmentId(this.#asset.value.env),
219
+ this.#asset.options,
220
+ );
214
221
  return this.#env;
215
222
  }
216
223
 
@@ -34,6 +34,7 @@ import {
34
34
  import Target from './Target';
35
35
  import {BundleBehaviorNames} from '../types';
36
36
  import {fromProjectPath} from '../projectPath';
37
+ import {fromEnvironmentId} from '../EnvironmentManager';
37
38
 
38
39
  const inspect = Symbol.for('nodejs.util.inspect.custom');
39
40
 
@@ -123,7 +124,7 @@ export class Bundle implements IBundle {
123
124
  }
124
125
 
125
126
  get env(): IEnvironment {
126
- return new Environment(this.#bundle.env, this.#options);
127
+ return new Environment(fromEnvironmentId(this.#bundle.env), this.#options);
127
128
  }
128
129
 
129
130
  get needsStableName(): ?boolean {