@atlaspack/core 2.16.2-canary.57 → 2.16.2-canary.59
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/lib/EnvironmentManager.js +57 -0
- package/lib/RequestTracker.js +18 -3
- package/lib/public/Config.js +84 -18
- package/lib/requests/ConfigRequest.js +27 -4
- package/package.json +17 -17
- package/src/EnvironmentManager.js +70 -1
- package/src/InternalConfig.js +1 -1
- package/src/RequestTracker.js +37 -11
- package/src/atlaspack-v3/worker/compat/plugin-config.js +1 -1
- package/src/public/Config.js +108 -28
- package/src/requests/ConfigRequest.js +33 -9
- package/src/types.js +1 -1
- package/test/EnvironmentManager.test.js +192 -0
- package/test/public/Config.test.js +108 -0
- package/test/requests/ConfigRequest.test.js +187 -3
|
@@ -4,8 +4,10 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.fromEnvironmentId = fromEnvironmentId;
|
|
7
|
+
exports.loadEnvironmentsFromCache = loadEnvironmentsFromCache;
|
|
7
8
|
exports.toEnvironmentId = toEnvironmentId;
|
|
8
9
|
exports.toEnvironmentRef = toEnvironmentRef;
|
|
10
|
+
exports.writeEnvironmentsToCache = writeEnvironmentsToCache;
|
|
9
11
|
function _rust() {
|
|
10
12
|
const data = require("@atlaspack/rust");
|
|
11
13
|
_rust = function () {
|
|
@@ -20,6 +22,14 @@ function _featureFlags() {
|
|
|
20
22
|
};
|
|
21
23
|
return data;
|
|
22
24
|
}
|
|
25
|
+
function _logger() {
|
|
26
|
+
const data = require("@atlaspack/logger");
|
|
27
|
+
_logger = function () {
|
|
28
|
+
return data;
|
|
29
|
+
};
|
|
30
|
+
return data;
|
|
31
|
+
}
|
|
32
|
+
var _constants = require("./constants");
|
|
23
33
|
/*!
|
|
24
34
|
* At the moment we're doing this change for `CoreEnvironment`,
|
|
25
35
|
* but the same change must be made for `TypesEnvironment` in @atlaspack/types.
|
|
@@ -77,4 +87,51 @@ function fromEnvironmentId(id) {
|
|
|
77
87
|
const env = Object.freeze((0, _rust().getEnvironment)(id));
|
|
78
88
|
localEnvironmentCache.set(id, env);
|
|
79
89
|
return env;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Writes all environments and their IDs to the cache
|
|
94
|
+
* @param {Cache} cache
|
|
95
|
+
* @returns {Promise<void>}
|
|
96
|
+
*/
|
|
97
|
+
async function writeEnvironmentsToCache(cache) {
|
|
98
|
+
const environments = (0, _rust().getAllEnvironments)();
|
|
99
|
+
const environmentIds = new Set();
|
|
100
|
+
|
|
101
|
+
// Store each environment individually
|
|
102
|
+
for (const env of environments) {
|
|
103
|
+
environmentIds.add(env.id);
|
|
104
|
+
const envKey = `Environment/${_constants.ATLASPACK_VERSION}/${env.id}`;
|
|
105
|
+
await (0, _logger().instrument)(`RequestTracker::writeToCache::cache.put(${envKey})`, async () => {
|
|
106
|
+
await cache.set(envKey, env);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Store the list of environment IDs
|
|
111
|
+
await (0, _logger().instrument)(`RequestTracker::writeToCache::cache.put(${`EnvironmentManager/${_constants.ATLASPACK_VERSION}`})`, async () => {
|
|
112
|
+
await cache.set(`EnvironmentManager/${_constants.ATLASPACK_VERSION}`, Array.from(environmentIds));
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Loads all environments and their IDs from the cache
|
|
118
|
+
* @param {Cache} cache
|
|
119
|
+
* @returns {Promise<void>}
|
|
120
|
+
*/
|
|
121
|
+
async function loadEnvironmentsFromCache(cache) {
|
|
122
|
+
const cachedEnvIds = await cache.get(`EnvironmentManager/${_constants.ATLASPACK_VERSION}`);
|
|
123
|
+
if (cachedEnvIds == null) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const environments = [];
|
|
127
|
+
for (const envId of cachedEnvIds) {
|
|
128
|
+
const envKey = `Environment/${_constants.ATLASPACK_VERSION}/${envId}`;
|
|
129
|
+
const cachedEnv = await cache.get(envKey);
|
|
130
|
+
if (cachedEnv != null) {
|
|
131
|
+
environments.push(cachedEnv);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (environments.length > 0) {
|
|
135
|
+
(0, _rust().setAllEnvironments)(environments);
|
|
136
|
+
}
|
|
80
137
|
}
|
package/lib/RequestTracker.js
CHANGED
|
@@ -95,6 +95,7 @@ function _perf_hooks() {
|
|
|
95
95
|
};
|
|
96
96
|
return data;
|
|
97
97
|
}
|
|
98
|
+
var _EnvironmentManager = require("./EnvironmentManager");
|
|
98
99
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
99
100
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
100
101
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
@@ -162,7 +163,7 @@ const nodeFromOption = (option, value) => ({
|
|
|
162
163
|
hash: (0, _utils2.hashFromOption)(value)
|
|
163
164
|
});
|
|
164
165
|
const nodeFromConfigKey = (fileName, configKey, contentHash) => ({
|
|
165
|
-
id: `config_key:${(0, _projectPath.fromProjectPathRelative)(fileName)}:${configKey}`,
|
|
166
|
+
id: `config_key:${(0, _projectPath.fromProjectPathRelative)(fileName)}:${JSON.stringify(configKey)}`,
|
|
166
167
|
type: CONFIG_KEY,
|
|
167
168
|
configKey,
|
|
168
169
|
contentHash
|
|
@@ -695,10 +696,18 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
695
696
|
this.removeNode(nodeId, removeOrphans);
|
|
696
697
|
}
|
|
697
698
|
let configKeyNodes = this.configKeyNodes.get(_filePath);
|
|
698
|
-
|
|
699
|
+
|
|
700
|
+
// With granular invalidations we will always run this block,
|
|
701
|
+
// so even if we get a create event (for whatever reason), we will still
|
|
702
|
+
// try to limit invalidations from config key changes through hashing.
|
|
703
|
+
//
|
|
704
|
+
// Currently create events can invalidate a large number of nodes due to
|
|
705
|
+
// "create above" invalidations.
|
|
706
|
+
const isConfigKeyChange = (0, _featureFlags().getFeatureFlag)('granularTsConfigInvalidation') || type === 'delete' || type === 'update';
|
|
707
|
+
if (configKeyNodes && isConfigKeyChange) {
|
|
699
708
|
for (let nodeId of configKeyNodes) {
|
|
700
709
|
let isInvalid = type === 'delete';
|
|
701
|
-
if (type
|
|
710
|
+
if (type !== 'delete') {
|
|
702
711
|
let node = this.getNode(nodeId);
|
|
703
712
|
(0, _assert().default)(node && node.type === CONFIG_KEY);
|
|
704
713
|
let contentHash = await (0, _ConfigRequest.getConfigKeyContentHash)(_filePath, node.configKey, options);
|
|
@@ -1015,6 +1024,9 @@ class RequestTracker {
|
|
|
1015
1024
|
total,
|
|
1016
1025
|
size: this.graph.nodes.length
|
|
1017
1026
|
});
|
|
1027
|
+
if ((0, _featureFlags().getFeatureFlag)('environmentDeduplication')) {
|
|
1028
|
+
await (0, _EnvironmentManager.writeEnvironmentsToCache)(options.cache);
|
|
1029
|
+
}
|
|
1018
1030
|
let serialisedGraph = this.graph.serialize();
|
|
1019
1031
|
|
|
1020
1032
|
// Delete an existing request graph cache, to prevent invalid states
|
|
@@ -1206,6 +1218,9 @@ async function loadRequestGraph(options) {
|
|
|
1206
1218
|
...commonMeta
|
|
1207
1219
|
}
|
|
1208
1220
|
});
|
|
1221
|
+
if ((0, _featureFlags().getFeatureFlag)('environmentDeduplication')) {
|
|
1222
|
+
await (0, _EnvironmentManager.loadEnvironmentsFromCache)(options.cache);
|
|
1223
|
+
}
|
|
1209
1224
|
const hasRequestGraphInCache = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? await options.cache.has(requestGraphKey) : await options.cache.hasLargeBlob(requestGraphKey);
|
|
1210
1225
|
if (hasRequestGraphInCache) {
|
|
1211
1226
|
try {
|
package/lib/public/Config.js
CHANGED
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
+
exports.makeConfigProxy = makeConfigProxy;
|
|
7
8
|
function _assert() {
|
|
8
9
|
const data = _interopRequireDefault(require("assert"));
|
|
9
10
|
_assert = function () {
|
|
@@ -37,6 +38,71 @@ function _featureFlags() {
|
|
|
37
38
|
var _EnvironmentManager = require("../EnvironmentManager");
|
|
38
39
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
39
40
|
const internalConfigToConfig = new (_utils().DefaultWeakMap)(() => new WeakMap());
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Implements read tracking over an object.
|
|
44
|
+
*
|
|
45
|
+
* Calling this function with a non-trivial object like a class instance will fail to work.
|
|
46
|
+
*
|
|
47
|
+
* We track reads to fields that resolve to:
|
|
48
|
+
*
|
|
49
|
+
* - primitive values
|
|
50
|
+
* - arrays
|
|
51
|
+
*
|
|
52
|
+
* That is, reading a nested field `a.b.c` will make a single call to `onRead` with the path
|
|
53
|
+
* `['a', 'b', 'c']`.
|
|
54
|
+
*
|
|
55
|
+
* In case the value is null or an array, we will track the read as well.
|
|
56
|
+
*
|
|
57
|
+
* Iterating over `Object.keys(obj.field)` will register a read for the `['field']` path.
|
|
58
|
+
* Other reads work normally.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
*
|
|
62
|
+
* const usedPaths = new Set();
|
|
63
|
+
* const onRead = (path) => {
|
|
64
|
+
* usedPaths.add(path);
|
|
65
|
+
* };
|
|
66
|
+
*
|
|
67
|
+
* const config = makeConfigProxy(onRead, {a: {b: {c: 'd'}}})
|
|
68
|
+
* console.log(config.a.b.c);
|
|
69
|
+
* console.log(Array.from(usedPaths));
|
|
70
|
+
* // We get a single read for the path
|
|
71
|
+
* // ['a', 'b', 'c']
|
|
72
|
+
*
|
|
73
|
+
*/
|
|
74
|
+
function makeConfigProxy(onRead, config) {
|
|
75
|
+
const reportedPaths = new Set();
|
|
76
|
+
const reportPath = path => {
|
|
77
|
+
if (reportedPaths.has(path)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
reportedPaths.add(path);
|
|
81
|
+
onRead(path);
|
|
82
|
+
};
|
|
83
|
+
const makeProxy = (target, path) => {
|
|
84
|
+
return new Proxy(target, {
|
|
85
|
+
ownKeys(target) {
|
|
86
|
+
reportPath(path);
|
|
87
|
+
|
|
88
|
+
// $FlowFixMe
|
|
89
|
+
return Object.getOwnPropertyNames(target);
|
|
90
|
+
},
|
|
91
|
+
get(target, prop) {
|
|
92
|
+
// $FlowFixMe
|
|
93
|
+
const value = target[prop];
|
|
94
|
+
if (typeof value === 'object' && value != null && !Array.isArray(value)) {
|
|
95
|
+
return makeProxy(value, [...path, prop]);
|
|
96
|
+
}
|
|
97
|
+
reportPath([...path, prop]);
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// $FlowFixMe
|
|
104
|
+
return makeProxy(config, []);
|
|
105
|
+
}
|
|
40
106
|
class PublicConfig {
|
|
41
107
|
#config /*: Config */;
|
|
42
108
|
#pkg /*: ?PackageJSON */;
|
|
@@ -127,32 +193,30 @@ class PublicConfig {
|
|
|
127
193
|
});
|
|
128
194
|
if (pkg && pkg.contents[packageKey]) {
|
|
129
195
|
// Invalidate only when the package key changes
|
|
130
|
-
this.invalidateOnConfigKeyChange(pkg.filePath, packageKey);
|
|
196
|
+
this.invalidateOnConfigKeyChange(pkg.filePath, [packageKey]);
|
|
131
197
|
return {
|
|
132
198
|
contents: pkg.contents[packageKey],
|
|
133
199
|
filePath: pkg.filePath
|
|
134
200
|
};
|
|
135
201
|
}
|
|
136
202
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
203
|
+
const readTracking = options === null || options === void 0 ? void 0 : options.readTracking;
|
|
204
|
+
if (readTracking === true) {
|
|
205
|
+
for (let fileName of fileNames) {
|
|
206
|
+
const config = await this.getConfigFrom(searchPath, [fileName], {
|
|
207
|
+
exclude: true
|
|
208
|
+
});
|
|
209
|
+
if (config != null) {
|
|
210
|
+
return Promise.resolve({
|
|
211
|
+
contents: makeConfigProxy(keyPath => {
|
|
212
|
+
this.invalidateOnConfigKeyChange(config.filePath, keyPath);
|
|
213
|
+
}, config.contents),
|
|
214
|
+
filePath: config.filePath
|
|
143
215
|
});
|
|
144
|
-
if (config && config.contents[configKey]) {
|
|
145
|
-
// Invalidate only when the package key changes
|
|
146
|
-
this.invalidateOnConfigKeyChange(config.filePath, configKey);
|
|
147
|
-
return {
|
|
148
|
-
contents: config.contents[configKey],
|
|
149
|
-
filePath: config.filePath
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
216
|
}
|
|
153
|
-
|
|
154
|
-
// fall through so that file above invalidations are registered
|
|
155
217
|
}
|
|
218
|
+
|
|
219
|
+
// fall through so that file above invalidations are registered
|
|
156
220
|
}
|
|
157
221
|
|
|
158
222
|
if (fileNames.length === 0) {
|
|
@@ -219,7 +283,9 @@ class PublicConfig {
|
|
|
219
283
|
if (this.#pkg) {
|
|
220
284
|
return this.#pkg;
|
|
221
285
|
}
|
|
222
|
-
let pkgConfig = await this.getConfig(['package.json']
|
|
286
|
+
let pkgConfig = await this.getConfig(['package.json'], {
|
|
287
|
+
readTracking: (0, _featureFlags().getFeatureFlag)('granularTsConfigInvalidation')
|
|
288
|
+
});
|
|
223
289
|
if (!pkgConfig) {
|
|
224
290
|
return null;
|
|
225
291
|
}
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.getConfigHash = getConfigHash;
|
|
7
7
|
exports.getConfigKeyContentHash = getConfigKeyContentHash;
|
|
8
8
|
exports.getConfigRequests = getConfigRequests;
|
|
9
|
+
exports.getValueAtPath = getValueAtPath;
|
|
9
10
|
exports.loadPluginConfig = loadPluginConfig;
|
|
10
11
|
exports.runConfigRequest = runConfigRequest;
|
|
11
12
|
function _utils() {
|
|
@@ -86,19 +87,41 @@ async function loadPluginConfig(loadedPlugin, config, options) {
|
|
|
86
87
|
});
|
|
87
88
|
}
|
|
88
89
|
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Return value at a given key path within an object.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* const obj = { a: { b: { c: 'd' } } };
|
|
96
|
+
* getValueAtPath(obj, ['a', 'b', 'c']); // 'd'
|
|
97
|
+
* getValueAtPath(obj, ['a', 'b', 'd']); // undefined
|
|
98
|
+
* getValueAtPath(obj, ['a', 'b']); // { c: 'd' }
|
|
99
|
+
* getValueAtPath(obj, ['a', 'b', 'c', 'd']); // undefined
|
|
100
|
+
*/
|
|
101
|
+
function getValueAtPath(obj, key) {
|
|
102
|
+
let current = obj;
|
|
103
|
+
for (let part of key) {
|
|
104
|
+
if (current == null) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
current = current[part];
|
|
108
|
+
}
|
|
109
|
+
return current;
|
|
110
|
+
}
|
|
89
111
|
const configKeyCache = (0, _buildCache().createBuildCache)();
|
|
90
112
|
async function getConfigKeyContentHash(filePath, configKey, options) {
|
|
91
|
-
let cacheKey = `${(0, _projectPath.fromProjectPathRelative)(filePath)}:${configKey}`;
|
|
113
|
+
let cacheKey = `${(0, _projectPath.fromProjectPathRelative)(filePath)}:${JSON.stringify(configKey)}`;
|
|
92
114
|
let cachedValue = configKeyCache.get(cacheKey);
|
|
93
115
|
if (cachedValue) {
|
|
94
116
|
return cachedValue;
|
|
95
117
|
}
|
|
96
|
-
|
|
97
|
-
|
|
118
|
+
const conf = await (0, _utils().readConfig)(options.inputFS, (0, _projectPath.fromProjectPath)(options.projectRoot, filePath));
|
|
119
|
+
const value = getValueAtPath(conf === null || conf === void 0 ? void 0 : conf.config, configKey);
|
|
120
|
+
if (conf == null || value == null) {
|
|
98
121
|
// This can occur when a config key has been removed entirely during `respondToFSEvents`
|
|
99
122
|
return '';
|
|
100
123
|
}
|
|
101
|
-
|
|
124
|
+
const contentHash = typeof value === 'object' ? (0, _utils().hashObject)(value) : (0, _rust().hashString)(JSON.stringify(value));
|
|
102
125
|
configKeyCache.set(cacheKey, contentHash);
|
|
103
126
|
return contentHash;
|
|
104
127
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaspack/core",
|
|
3
|
-
"version": "2.16.2-canary.
|
|
3
|
+
"version": "2.16.2-canary.59+0b2f6f557",
|
|
4
4
|
"license": "(MIT OR Apache-2.0)",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -21,21 +21,21 @@
|
|
|
21
21
|
"check-ts": "tsc --noEmit index.d.ts"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@atlaspack/build-cache": "2.13.3-canary.
|
|
25
|
-
"@atlaspack/cache": "3.1.1-canary.
|
|
26
|
-
"@atlaspack/diagnostic": "2.14.1-canary.
|
|
27
|
-
"@atlaspack/events": "2.14.1-canary.
|
|
28
|
-
"@atlaspack/feature-flags": "2.14.1-canary.
|
|
29
|
-
"@atlaspack/fs": "2.14.5-canary.
|
|
30
|
-
"@atlaspack/graph": "3.4.1-canary.
|
|
31
|
-
"@atlaspack/logger": "2.14.5-canary.
|
|
32
|
-
"@atlaspack/package-manager": "2.14.5-canary.
|
|
33
|
-
"@atlaspack/plugin": "2.14.5-canary.
|
|
34
|
-
"@atlaspack/profiler": "2.14.1-canary.
|
|
35
|
-
"@atlaspack/rust": "3.2.1-canary.
|
|
36
|
-
"@atlaspack/types": "2.14.5-canary.
|
|
37
|
-
"@atlaspack/utils": "2.14.5-canary.
|
|
38
|
-
"@atlaspack/workers": "2.14.5-canary.
|
|
24
|
+
"@atlaspack/build-cache": "2.13.3-canary.127+0b2f6f557",
|
|
25
|
+
"@atlaspack/cache": "3.1.1-canary.59+0b2f6f557",
|
|
26
|
+
"@atlaspack/diagnostic": "2.14.1-canary.127+0b2f6f557",
|
|
27
|
+
"@atlaspack/events": "2.14.1-canary.127+0b2f6f557",
|
|
28
|
+
"@atlaspack/feature-flags": "2.14.1-canary.127+0b2f6f557",
|
|
29
|
+
"@atlaspack/fs": "2.14.5-canary.59+0b2f6f557",
|
|
30
|
+
"@atlaspack/graph": "3.4.1-canary.127+0b2f6f557",
|
|
31
|
+
"@atlaspack/logger": "2.14.5-canary.59+0b2f6f557",
|
|
32
|
+
"@atlaspack/package-manager": "2.14.5-canary.59+0b2f6f557",
|
|
33
|
+
"@atlaspack/plugin": "2.14.5-canary.59+0b2f6f557",
|
|
34
|
+
"@atlaspack/profiler": "2.14.1-canary.127+0b2f6f557",
|
|
35
|
+
"@atlaspack/rust": "3.2.1-canary.59+0b2f6f557",
|
|
36
|
+
"@atlaspack/types": "2.14.5-canary.59+0b2f6f557",
|
|
37
|
+
"@atlaspack/utils": "2.14.5-canary.59+0b2f6f557",
|
|
38
|
+
"@atlaspack/workers": "2.14.5-canary.59+0b2f6f557",
|
|
39
39
|
"@mischnic/json-sourcemap": "^0.1.0",
|
|
40
40
|
"@parcel/source-map": "^2.1.1",
|
|
41
41
|
"base-x": "^3.0.8",
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"./src/serializerCore.js": "./src/serializerCore.browser.js"
|
|
72
72
|
},
|
|
73
73
|
"type": "commonjs",
|
|
74
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "0b2f6f55794d3ff6e2f5a41f963e7e5dd8ad9f8d"
|
|
75
75
|
}
|
|
@@ -4,8 +4,16 @@
|
|
|
4
4
|
* but the same change must be made for `TypesEnvironment` in @atlaspack/types.
|
|
5
5
|
*/
|
|
6
6
|
import type {Environment as CoreEnvironment} from './types';
|
|
7
|
-
import {
|
|
7
|
+
import {type Cache} from '@atlaspack/cache';
|
|
8
|
+
import {
|
|
9
|
+
addEnvironment,
|
|
10
|
+
getEnvironment,
|
|
11
|
+
getAllEnvironments,
|
|
12
|
+
setAllEnvironments,
|
|
13
|
+
} from '@atlaspack/rust';
|
|
8
14
|
import {getFeatureFlag} from '@atlaspack/feature-flags';
|
|
15
|
+
import {instrument} from '@atlaspack/logger';
|
|
16
|
+
import {ATLASPACK_VERSION} from './constants';
|
|
9
17
|
|
|
10
18
|
const localEnvironmentCache = new Map<string, CoreEnvironment>();
|
|
11
19
|
|
|
@@ -74,3 +82,64 @@ export function fromEnvironmentId(id: EnvironmentRef): CoreEnvironment {
|
|
|
74
82
|
localEnvironmentCache.set(id, env);
|
|
75
83
|
return env;
|
|
76
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
|
+
}
|
package/src/InternalConfig.js
CHANGED
|
@@ -24,7 +24,7 @@ type ConfigOpts = {|
|
|
|
24
24
|
invalidateOnFileChange?: Set<ProjectPath>,
|
|
25
25
|
invalidateOnConfigKeyChange?: Array<{|
|
|
26
26
|
filePath: ProjectPath,
|
|
27
|
-
configKey: string,
|
|
27
|
+
configKey: string[],
|
|
28
28
|
|}>,
|
|
29
29
|
invalidateOnFileCreate?: Array<InternalFileCreateInvalidation>,
|
|
30
30
|
invalidateOnEnvChange?: Set<string>,
|
package/src/RequestTracker.js
CHANGED
|
@@ -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
|
-
|
|
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)}:${
|
|
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(
|
|
@@ -1109,11 +1116,22 @@ export class RequestGraph extends ContentGraph<
|
|
|
1109
1116
|
}
|
|
1110
1117
|
|
|
1111
1118
|
let configKeyNodes = this.configKeyNodes.get(_filePath);
|
|
1112
|
-
|
|
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
|
|
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);
|
|
@@ -107,7 +107,7 @@ export class PluginConfig implements IPluginConfig {
|
|
|
107
107
|
exclude?: boolean,
|
|
108
108
|
|}
|
|
109
109
|
| {|
|
|
110
|
-
|
|
110
|
+
readTracking?: boolean,
|
|
111
111
|
|},
|
|
112
112
|
): Promise<?ConfigResultWithFilePath<T>> {
|
|
113
113
|
return this.#inner.getConfigFrom(searchPath, filePaths, options);
|