@atlaspack/core 2.12.1-canary.3432 → 2.12.1-canary.3434
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/Atlaspack.js +9 -2
- package/lib/BundleGraph.js +59 -5
- package/lib/SymbolPropagation.js +1 -1
- package/lib/atlaspack-v3/worker/worker.js +2 -1
- package/lib/public/BundleGraph.js +68 -0
- package/lib/resolveOptions.js +2 -0
- package/lib/types.js +2 -1
- package/package.json +16 -16
- package/src/Atlaspack.js +11 -6
- package/src/BundleGraph.js +77 -1
- package/src/SymbolPropagation.js +5 -2
- package/src/atlaspack-v3/worker/worker.js +1 -0
- package/src/public/BundleGraph.js +106 -0
- package/src/resolveOptions.js +2 -0
- package/src/types.js +10 -0
- package/test/PublicBundle.test.js +1 -0
package/lib/Atlaspack.js
CHANGED
|
@@ -151,6 +151,11 @@ class Atlaspack {
|
|
|
151
151
|
if (this.#initialized) {
|
|
152
152
|
return;
|
|
153
153
|
}
|
|
154
|
+
const featureFlags = {
|
|
155
|
+
..._featureFlags().DEFAULT_FEATURE_FLAGS,
|
|
156
|
+
...this.#initialOptions.featureFlags
|
|
157
|
+
};
|
|
158
|
+
(0, _featureFlags().setFeatureFlags)(featureFlags);
|
|
154
159
|
await _sourceMap().init;
|
|
155
160
|
await (_rust().init === null || _rust().init === void 0 ? void 0 : (0, _rust().init)());
|
|
156
161
|
try {
|
|
@@ -162,7 +167,10 @@ class Atlaspack {
|
|
|
162
167
|
// Fallthrough
|
|
163
168
|
_logger().default.warn(e);
|
|
164
169
|
}
|
|
165
|
-
let resolvedOptions = await (0, _resolveOptions.default)(
|
|
170
|
+
let resolvedOptions = await (0, _resolveOptions.default)({
|
|
171
|
+
...this.#initialOptions,
|
|
172
|
+
featureFlags
|
|
173
|
+
});
|
|
166
174
|
this.#resolvedOptions = resolvedOptions;
|
|
167
175
|
let rustAtlaspack;
|
|
168
176
|
if (resolvedOptions.featureFlags.atlaspackV3) {
|
|
@@ -192,7 +200,6 @@ class Atlaspack {
|
|
|
192
200
|
}
|
|
193
201
|
});
|
|
194
202
|
}
|
|
195
|
-
(0, _featureFlags().setFeatureFlags)(resolvedOptions.featureFlags);
|
|
196
203
|
let {
|
|
197
204
|
config
|
|
198
205
|
} = await (0, _AtlaspackConfigRequest.loadAtlaspackConfig)(resolvedOptions);
|
package/lib/BundleGraph.js
CHANGED
|
@@ -44,6 +44,13 @@ var _utils2 = require("./utils");
|
|
|
44
44
|
var _Environment = require("./public/Environment");
|
|
45
45
|
var _projectPath = require("./projectPath");
|
|
46
46
|
var _constants = require("./constants");
|
|
47
|
+
function _featureFlags() {
|
|
48
|
+
const data = require("@atlaspack/feature-flags");
|
|
49
|
+
_featureFlags = function () {
|
|
50
|
+
return data;
|
|
51
|
+
};
|
|
52
|
+
return data;
|
|
53
|
+
}
|
|
47
54
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
48
55
|
const bundleGraphEdgeTypes = exports.bundleGraphEdgeTypes = {
|
|
49
56
|
// A lack of an edge type indicates to follow the edge while traversing
|
|
@@ -107,16 +114,19 @@ class BundleGraph {
|
|
|
107
114
|
/** The internal core Graph structure */
|
|
108
115
|
|
|
109
116
|
_bundlePublicIds /*: Set<string> */ = new Set();
|
|
117
|
+
_conditions /*: Map<string, Condition> */ = new Map();
|
|
110
118
|
constructor({
|
|
111
119
|
graph,
|
|
112
120
|
publicIdByAssetId,
|
|
113
121
|
assetPublicIds,
|
|
114
|
-
bundleContentHashes
|
|
122
|
+
bundleContentHashes,
|
|
123
|
+
conditions
|
|
115
124
|
}) {
|
|
116
125
|
this._graph = graph;
|
|
117
126
|
this._assetPublicIds = assetPublicIds;
|
|
118
127
|
this._publicIdByAssetId = publicIdByAssetId;
|
|
119
128
|
this._bundleContentHashes = bundleContentHashes;
|
|
129
|
+
this._conditions = conditions;
|
|
120
130
|
}
|
|
121
131
|
|
|
122
132
|
/**
|
|
@@ -128,6 +138,8 @@ class BundleGraph {
|
|
|
128
138
|
let assetGroupIds = new Map();
|
|
129
139
|
let dependencies = new Map();
|
|
130
140
|
let assetGraphNodeIdToBundleGraphNodeId = new Map();
|
|
141
|
+
let conditions = new Map();
|
|
142
|
+
let placeholderToDependency = new Map();
|
|
131
143
|
let assetGraphRootNode = assetGraph.rootNodeId != null ? assetGraph.getNode(assetGraph.rootNodeId) : null;
|
|
132
144
|
(0, _assert().default)(assetGraphRootNode != null && assetGraphRootNode.type === 'root');
|
|
133
145
|
assetGraph.dfsFast(nodeId => {
|
|
@@ -146,6 +158,17 @@ class BundleGraph {
|
|
|
146
158
|
}
|
|
147
159
|
} else if (node != null && node.type === 'asset_group') {
|
|
148
160
|
assetGroupIds.set(nodeId, assetGraph.getNodeIdsConnectedFrom(nodeId));
|
|
161
|
+
} else if ((0, _featureFlags().getFeatureFlag)('conditionalBundlingApi') && node != null && node.type === 'dependency') {
|
|
162
|
+
var _dep$meta;
|
|
163
|
+
// The dependency placeholders in the `importCond` calls that will be in the transformed
|
|
164
|
+
// code need to be mapped to the "real" dependencies, so we need access to a map of placeholders
|
|
165
|
+
// to dependencies
|
|
166
|
+
const dep = node.value;
|
|
167
|
+
// $FlowFixMe[incompatible-type] Meta is untyped
|
|
168
|
+
const placeholder = (_dep$meta = dep.meta) === null || _dep$meta === void 0 ? void 0 : _dep$meta.placeholder;
|
|
169
|
+
if (placeholder != null) {
|
|
170
|
+
placeholderToDependency.set(placeholder, dep);
|
|
171
|
+
}
|
|
149
172
|
}
|
|
150
173
|
});
|
|
151
174
|
let walkVisited = new Set();
|
|
@@ -153,6 +176,34 @@ class BundleGraph {
|
|
|
153
176
|
if (walkVisited.has(nodeId)) return;
|
|
154
177
|
walkVisited.add(nodeId);
|
|
155
178
|
let node = (0, _nullthrows().default)(assetGraph.getNode(nodeId));
|
|
179
|
+
if ((0, _featureFlags().getFeatureFlag)('conditionalBundlingApi') && node.type === 'asset') {
|
|
180
|
+
const asset = node.value;
|
|
181
|
+
if (Array.isArray(asset.meta.conditions)) {
|
|
182
|
+
// $FlowFixMe
|
|
183
|
+
for (const condition of asset.meta.conditions) {
|
|
184
|
+
// Resolve the placeholders that were attached to the asset in JSTransformer to dependencies,
|
|
185
|
+
// as well as create a public id for the condition.
|
|
186
|
+
const {
|
|
187
|
+
key,
|
|
188
|
+
ifTruePlaceholder,
|
|
189
|
+
ifFalsePlaceholder
|
|
190
|
+
} = condition;
|
|
191
|
+
const condHash = (0, _rust().hashString)(`${key}:${ifTruePlaceholder}:${ifFalsePlaceholder}`);
|
|
192
|
+
const condPublicId = (0, _utils2.getPublicId)(condHash, v => conditions.has(v));
|
|
193
|
+
if (conditions.has(condHash)) {
|
|
194
|
+
throw new Error('Unexpected duplicate asset');
|
|
195
|
+
} else {
|
|
196
|
+
conditions.set(condHash, {
|
|
197
|
+
publicId: condPublicId,
|
|
198
|
+
assets: new Set([asset]),
|
|
199
|
+
key,
|
|
200
|
+
ifTrueDependency: (0, _nullthrows().default)(placeholderToDependency.get(ifTruePlaceholder), 'ifTruePlaceholder was undefined'),
|
|
201
|
+
ifFalseDependency: (0, _nullthrows().default)(placeholderToDependency.get(ifFalsePlaceholder), 'ifFalsePlaceholder was undefined')
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
156
207
|
if (node.type === 'dependency' && node.value.symbols != null && node.value.env.shouldScopeHoist &&
|
|
157
208
|
// Disable in dev mode because this feature is at odds with safeToIncrementallyBundle
|
|
158
209
|
isProduction) {
|
|
@@ -338,7 +389,8 @@ class BundleGraph {
|
|
|
338
389
|
graph,
|
|
339
390
|
assetPublicIds,
|
|
340
391
|
bundleContentHashes: new Map(),
|
|
341
|
-
publicIdByAssetId
|
|
392
|
+
publicIdByAssetId,
|
|
393
|
+
conditions
|
|
342
394
|
});
|
|
343
395
|
}
|
|
344
396
|
serialize() {
|
|
@@ -347,7 +399,8 @@ class BundleGraph {
|
|
|
347
399
|
graph: this._graph.serialize(),
|
|
348
400
|
assetPublicIds: this._assetPublicIds,
|
|
349
401
|
bundleContentHashes: this._bundleContentHashes,
|
|
350
|
-
publicIdByAssetId: this._publicIdByAssetId
|
|
402
|
+
publicIdByAssetId: this._publicIdByAssetId,
|
|
403
|
+
conditions: this._conditions
|
|
351
404
|
};
|
|
352
405
|
}
|
|
353
406
|
static deserialize(serialized) {
|
|
@@ -355,7 +408,8 @@ class BundleGraph {
|
|
|
355
408
|
graph: _graph().ContentGraph.deserialize(serialized.graph),
|
|
356
409
|
assetPublicIds: serialized.assetPublicIds,
|
|
357
410
|
bundleContentHashes: serialized.bundleContentHashes,
|
|
358
|
-
publicIdByAssetId: serialized.publicIdByAssetId
|
|
411
|
+
publicIdByAssetId: serialized.publicIdByAssetId,
|
|
412
|
+
conditions: serialized.conditions
|
|
359
413
|
});
|
|
360
414
|
}
|
|
361
415
|
createBundle(opts) {
|
|
@@ -768,7 +822,7 @@ class BundleGraph {
|
|
|
768
822
|
return true;
|
|
769
823
|
}
|
|
770
824
|
let assetNodeId = (0, _nullthrows().default)(this._graph.getNodeIdByContentKey(asset.id));
|
|
771
|
-
if (this._graph.getNodeIdsConnectedTo(assetNodeId, bundleGraphEdgeTypes.references).map(id => this._graph.getNode(id)).some(node => (node === null || node === void 0 ? void 0 : node.type) === 'dependency' && node.value.priority === _types.Priority.lazy && node.value.specifierType !== _types.SpecifierType.url)) {
|
|
825
|
+
if (this._graph.getNodeIdsConnectedTo(assetNodeId, bundleGraphEdgeTypes.references).map(id => this._graph.getNode(id)).some(node => (node === null || node === void 0 ? void 0 : node.type) === 'dependency' && (node.value.priority === _types.Priority.lazy || node.value.priority === _types.Priority.conditional) && node.value.specifierType !== _types.SpecifierType.url)) {
|
|
772
826
|
// If this asset is referenced by any async dependency, it's referenced.
|
|
773
827
|
return true;
|
|
774
828
|
}
|
package/lib/SymbolPropagation.js
CHANGED
|
@@ -108,7 +108,7 @@ function propagateSymbols({
|
|
|
108
108
|
namespaceReexportedSymbols.add('*');
|
|
109
109
|
} else {
|
|
110
110
|
for (let incomingDep of incomingDeps) {
|
|
111
|
-
if (incomingDep.value.symbols == null) {
|
|
111
|
+
if (incomingDep.value.symbols == null || incomingDep.value.priority === _types.Priority.conditional) {
|
|
112
112
|
if (incomingDep.value.sourceAssetId == null) {
|
|
113
113
|
// The root dependency on non-library builds
|
|
114
114
|
isEntry = true;
|
|
@@ -189,5 +189,73 @@ class BundleGraph {
|
|
|
189
189
|
getEntryRoot(target) {
|
|
190
190
|
return this.#graph.getEntryRoot(this.#options.projectRoot, (0, _Target.targetToInternalTarget)(target));
|
|
191
191
|
}
|
|
192
|
+
|
|
193
|
+
// Given a set of dependencies, return any conditions where those dependencies are either
|
|
194
|
+
// the true or false dependency for those conditions. This is currently used to work out which
|
|
195
|
+
// conditions belong to a bundle in packaging.
|
|
196
|
+
getConditionsForDependencies(deps) {
|
|
197
|
+
const conditions = new Set();
|
|
198
|
+
const depIds = deps.map(dep => dep.id);
|
|
199
|
+
for (const condition of this.#graph._conditions.values()) {
|
|
200
|
+
if (depIds.includes(condition.ifTrueDependency.id) || depIds.includes(condition.ifFalseDependency.id)) {
|
|
201
|
+
const [trueAsset, falseAsset] = [condition.ifTrueDependency, condition.ifFalseDependency].map(dep => {
|
|
202
|
+
const resolved = (0, _nullthrows().default)(this.#graph.resolveAsyncDependency(dep));
|
|
203
|
+
if (resolved.type === 'asset') {
|
|
204
|
+
return resolved.value;
|
|
205
|
+
} else {
|
|
206
|
+
return this.#graph.getAssetById(resolved.value.entryAssetId);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
conditions.add({
|
|
210
|
+
publicId: condition.publicId,
|
|
211
|
+
key: condition.key,
|
|
212
|
+
ifTrueDependency: (0, _nullthrows().default)(deps.find(dep => dep.id === condition.ifTrueDependency.id), 'ifTrueDependency was null'),
|
|
213
|
+
ifFalseDependency: (0, _nullthrows().default)(deps.find(dep => dep.id === condition.ifFalseDependency.id), 'ifFalseDependency was null'),
|
|
214
|
+
ifTrueAssetId: this.#graph.getAssetPublicId(trueAsset),
|
|
215
|
+
ifFalseAssetId: this.#graph.getAssetPublicId(falseAsset)
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return conditions;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// This is used to generate information for building a manifest that can
|
|
223
|
+
// be used by a webserver to understand which conditions are used by which bundles,
|
|
224
|
+
// and which bundles those conditions require depending on what they evaluate to.
|
|
225
|
+
getConditionalBundleMapping() {
|
|
226
|
+
let bundleConditions = new Map();
|
|
227
|
+
|
|
228
|
+
// Convert the internal references in conditions to public API references
|
|
229
|
+
for (const cond of this.#graph._conditions.values()) {
|
|
230
|
+
let assets = Array.from(cond.assets).map(asset => (0, _nullthrows().default)(this.getAssetById(asset.id)));
|
|
231
|
+
let bundles = new Set();
|
|
232
|
+
let ifTrueBundles = [];
|
|
233
|
+
let ifFalseBundles = [];
|
|
234
|
+
for (const asset of assets) {
|
|
235
|
+
const bundlesWithAsset = this.getBundlesWithAsset(asset);
|
|
236
|
+
for (const bundle of bundlesWithAsset) {
|
|
237
|
+
bundles.add(bundle);
|
|
238
|
+
}
|
|
239
|
+
const assetDeps = this.getDependencies(asset);
|
|
240
|
+
const depToBundles = dep => {
|
|
241
|
+
const publicDep = (0, _nullthrows().default)(assetDeps.find(assetDep => dep.id === assetDep.id));
|
|
242
|
+
const resolved = (0, _nullthrows().default)(this.resolveAsyncDependency(publicDep));
|
|
243
|
+
(0, _assert().default)(resolved.type === 'bundle_group');
|
|
244
|
+
return this.getBundlesInBundleGroup(resolved.value);
|
|
245
|
+
};
|
|
246
|
+
ifTrueBundles.push(...depToBundles(cond.ifTrueDependency));
|
|
247
|
+
ifFalseBundles.push(...depToBundles(cond.ifFalseDependency));
|
|
248
|
+
}
|
|
249
|
+
for (let bundle of bundles) {
|
|
250
|
+
const conditions = bundleConditions.get(bundle) ?? new Map();
|
|
251
|
+
conditions.set(cond.key, {
|
|
252
|
+
ifTrueBundles,
|
|
253
|
+
ifFalseBundles
|
|
254
|
+
});
|
|
255
|
+
bundleConditions.set(bundle, conditions);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return bundleConditions;
|
|
259
|
+
}
|
|
192
260
|
}
|
|
193
261
|
exports.default = BundleGraph;
|
package/lib/resolveOptions.js
CHANGED
|
@@ -197,6 +197,8 @@ async function resolveOptions(initialOptions) {
|
|
|
197
197
|
outputFormat: initialOptions === null || initialOptions === void 0 || (_initialOptions$defau8 = initialOptions.defaultTargetOptions) === null || _initialOptions$defau8 === void 0 ? void 0 : _initialOptions$defau8.outputFormat,
|
|
198
198
|
isLibrary: initialOptions === null || initialOptions === void 0 || (_initialOptions$defau9 = initialOptions.defaultTargetOptions) === null || _initialOptions$defau9 === void 0 ? void 0 : _initialOptions$defau9.isLibrary
|
|
199
199
|
},
|
|
200
|
+
// unused, feature-flags are set above this to allow this function to use
|
|
201
|
+
// feature-flags
|
|
200
202
|
featureFlags: {
|
|
201
203
|
..._featureFlags().DEFAULT_FEATURE_FLAGS,
|
|
202
204
|
...(initialOptions === null || initialOptions === void 0 ? void 0 : initialOptions.featureFlags)
|
package/lib/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaspack/core",
|
|
3
|
-
"version": "2.12.1-canary.
|
|
3
|
+
"version": "2.12.1-canary.3434+c61bf3cde",
|
|
4
4
|
"license": "(MIT OR Apache-2.0)",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -20,20 +20,20 @@
|
|
|
20
20
|
"check-ts": "tsc --noEmit index.d.ts"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@atlaspack/cache": "2.12.1-canary.
|
|
24
|
-
"@atlaspack/diagnostic": "2.12.1-canary.
|
|
25
|
-
"@atlaspack/events": "2.12.1-canary.
|
|
26
|
-
"@atlaspack/feature-flags": "2.12.1-canary.
|
|
27
|
-
"@atlaspack/fs": "2.12.1-canary.
|
|
28
|
-
"@atlaspack/graph": "3.2.1-canary.
|
|
29
|
-
"@atlaspack/logger": "2.12.1-canary.
|
|
30
|
-
"@atlaspack/package-manager": "2.12.1-canary.
|
|
31
|
-
"@atlaspack/plugin": "2.12.1-canary.
|
|
32
|
-
"@atlaspack/profiler": "2.12.1-canary.
|
|
33
|
-
"@atlaspack/rust": "2.12.1-canary.
|
|
34
|
-
"@atlaspack/types": "2.12.1-canary.
|
|
35
|
-
"@atlaspack/utils": "2.12.1-canary.
|
|
36
|
-
"@atlaspack/workers": "2.12.1-canary.
|
|
23
|
+
"@atlaspack/cache": "2.12.1-canary.3434+c61bf3cde",
|
|
24
|
+
"@atlaspack/diagnostic": "2.12.1-canary.3434+c61bf3cde",
|
|
25
|
+
"@atlaspack/events": "2.12.1-canary.3434+c61bf3cde",
|
|
26
|
+
"@atlaspack/feature-flags": "2.12.1-canary.3434+c61bf3cde",
|
|
27
|
+
"@atlaspack/fs": "2.12.1-canary.3434+c61bf3cde",
|
|
28
|
+
"@atlaspack/graph": "3.2.1-canary.3434+c61bf3cde",
|
|
29
|
+
"@atlaspack/logger": "2.12.1-canary.3434+c61bf3cde",
|
|
30
|
+
"@atlaspack/package-manager": "2.12.1-canary.3434+c61bf3cde",
|
|
31
|
+
"@atlaspack/plugin": "2.12.1-canary.3434+c61bf3cde",
|
|
32
|
+
"@atlaspack/profiler": "2.12.1-canary.3434+c61bf3cde",
|
|
33
|
+
"@atlaspack/rust": "2.12.1-canary.3434+c61bf3cde",
|
|
34
|
+
"@atlaspack/types": "2.12.1-canary.3434+c61bf3cde",
|
|
35
|
+
"@atlaspack/utils": "2.12.1-canary.3434+c61bf3cde",
|
|
36
|
+
"@atlaspack/workers": "2.12.1-canary.3434+c61bf3cde",
|
|
37
37
|
"@mischnic/json-sourcemap": "^0.1.0",
|
|
38
38
|
"@parcel/source-map": "^2.1.1",
|
|
39
39
|
"base-x": "^3.0.8",
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"browser": {
|
|
58
58
|
"./src/serializerCore.js": "./src/serializerCore.browser.js"
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "c61bf3cde53d1cdb5ae13541c644a6e3ef5521e1"
|
|
61
61
|
}
|
package/src/Atlaspack.js
CHANGED
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
fromProjectPathRelative,
|
|
58
58
|
} from './projectPath';
|
|
59
59
|
import {tracer} from '@atlaspack/profiler';
|
|
60
|
-
import {setFeatureFlags} from '@atlaspack/feature-flags';
|
|
60
|
+
import {setFeatureFlags, DEFAULT_FEATURE_FLAGS} from '@atlaspack/feature-flags';
|
|
61
61
|
import {AtlaspackV3, toFileSystemV3} from './atlaspack-v3';
|
|
62
62
|
|
|
63
63
|
registerCoreWithSerializer();
|
|
@@ -105,6 +105,12 @@ export default class Atlaspack {
|
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
const featureFlags = {
|
|
109
|
+
...DEFAULT_FEATURE_FLAGS,
|
|
110
|
+
...this.#initialOptions.featureFlags,
|
|
111
|
+
};
|
|
112
|
+
setFeatureFlags(featureFlags);
|
|
113
|
+
|
|
108
114
|
await initSourcemaps;
|
|
109
115
|
await initRust?.();
|
|
110
116
|
try {
|
|
@@ -117,9 +123,10 @@ export default class Atlaspack {
|
|
|
117
123
|
logger.warn(e);
|
|
118
124
|
}
|
|
119
125
|
|
|
120
|
-
let resolvedOptions: AtlaspackOptions = await resolveOptions(
|
|
121
|
-
this.#initialOptions,
|
|
122
|
-
|
|
126
|
+
let resolvedOptions: AtlaspackOptions = await resolveOptions({
|
|
127
|
+
...this.#initialOptions,
|
|
128
|
+
featureFlags,
|
|
129
|
+
});
|
|
123
130
|
this.#resolvedOptions = resolvedOptions;
|
|
124
131
|
|
|
125
132
|
let rustAtlaspack: AtlaspackV3;
|
|
@@ -152,8 +159,6 @@ export default class Atlaspack {
|
|
|
152
159
|
});
|
|
153
160
|
}
|
|
154
161
|
|
|
155
|
-
setFeatureFlags(resolvedOptions.featureFlags);
|
|
156
|
-
|
|
157
162
|
let {config} = await loadAtlaspackConfig(resolvedOptions);
|
|
158
163
|
this.#config = new AtlaspackConfig(config, resolvedOptions);
|
|
159
164
|
|
package/src/BundleGraph.js
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
Symbol,
|
|
7
7
|
TraversalActions,
|
|
8
8
|
BundleBehavior as IBundleBehavior,
|
|
9
|
+
ConditionMeta,
|
|
9
10
|
} from '@atlaspack/types';
|
|
10
11
|
import type {
|
|
11
12
|
ContentKey,
|
|
@@ -26,6 +27,7 @@ import type {
|
|
|
26
27
|
Environment,
|
|
27
28
|
InternalSourceLocation,
|
|
28
29
|
Target,
|
|
30
|
+
Condition,
|
|
29
31
|
} from './types';
|
|
30
32
|
import type AssetGraph from './AssetGraph';
|
|
31
33
|
import type {ProjectPath} from './projectPath';
|
|
@@ -46,6 +48,7 @@ import {getBundleGroupId, getPublicId} from './utils';
|
|
|
46
48
|
import {ISOLATED_ENVS} from './public/Environment';
|
|
47
49
|
import {fromProjectPath, fromProjectPathRelative} from './projectPath';
|
|
48
50
|
import {HASH_REF_PREFIX} from './constants';
|
|
51
|
+
import {getFeatureFlag} from '@atlaspack/feature-flags';
|
|
49
52
|
|
|
50
53
|
export const bundleGraphEdgeTypes = {
|
|
51
54
|
// A lack of an edge type indicates to follow the edge while traversing
|
|
@@ -91,6 +94,7 @@ type BundleGraphOpts = {|
|
|
|
91
94
|
bundleContentHashes: Map<string, string>,
|
|
92
95
|
assetPublicIds: Set<string>,
|
|
93
96
|
publicIdByAssetId: Map<string, string>,
|
|
97
|
+
conditions: Map<string, Condition>,
|
|
94
98
|
|};
|
|
95
99
|
|
|
96
100
|
type SerializedBundleGraph = {|
|
|
@@ -99,6 +103,7 @@ type SerializedBundleGraph = {|
|
|
|
99
103
|
bundleContentHashes: Map<string, string>,
|
|
100
104
|
assetPublicIds: Set<string>,
|
|
101
105
|
publicIdByAssetId: Map<string, string>,
|
|
106
|
+
conditions: Map<string, Condition>,
|
|
102
107
|
|};
|
|
103
108
|
|
|
104
109
|
function makeReadOnlySet<T>(set: Set<T>): $ReadOnlySet<T> {
|
|
@@ -139,22 +144,26 @@ export default class BundleGraph {
|
|
|
139
144
|
/** The internal core Graph structure */
|
|
140
145
|
_graph: ContentGraph<BundleGraphNode, BundleGraphEdgeType>;
|
|
141
146
|
_bundlePublicIds /*: Set<string> */ = new Set<string>();
|
|
147
|
+
_conditions /*: Map<string, Condition> */ = new Map<string, Condition>();
|
|
142
148
|
|
|
143
149
|
constructor({
|
|
144
150
|
graph,
|
|
145
151
|
publicIdByAssetId,
|
|
146
152
|
assetPublicIds,
|
|
147
153
|
bundleContentHashes,
|
|
154
|
+
conditions,
|
|
148
155
|
}: {|
|
|
149
156
|
graph: ContentGraph<BundleGraphNode, BundleGraphEdgeType>,
|
|
150
157
|
publicIdByAssetId: Map<string, string>,
|
|
151
158
|
assetPublicIds: Set<string>,
|
|
152
159
|
bundleContentHashes: Map<string, string>,
|
|
160
|
+
conditions: Map<string, Condition>,
|
|
153
161
|
|}) {
|
|
154
162
|
this._graph = graph;
|
|
155
163
|
this._assetPublicIds = assetPublicIds;
|
|
156
164
|
this._publicIdByAssetId = publicIdByAssetId;
|
|
157
165
|
this._bundleContentHashes = bundleContentHashes;
|
|
166
|
+
this._conditions = conditions;
|
|
158
167
|
}
|
|
159
168
|
|
|
160
169
|
/**
|
|
@@ -171,6 +180,9 @@ export default class BundleGraph {
|
|
|
171
180
|
let assetGroupIds = new Map();
|
|
172
181
|
let dependencies = new Map();
|
|
173
182
|
let assetGraphNodeIdToBundleGraphNodeId = new Map<NodeId, NodeId>();
|
|
183
|
+
let conditions = new Map<string, Condition>();
|
|
184
|
+
|
|
185
|
+
let placeholderToDependency = new Map<string, Dependency>();
|
|
174
186
|
|
|
175
187
|
let assetGraphRootNode =
|
|
176
188
|
assetGraph.rootNodeId != null
|
|
@@ -195,6 +207,20 @@ export default class BundleGraph {
|
|
|
195
207
|
}
|
|
196
208
|
} else if (node != null && node.type === 'asset_group') {
|
|
197
209
|
assetGroupIds.set(nodeId, assetGraph.getNodeIdsConnectedFrom(nodeId));
|
|
210
|
+
} else if (
|
|
211
|
+
getFeatureFlag('conditionalBundlingApi') &&
|
|
212
|
+
node != null &&
|
|
213
|
+
node.type === 'dependency'
|
|
214
|
+
) {
|
|
215
|
+
// The dependency placeholders in the `importCond` calls that will be in the transformed
|
|
216
|
+
// code need to be mapped to the "real" dependencies, so we need access to a map of placeholders
|
|
217
|
+
// to dependencies
|
|
218
|
+
const dep = node.value;
|
|
219
|
+
// $FlowFixMe[incompatible-type] Meta is untyped
|
|
220
|
+
const placeholder: string | void = dep.meta?.placeholder;
|
|
221
|
+
if (placeholder != null) {
|
|
222
|
+
placeholderToDependency.set(placeholder, dep);
|
|
223
|
+
}
|
|
198
224
|
}
|
|
199
225
|
});
|
|
200
226
|
|
|
@@ -204,6 +230,51 @@ export default class BundleGraph {
|
|
|
204
230
|
walkVisited.add(nodeId);
|
|
205
231
|
|
|
206
232
|
let node = nullthrows(assetGraph.getNode(nodeId));
|
|
233
|
+
|
|
234
|
+
if (getFeatureFlag('conditionalBundlingApi') && node.type === 'asset') {
|
|
235
|
+
const asset = node.value;
|
|
236
|
+
if (Array.isArray(asset.meta.conditions)) {
|
|
237
|
+
// $FlowFixMe
|
|
238
|
+
for (const condition of (asset.meta.conditions: ConditionMeta[])) {
|
|
239
|
+
// Resolve the placeholders that were attached to the asset in JSTransformer to dependencies,
|
|
240
|
+
// as well as create a public id for the condition.
|
|
241
|
+
const {
|
|
242
|
+
key,
|
|
243
|
+
ifTruePlaceholder,
|
|
244
|
+
ifFalsePlaceholder,
|
|
245
|
+
}: {
|
|
246
|
+
key: string,
|
|
247
|
+
ifTruePlaceholder: string,
|
|
248
|
+
ifFalsePlaceholder: string,
|
|
249
|
+
...
|
|
250
|
+
} = condition;
|
|
251
|
+
|
|
252
|
+
const condHash = hashString(
|
|
253
|
+
`${key}:${ifTruePlaceholder}:${ifFalsePlaceholder}`,
|
|
254
|
+
);
|
|
255
|
+
const condPublicId = getPublicId(condHash, v => conditions.has(v));
|
|
256
|
+
|
|
257
|
+
if (conditions.has(condHash)) {
|
|
258
|
+
throw new Error('Unexpected duplicate asset');
|
|
259
|
+
} else {
|
|
260
|
+
conditions.set(condHash, {
|
|
261
|
+
publicId: condPublicId,
|
|
262
|
+
assets: new Set([asset]),
|
|
263
|
+
key,
|
|
264
|
+
ifTrueDependency: nullthrows(
|
|
265
|
+
placeholderToDependency.get(ifTruePlaceholder),
|
|
266
|
+
'ifTruePlaceholder was undefined',
|
|
267
|
+
),
|
|
268
|
+
ifFalseDependency: nullthrows(
|
|
269
|
+
placeholderToDependency.get(ifFalsePlaceholder),
|
|
270
|
+
'ifFalsePlaceholder was undefined',
|
|
271
|
+
),
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
207
278
|
if (
|
|
208
279
|
node.type === 'dependency' &&
|
|
209
280
|
node.value.symbols != null &&
|
|
@@ -440,11 +511,13 @@ export default class BundleGraph {
|
|
|
440
511
|
);
|
|
441
512
|
}
|
|
442
513
|
}
|
|
514
|
+
|
|
443
515
|
return new BundleGraph({
|
|
444
516
|
graph,
|
|
445
517
|
assetPublicIds,
|
|
446
518
|
bundleContentHashes: new Map(),
|
|
447
519
|
publicIdByAssetId,
|
|
520
|
+
conditions,
|
|
448
521
|
});
|
|
449
522
|
}
|
|
450
523
|
|
|
@@ -455,6 +528,7 @@ export default class BundleGraph {
|
|
|
455
528
|
assetPublicIds: this._assetPublicIds,
|
|
456
529
|
bundleContentHashes: this._bundleContentHashes,
|
|
457
530
|
publicIdByAssetId: this._publicIdByAssetId,
|
|
531
|
+
conditions: this._conditions,
|
|
458
532
|
};
|
|
459
533
|
}
|
|
460
534
|
|
|
@@ -464,6 +538,7 @@ export default class BundleGraph {
|
|
|
464
538
|
assetPublicIds: serialized.assetPublicIds,
|
|
465
539
|
bundleContentHashes: serialized.bundleContentHashes,
|
|
466
540
|
publicIdByAssetId: serialized.publicIdByAssetId,
|
|
541
|
+
conditions: serialized.conditions,
|
|
467
542
|
});
|
|
468
543
|
}
|
|
469
544
|
|
|
@@ -1215,7 +1290,8 @@ export default class BundleGraph {
|
|
|
1215
1290
|
.some(
|
|
1216
1291
|
node =>
|
|
1217
1292
|
node?.type === 'dependency' &&
|
|
1218
|
-
node.value.priority === Priority.lazy
|
|
1293
|
+
(node.value.priority === Priority.lazy ||
|
|
1294
|
+
node.value.priority === Priority.conditional) &&
|
|
1219
1295
|
node.value.specifierType !== SpecifierType.url,
|
|
1220
1296
|
)
|
|
1221
1297
|
) {
|
package/src/SymbolPropagation.js
CHANGED
|
@@ -16,7 +16,7 @@ import nullthrows from 'nullthrows';
|
|
|
16
16
|
import {setEqual} from '@atlaspack/utils';
|
|
17
17
|
import logger from '@atlaspack/logger';
|
|
18
18
|
import {md, convertSourceLocationToHighlight} from '@atlaspack/diagnostic';
|
|
19
|
-
import {BundleBehavior} from './types';
|
|
19
|
+
import {BundleBehavior, Priority} from './types';
|
|
20
20
|
import {fromProjectPathRelative, fromProjectPath} from './projectPath';
|
|
21
21
|
|
|
22
22
|
export function propagateSymbols({
|
|
@@ -101,7 +101,10 @@ export function propagateSymbols({
|
|
|
101
101
|
namespaceReexportedSymbols.add('*');
|
|
102
102
|
} else {
|
|
103
103
|
for (let incomingDep of incomingDeps) {
|
|
104
|
-
if (
|
|
104
|
+
if (
|
|
105
|
+
incomingDep.value.symbols == null ||
|
|
106
|
+
incomingDep.value.priority === Priority.conditional
|
|
107
|
+
) {
|
|
105
108
|
if (incomingDep.value.sourceAssetId == null) {
|
|
106
109
|
// The root dependency on non-library builds
|
|
107
110
|
isEntry = true;
|
|
@@ -332,4 +332,110 @@ export default class BundleGraph<TBundle: IBundle>
|
|
|
332
332
|
targetToInternalTarget(target),
|
|
333
333
|
);
|
|
334
334
|
}
|
|
335
|
+
|
|
336
|
+
// Given a set of dependencies, return any conditions where those dependencies are either
|
|
337
|
+
// the true or false dependency for those conditions. This is currently used to work out which
|
|
338
|
+
// conditions belong to a bundle in packaging.
|
|
339
|
+
getConditionsForDependencies(deps: Array<IDependency>): Set<{|
|
|
340
|
+
publicId: string,
|
|
341
|
+
key: string,
|
|
342
|
+
ifTrueDependency: IDependency,
|
|
343
|
+
ifFalseDependency: IDependency,
|
|
344
|
+
ifTrueAssetId: string,
|
|
345
|
+
ifFalseAssetId: string,
|
|
346
|
+
|}> {
|
|
347
|
+
const conditions = new Set();
|
|
348
|
+
const depIds = deps.map(dep => dep.id);
|
|
349
|
+
for (const condition of this.#graph._conditions.values()) {
|
|
350
|
+
if (
|
|
351
|
+
depIds.includes(condition.ifTrueDependency.id) ||
|
|
352
|
+
depIds.includes(condition.ifFalseDependency.id)
|
|
353
|
+
) {
|
|
354
|
+
const [trueAsset, falseAsset] = [
|
|
355
|
+
condition.ifTrueDependency,
|
|
356
|
+
condition.ifFalseDependency,
|
|
357
|
+
].map(dep => {
|
|
358
|
+
const resolved = nullthrows(this.#graph.resolveAsyncDependency(dep));
|
|
359
|
+
if (resolved.type === 'asset') {
|
|
360
|
+
return resolved.value;
|
|
361
|
+
} else {
|
|
362
|
+
return this.#graph.getAssetById(resolved.value.entryAssetId);
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
conditions.add({
|
|
367
|
+
publicId: condition.publicId,
|
|
368
|
+
key: condition.key,
|
|
369
|
+
ifTrueDependency: nullthrows(
|
|
370
|
+
deps.find(dep => dep.id === condition.ifTrueDependency.id),
|
|
371
|
+
'ifTrueDependency was null',
|
|
372
|
+
),
|
|
373
|
+
ifFalseDependency: nullthrows(
|
|
374
|
+
deps.find(dep => dep.id === condition.ifFalseDependency.id),
|
|
375
|
+
'ifFalseDependency was null',
|
|
376
|
+
),
|
|
377
|
+
ifTrueAssetId: this.#graph.getAssetPublicId(trueAsset),
|
|
378
|
+
ifFalseAssetId: this.#graph.getAssetPublicId(falseAsset),
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return conditions;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// This is used to generate information for building a manifest that can
|
|
387
|
+
// be used by a webserver to understand which conditions are used by which bundles,
|
|
388
|
+
// and which bundles those conditions require depending on what they evaluate to.
|
|
389
|
+
getConditionalBundleMapping(): Map<
|
|
390
|
+
TBundle,
|
|
391
|
+
Map<
|
|
392
|
+
string,
|
|
393
|
+
{|
|
|
394
|
+
ifTrueBundles: Array<TBundle>,
|
|
395
|
+
ifFalseBundles: Array<TBundle>,
|
|
396
|
+
|},
|
|
397
|
+
>,
|
|
398
|
+
> {
|
|
399
|
+
let bundleConditions = new Map();
|
|
400
|
+
|
|
401
|
+
// Convert the internal references in conditions to public API references
|
|
402
|
+
for (const cond of this.#graph._conditions.values()) {
|
|
403
|
+
let assets = Array.from(cond.assets).map(asset =>
|
|
404
|
+
nullthrows(this.getAssetById(asset.id)),
|
|
405
|
+
);
|
|
406
|
+
let bundles = new Set<TBundle>();
|
|
407
|
+
let ifTrueBundles = [];
|
|
408
|
+
let ifFalseBundles = [];
|
|
409
|
+
for (const asset of assets) {
|
|
410
|
+
const bundlesWithAsset = this.getBundlesWithAsset(asset);
|
|
411
|
+
for (const bundle of bundlesWithAsset) {
|
|
412
|
+
bundles.add(bundle);
|
|
413
|
+
}
|
|
414
|
+
const assetDeps = this.getDependencies(asset);
|
|
415
|
+
const depToBundles = dep => {
|
|
416
|
+
const publicDep = nullthrows(
|
|
417
|
+
assetDeps.find(assetDep => dep.id === assetDep.id),
|
|
418
|
+
);
|
|
419
|
+
const resolved = nullthrows(this.resolveAsyncDependency(publicDep));
|
|
420
|
+
invariant(resolved.type === 'bundle_group');
|
|
421
|
+
return this.getBundlesInBundleGroup(resolved.value);
|
|
422
|
+
};
|
|
423
|
+
ifTrueBundles.push(...depToBundles(cond.ifTrueDependency));
|
|
424
|
+
ifFalseBundles.push(...depToBundles(cond.ifFalseDependency));
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
for (let bundle of bundles) {
|
|
428
|
+
const conditions = bundleConditions.get(bundle) ?? new Map();
|
|
429
|
+
|
|
430
|
+
conditions.set(cond.key, {
|
|
431
|
+
ifTrueBundles,
|
|
432
|
+
ifFalseBundles,
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
bundleConditions.set(bundle, conditions);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return bundleConditions;
|
|
440
|
+
}
|
|
335
441
|
}
|
package/src/resolveOptions.js
CHANGED
|
@@ -231,6 +231,8 @@ export default async function resolveOptions(
|
|
|
231
231
|
outputFormat: initialOptions?.defaultTargetOptions?.outputFormat,
|
|
232
232
|
isLibrary: initialOptions?.defaultTargetOptions?.isLibrary,
|
|
233
233
|
},
|
|
234
|
+
// unused, feature-flags are set above this to allow this function to use
|
|
235
|
+
// feature-flags
|
|
234
236
|
featureFlags: {...DEFAULT_FEATURE_FLAGS, ...initialOptions?.featureFlags},
|
|
235
237
|
parcelVersion: ATLASPACK_VERSION,
|
|
236
238
|
};
|
package/src/types.js
CHANGED
|
@@ -115,6 +115,7 @@ export const Priority = {
|
|
|
115
115
|
sync: 0,
|
|
116
116
|
parallel: 1,
|
|
117
117
|
lazy: 2,
|
|
118
|
+
conditional: 3,
|
|
118
119
|
};
|
|
119
120
|
|
|
120
121
|
// Must match package_json.rs in node-resolver-rs.
|
|
@@ -542,6 +543,7 @@ export type Bundle = {|
|
|
|
542
543
|
displayName: ?string,
|
|
543
544
|
pipeline: ?string,
|
|
544
545
|
manualSharedBundle?: ?string,
|
|
546
|
+
conditions?: Map<string, string>,
|
|
545
547
|
|};
|
|
546
548
|
|
|
547
549
|
export type BundleNode = {|
|
|
@@ -580,3 +582,11 @@ export type ValidationOpts = {|
|
|
|
580
582
|
|};
|
|
581
583
|
|
|
582
584
|
export type ReportFn = (event: ReporterEvent) => void | Promise<void>;
|
|
585
|
+
|
|
586
|
+
export type Condition = {|
|
|
587
|
+
publicId: string,
|
|
588
|
+
assets: Set<Asset>,
|
|
589
|
+
key: string,
|
|
590
|
+
ifTrueDependency: Dependency,
|
|
591
|
+
ifFalseDependency: Dependency,
|
|
592
|
+
|};
|