@atlaspack/core 2.16.2-dev.55 → 2.16.2-dev.69
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 +33 -0
- package/_empty.js +0 -0
- package/lib/AssetGraph.js +17 -6
- package/lib/Atlaspack.js +2 -5
- package/lib/AtlaspackConfig.schema.js +1 -7
- package/lib/BundleGraph.js +10 -8
- package/lib/Dependency.js +6 -2
- package/lib/Environment.js +4 -3
- package/lib/EnvironmentManager.js +137 -0
- package/lib/InternalConfig.js +3 -2
- package/lib/PackagerRunner.js +15 -9
- package/lib/RequestTracker.js +56 -46
- package/lib/Transformation.js +2 -2
- package/lib/UncommittedAsset.js +3 -2
- package/lib/applyRuntimes.js +2 -1
- package/lib/assetUtils.js +2 -1
- package/lib/atlaspack-v3/AtlaspackV3.js +44 -1
- package/lib/atlaspack-v3/NapiWorkerPool.js +1 -1
- package/lib/atlaspack-v3/worker/compat/environment.js +2 -2
- package/lib/atlaspack-v3/worker/compat/mutable-asset.js +6 -6
- package/lib/atlaspack-v3/worker/compat/plugin-config.js +5 -5
- package/lib/atlaspack-v3/worker/napi-worker.js +3 -0
- package/lib/atlaspack-v3/worker/worker.js +11 -4
- package/lib/dumpGraphToGraphViz.js +1 -1
- package/lib/index.js +9 -1
- package/lib/internal-plugins.js +9 -0
- package/lib/isSuperPackage.js +23 -0
- package/lib/loadAtlaspackPlugin.js +15 -0
- package/lib/public/Asset.js +3 -2
- package/lib/public/Bundle.js +2 -1
- package/lib/public/Config.js +86 -19
- package/lib/public/Dependency.js +2 -1
- package/lib/public/MutableBundleGraph.js +2 -1
- package/lib/public/PluginOptions.js +3 -0
- package/lib/public/Target.js +2 -1
- package/lib/requests/AssetRequest.js +2 -1
- package/lib/requests/AtlaspackConfigRequest.js +44 -29
- package/lib/requests/ConfigRequest.js +27 -4
- package/lib/requests/TargetRequest.js +18 -16
- package/lib/requests/WriteBundleRequest.js +5 -2
- package/lib/requests/WriteBundlesRequest.js +1 -0
- package/lib/resolveOptions.js +5 -4
- package/lib/worker.js +9 -26
- package/package.json +21 -18
- package/src/AssetGraph.js +12 -6
- package/src/Atlaspack.js +8 -7
- package/src/BundleGraph.js +21 -9
- package/src/Dependency.js +13 -5
- package/src/Environment.js +8 -5
- package/src/EnvironmentManager.js +145 -0
- package/src/InternalConfig.js +6 -5
- package/src/PackagerRunner.js +17 -11
- package/src/RequestTracker.js +39 -13
- package/src/UncommittedAsset.js +7 -2
- package/src/applyRuntimes.js +6 -1
- package/src/assetUtils.js +4 -3
- package/src/atlaspack-v3/AtlaspackV3.js +53 -2
- package/src/atlaspack-v3/NapiWorkerPool.js +5 -1
- package/src/atlaspack-v3/worker/compat/plugin-config.js +1 -1
- package/src/atlaspack-v3/worker/worker.js +11 -4
- package/src/index.js +2 -0
- package/src/internal-plugins.js +4 -0
- package/src/isSuperPackage.js +28 -0
- package/src/loadAtlaspackPlugin.js +23 -1
- package/src/public/Asset.js +9 -2
- package/src/public/Bundle.js +2 -1
- package/src/public/Config.js +110 -29
- package/src/public/Dependency.js +2 -1
- package/src/public/MutableBundleGraph.js +2 -1
- package/src/public/PluginOptions.js +4 -0
- package/src/public/Target.js +2 -1
- package/src/requests/AssetRequest.js +2 -1
- package/src/requests/AtlaspackConfigRequest.js +77 -31
- package/src/requests/ConfigRequest.js +33 -9
- package/src/requests/TargetRequest.js +19 -25
- package/src/requests/WriteBundleRequest.js +6 -7
- package/src/requests/WriteBundlesRequest.js +1 -0
- package/src/resolveOptions.js +2 -0
- package/src/types.js +10 -7
- package/src/worker.js +8 -7
- package/test/Environment.test.js +43 -34
- package/test/EnvironmentManager.test.js +192 -0
- package/test/PublicEnvironment.test.js +10 -7
- package/test/RequestTracker.test.js +1 -4
- package/test/public/Config.test.js +108 -0
- package/test/requests/ConfigRequest.test.js +187 -3
- package/test/test-utils.js +3 -2
- package/lib/atlaspack-v3/worker/index.js +0 -6
- /package/src/atlaspack-v3/worker/{index.js → napi-worker.js} +0 -0
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(
|
|
@@ -714,8 +721,8 @@ export class RequestGraph extends ContentGraph<
|
|
|
714
721
|
env: string,
|
|
715
722
|
value: string | void,
|
|
716
723
|
) {
|
|
717
|
-
|
|
718
|
-
|
|
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
|
-
|
|
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);
|
package/src/UncommittedAsset.js
CHANGED
|
@@ -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(
|
|
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:
|
package/src/applyRuntimes.js
CHANGED
|
@@ -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(
|
|
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:
|
|
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
|
|
75
|
+
environmentId: toEnvironmentId(options.env),
|
|
75
76
|
filePath: options.filePath,
|
|
76
77
|
code: options.code,
|
|
77
78
|
pipeline: options.pipeline,
|
|
@@ -12,6 +12,8 @@ import {NapiWorkerPool} from './NapiWorkerPool';
|
|
|
12
12
|
import ThrowableDiagnostic from '@atlaspack/diagnostic';
|
|
13
13
|
import type {Event} from '@parcel/watcher';
|
|
14
14
|
import type {NapiWorkerPool as INapiWorkerPool} from '@atlaspack/types';
|
|
15
|
+
import {isSuperPackage} from '../isSuperPackage';
|
|
16
|
+
import path from 'path';
|
|
15
17
|
|
|
16
18
|
export type AtlaspackV3Options = {|
|
|
17
19
|
fs?: AtlaspackNapiOptions['fs'],
|
|
@@ -23,9 +25,54 @@ export type AtlaspackV3Options = {|
|
|
|
23
25
|
lmdb: Lmdb,
|
|
24
26
|
featureFlags?: {[string]: string | boolean},
|
|
25
27
|
napiWorkerPool?: INapiWorkerPool,
|
|
26
|
-
|
|
28
|
+
...$Diff<
|
|
29
|
+
AtlaspackNapiOptions['options'],
|
|
30
|
+
{|
|
|
31
|
+
jsPaths: AtlaspackNapiOptions['options']['jsPaths'],
|
|
32
|
+
useBuiltinConfigs: AtlaspackNapiOptions['options']['useBuiltinConfigs'],
|
|
33
|
+
|},
|
|
34
|
+
>,
|
|
27
35
|
|};
|
|
28
36
|
|
|
37
|
+
function getJsPaths(): AtlaspackNapiOptions['options']['jsPaths'] {
|
|
38
|
+
const dirname = /*#__ATLASPACK_IGNORE__*/ __dirname;
|
|
39
|
+
|
|
40
|
+
if (isSuperPackage()) {
|
|
41
|
+
// dirname: atlaspack/lib/core/core/atlaspack-v3
|
|
42
|
+
// core: atlaspack/lib/core/core/index.js
|
|
43
|
+
const corePath = path.join(dirname, '..');
|
|
44
|
+
// esmodule helpers: atlaspack/lib/transformers/js/esmodule-helpers.js
|
|
45
|
+
const esmoduleHelpersPath = path.join(
|
|
46
|
+
dirname,
|
|
47
|
+
'../../../transformers/js/esmodule-helpers.js',
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// empty file: atlaspack/lib/core/core/_empty.js
|
|
51
|
+
const emptyFile = path.join(dirname, '_empty.js');
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
corePath,
|
|
55
|
+
esmoduleHelpersSpecifier: path.relative(corePath, esmoduleHelpersPath),
|
|
56
|
+
esmoduleHelpersIncludeNodeModules: 'atlaspack',
|
|
57
|
+
emptyFile,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// dirname: @atlaspack/core/lib/atlaspack-v3
|
|
62
|
+
// core: @atlaspack/core
|
|
63
|
+
const corePath = path.join(dirname, '../..');
|
|
64
|
+
// empty file: atlaspack/lib/core/core/_empty.js
|
|
65
|
+
const emptyFile = path.join(dirname, '_empty.js');
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
corePath,
|
|
69
|
+
esmoduleHelpersSpecifier:
|
|
70
|
+
'@atlaspack/transformer-js/src/esmodule-helpers.js',
|
|
71
|
+
esmoduleHelpersIncludeNodeModules: '@atlaspack/transformer-js',
|
|
72
|
+
emptyFile,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
29
76
|
export class AtlaspackV3 {
|
|
30
77
|
_atlaspack_napi: AtlaspackNapi;
|
|
31
78
|
|
|
@@ -52,7 +99,11 @@ export class AtlaspackV3 {
|
|
|
52
99
|
fs,
|
|
53
100
|
packageManager,
|
|
54
101
|
threads,
|
|
55
|
-
options
|
|
102
|
+
options: {
|
|
103
|
+
...options,
|
|
104
|
+
jsPaths: getJsPaths(),
|
|
105
|
+
useBuiltinConfigs: isSuperPackage(),
|
|
106
|
+
},
|
|
56
107
|
napiWorkerPool,
|
|
57
108
|
},
|
|
58
109
|
lmdb,
|
|
@@ -6,7 +6,11 @@ import process from 'process';
|
|
|
6
6
|
import type {Transferable} from '@atlaspack/rust';
|
|
7
7
|
import {getAvailableThreads} from '@atlaspack/rust';
|
|
8
8
|
|
|
9
|
-
const WORKER_PATH = path.join(
|
|
9
|
+
const WORKER_PATH = path.join(
|
|
10
|
+
/*#__ATLASPACK_IGNORE__*/ __dirname,
|
|
11
|
+
'worker',
|
|
12
|
+
'napi-worker.js',
|
|
13
|
+
);
|
|
10
14
|
const ATLASPACK_NAPI_WORKERS =
|
|
11
15
|
process.env.ATLASPACK_NAPI_WORKERS &&
|
|
12
16
|
parseInt(process.env.ATLASPACK_NAPI_WORKERS, 10);
|
|
@@ -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);
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
bundleBehaviorMap,
|
|
26
26
|
dependencyPriorityMap,
|
|
27
27
|
} from './compat';
|
|
28
|
+
import atlaspackInternalPlugins from '../../internal-plugins';
|
|
28
29
|
|
|
29
30
|
const CONFIG = Symbol.for('parcel-plugin-config');
|
|
30
31
|
|
|
@@ -41,10 +42,16 @@ export class AtlaspackWorker {
|
|
|
41
42
|
|
|
42
43
|
loadPlugin: JsCallable<[LoadPluginOptions], Promise<void>> = jsCallable(
|
|
43
44
|
async ({kind, specifier, resolveFrom}) => {
|
|
44
|
-
let
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
let resolvedModule;
|
|
46
|
+
if (atlaspackInternalPlugins && atlaspackInternalPlugins[specifier]) {
|
|
47
|
+
// If the plugin is available inside the package then use it
|
|
48
|
+
resolvedModule = atlaspackInternalPlugins[specifier]();
|
|
49
|
+
} else {
|
|
50
|
+
let customRequire = module.createRequire(resolveFrom);
|
|
51
|
+
let resolvedPath = customRequire.resolve(specifier);
|
|
52
|
+
// $FlowFixMe
|
|
53
|
+
resolvedModule = await import(resolvedPath);
|
|
54
|
+
}
|
|
48
55
|
|
|
49
56
|
let instance = undefined;
|
|
50
57
|
if (resolvedModule.default && resolvedModule.default[CONFIG]) {
|
package/src/index.js
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
let fs = require('fs');
|
|
3
|
+
let {findAncestorFile} = require('@atlaspack/rust');
|
|
4
|
+
|
|
5
|
+
let dirname = /*#__ATLASPACK_IGNORE__*/ __dirname;
|
|
6
|
+
|
|
7
|
+
function isSuperPackage(): boolean {
|
|
8
|
+
if (!dirname) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let packageJson = JSON.parse(
|
|
13
|
+
// $FlowFixMe
|
|
14
|
+
fs.readFileSync(findAncestorFile(['package.json'], dirname, '/'), 'utf8'),
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
return packageJson.name === 'atlaspack';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let result;
|
|
21
|
+
|
|
22
|
+
module.exports.isSuperPackage = (): boolean => {
|
|
23
|
+
if (result == null) {
|
|
24
|
+
result = isSuperPackage();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return result;
|
|
28
|
+
};
|
|
@@ -8,8 +8,14 @@ import ThrowableDiagnostic, {
|
|
|
8
8
|
generateJSONCodeHighlights,
|
|
9
9
|
md,
|
|
10
10
|
} from '@atlaspack/diagnostic';
|
|
11
|
+
import {version as ATLASPACK_VERSION} from '../package.json';
|
|
12
|
+
import atlaspackInternalPlugins from './internal-plugins';
|
|
11
13
|
import {findAlternativeNodeModules} from '@atlaspack/utils';
|
|
12
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
type ProjectPath,
|
|
16
|
+
toProjectPath,
|
|
17
|
+
toProjectPathUnsafe,
|
|
18
|
+
} from './projectPath';
|
|
13
19
|
|
|
14
20
|
const NODE_MODULES = `${path.sep}node_modules${path.sep}`;
|
|
15
21
|
const CONFIG = Symbol.for('parcel-plugin-config');
|
|
@@ -24,6 +30,22 @@ export default async function loadPlugin<T>(
|
|
|
24
30
|
version: Semver,
|
|
25
31
|
resolveFrom: ProjectPath,
|
|
26
32
|
|}> {
|
|
33
|
+
if (atlaspackInternalPlugins && atlaspackInternalPlugins[pluginName]) {
|
|
34
|
+
let plugin = atlaspackInternalPlugins[pluginName]();
|
|
35
|
+
plugin = plugin.default || plugin;
|
|
36
|
+
plugin = plugin[CONFIG];
|
|
37
|
+
if (!plugin) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`Plugin ${pluginName} is not a valid Atlaspack plugin, should export an instance of a Atlaspack plugin ex. "export default new Reporter({ ... })".`,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
plugin,
|
|
44
|
+
version: ATLASPACK_VERSION,
|
|
45
|
+
resolveFrom: toProjectPathUnsafe(options.projectRoot),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
27
49
|
let resolveFrom = configPath;
|
|
28
50
|
|
|
29
51
|
// Config packages can reference plugins, but cannot contain other plugins within them.
|
package/src/public/Asset.js
CHANGED
|
@@ -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(
|
|
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(
|
|
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
|
|
package/src/public/Bundle.js
CHANGED
|
@@ -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 {
|
package/src/public/Config.js
CHANGED
|
@@ -21,12 +21,89 @@ import {
|
|
|
21
21
|
import Environment from './Environment';
|
|
22
22
|
import {fromProjectPath, toProjectPath} from '../projectPath';
|
|
23
23
|
import {getFeatureFlag} from '@atlaspack/feature-flags';
|
|
24
|
+
import {fromEnvironmentId} from '../EnvironmentManager';
|
|
24
25
|
|
|
25
26
|
const internalConfigToConfig: DefaultWeakMap<
|
|
26
27
|
AtlaspackOptions,
|
|
27
28
|
WeakMap<Config, PublicConfig>,
|
|
28
29
|
> = new DefaultWeakMap(() => new WeakMap());
|
|
29
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Implements read tracking over an object.
|
|
33
|
+
*
|
|
34
|
+
* Calling this function with a non-trivial object like a class instance will fail to work.
|
|
35
|
+
*
|
|
36
|
+
* We track reads to fields that resolve to:
|
|
37
|
+
*
|
|
38
|
+
* - primitive values
|
|
39
|
+
* - arrays
|
|
40
|
+
*
|
|
41
|
+
* That is, reading a nested field `a.b.c` will make a single call to `onRead` with the path
|
|
42
|
+
* `['a', 'b', 'c']`.
|
|
43
|
+
*
|
|
44
|
+
* In case the value is null or an array, we will track the read as well.
|
|
45
|
+
*
|
|
46
|
+
* Iterating over `Object.keys(obj.field)` will register a read for the `['field']` path.
|
|
47
|
+
* Other reads work normally.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
*
|
|
51
|
+
* const usedPaths = new Set();
|
|
52
|
+
* const onRead = (path) => {
|
|
53
|
+
* usedPaths.add(path);
|
|
54
|
+
* };
|
|
55
|
+
*
|
|
56
|
+
* const config = makeConfigProxy(onRead, {a: {b: {c: 'd'}}})
|
|
57
|
+
* console.log(config.a.b.c);
|
|
58
|
+
* console.log(Array.from(usedPaths));
|
|
59
|
+
* // We get a single read for the path
|
|
60
|
+
* // ['a', 'b', 'c']
|
|
61
|
+
*
|
|
62
|
+
*/
|
|
63
|
+
export function makeConfigProxy<T>(
|
|
64
|
+
onRead: (path: string[]) => void,
|
|
65
|
+
config: T,
|
|
66
|
+
): T {
|
|
67
|
+
const reportedPaths = new Set();
|
|
68
|
+
const reportPath = (path) => {
|
|
69
|
+
if (reportedPaths.has(path)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
reportedPaths.add(path);
|
|
73
|
+
onRead(path);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const makeProxy = (target, path) => {
|
|
77
|
+
return new Proxy(target, {
|
|
78
|
+
ownKeys(target) {
|
|
79
|
+
reportPath(path);
|
|
80
|
+
|
|
81
|
+
// $FlowFixMe
|
|
82
|
+
return Object.getOwnPropertyNames(target);
|
|
83
|
+
},
|
|
84
|
+
get(target, prop) {
|
|
85
|
+
// $FlowFixMe
|
|
86
|
+
const value = target[prop];
|
|
87
|
+
|
|
88
|
+
if (
|
|
89
|
+
typeof value === 'object' &&
|
|
90
|
+
value != null &&
|
|
91
|
+
!Array.isArray(value)
|
|
92
|
+
) {
|
|
93
|
+
return makeProxy(value, [...path, prop]);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
reportPath([...path, prop]);
|
|
97
|
+
|
|
98
|
+
return value;
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// $FlowFixMe
|
|
104
|
+
return makeProxy(config, []);
|
|
105
|
+
}
|
|
106
|
+
|
|
30
107
|
export default class PublicConfig implements IConfig {
|
|
31
108
|
#config /*: Config */;
|
|
32
109
|
#pkg /*: ?PackageJSON */;
|
|
@@ -46,7 +123,7 @@ export default class PublicConfig implements IConfig {
|
|
|
46
123
|
}
|
|
47
124
|
|
|
48
125
|
get env(): Environment {
|
|
49
|
-
return new Environment(this.#config.env, this.#options);
|
|
126
|
+
return new Environment(fromEnvironmentId(this.#config.env), this.#options);
|
|
50
127
|
}
|
|
51
128
|
|
|
52
129
|
get searchPath(): FilePath {
|
|
@@ -76,7 +153,7 @@ export default class PublicConfig implements IConfig {
|
|
|
76
153
|
);
|
|
77
154
|
}
|
|
78
155
|
|
|
79
|
-
invalidateOnConfigKeyChange(filePath: FilePath, configKey: string) {
|
|
156
|
+
invalidateOnConfigKeyChange(filePath: FilePath, configKey: string[]) {
|
|
80
157
|
this.#config.invalidateOnConfigKeyChange.push({
|
|
81
158
|
filePath: toProjectPath(this.#options.projectRoot, filePath),
|
|
82
159
|
configKey,
|
|
@@ -144,9 +221,10 @@ export default class PublicConfig implements IConfig {
|
|
|
144
221
|
|}
|
|
145
222
|
| ?{|
|
|
146
223
|
/**
|
|
147
|
-
* If specified,
|
|
224
|
+
* If specified, this function will return a proxy object that will track reads to
|
|
225
|
+
* config fields and only register invalidations for when those keys change.
|
|
148
226
|
*/
|
|
149
|
-
|
|
227
|
+
readTracking?: boolean,
|
|
150
228
|
|},
|
|
151
229
|
): Promise<?ConfigResultWithFilePath<T>> {
|
|
152
230
|
let packageKey = options?.packageKey;
|
|
@@ -157,7 +235,7 @@ export default class PublicConfig implements IConfig {
|
|
|
157
235
|
|
|
158
236
|
if (pkg && pkg.contents[packageKey]) {
|
|
159
237
|
// Invalidate only when the package key changes
|
|
160
|
-
this.invalidateOnConfigKeyChange(pkg.filePath, packageKey);
|
|
238
|
+
this.invalidateOnConfigKeyChange(pkg.filePath, [packageKey]);
|
|
161
239
|
|
|
162
240
|
return {
|
|
163
241
|
contents: pkg.contents[packageKey],
|
|
@@ -166,27 +244,24 @@ export default class PublicConfig implements IConfig {
|
|
|
166
244
|
}
|
|
167
245
|
}
|
|
168
246
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
247
|
+
const readTracking = options?.readTracking;
|
|
248
|
+
if (readTracking === true) {
|
|
249
|
+
for (let fileName of fileNames) {
|
|
250
|
+
const config = await this.getConfigFrom(searchPath, [fileName], {
|
|
251
|
+
exclude: true,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
if (config != null) {
|
|
255
|
+
return Promise.resolve({
|
|
256
|
+
contents: makeConfigProxy((keyPath) => {
|
|
257
|
+
this.invalidateOnConfigKeyChange(config.filePath, keyPath);
|
|
258
|
+
}, config.contents),
|
|
259
|
+
filePath: config.filePath,
|
|
175
260
|
});
|
|
176
|
-
|
|
177
|
-
if (config && config.contents[configKey]) {
|
|
178
|
-
// Invalidate only when the package key changes
|
|
179
|
-
this.invalidateOnConfigKeyChange(config.filePath, configKey);
|
|
180
|
-
|
|
181
|
-
return {
|
|
182
|
-
contents: config.contents[configKey],
|
|
183
|
-
filePath: config.filePath,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
261
|
}
|
|
187
|
-
|
|
188
|
-
// fall through so that file above invalidations are registered
|
|
189
262
|
}
|
|
263
|
+
|
|
264
|
+
// fall through so that file above invalidations are registered
|
|
190
265
|
}
|
|
191
266
|
|
|
192
267
|
if (fileNames.length === 0) {
|
|
@@ -268,11 +343,15 @@ export default class PublicConfig implements IConfig {
|
|
|
268
343
|
|
|
269
344
|
getConfig<T>(
|
|
270
345
|
filePaths: Array<FilePath>,
|
|
271
|
-
options:
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
346
|
+
options:
|
|
347
|
+
| ?{|
|
|
348
|
+
packageKey?: string,
|
|
349
|
+
parse?: boolean,
|
|
350
|
+
exclude?: boolean,
|
|
351
|
+
|}
|
|
352
|
+
| {|
|
|
353
|
+
readTracking?: boolean,
|
|
354
|
+
|},
|
|
276
355
|
): Promise<?ConfigResultWithFilePath<T>> {
|
|
277
356
|
return this.getConfigFrom(this.searchPath, filePaths, options);
|
|
278
357
|
}
|
|
@@ -282,7 +361,9 @@ export default class PublicConfig implements IConfig {
|
|
|
282
361
|
return this.#pkg;
|
|
283
362
|
}
|
|
284
363
|
|
|
285
|
-
let pkgConfig = await this.getConfig<PackageJSON>(['package.json']
|
|
364
|
+
let pkgConfig = await this.getConfig<PackageJSON>(['package.json'], {
|
|
365
|
+
readTracking: getFeatureFlag('granularTsConfigInvalidation'),
|
|
366
|
+
});
|
|
286
367
|
if (!pkgConfig) {
|
|
287
368
|
return null;
|
|
288
369
|
}
|