animate/webGl/my-threejs-test/node_modules/@parcel/bundler-default/lib/DefaultBundler.js

1412 lines
63 KiB
JavaScript
Raw Normal View History

2024-06-24 09:24:00 +00:00
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
function _graph() {
const data = require("@parcel/graph");
_graph = function () {
return data;
};
return data;
}
function _assert() {
const data = _interopRequireDefault(require("assert"));
_assert = function () {
return data;
};
return data;
}
function _plugin() {
const data = require("@parcel/plugin");
_plugin = function () {
return data;
};
return data;
}
function _utils() {
const data = require("@parcel/utils");
_utils = function () {
return data;
};
return data;
}
function _nullthrows() {
const data = _interopRequireDefault(require("nullthrows"));
_nullthrows = function () {
return data;
};
return data;
}
function _path() {
const data = _interopRequireDefault(require("path"));
_path = function () {
return data;
};
return data;
}
function _diagnostic() {
const data = require("@parcel/diagnostic");
_diagnostic = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Default options by http version.
const HTTP_OPTIONS = {
'1': {
minBundles: 1,
manualSharedBundles: [],
minBundleSize: 30000,
maxParallelRequests: 6,
disableSharedBundles: false
},
'2': {
minBundles: 1,
manualSharedBundles: [],
minBundleSize: 20000,
maxParallelRequests: 25,
disableSharedBundles: false
}
};
/* BundleRoot - An asset that is the main entry of a Bundle. */
const dependencyPriorityEdges = {
sync: 1,
parallel: 2,
lazy: 3
};
// IdealGraph is the structure we will pass to decorate,
// which mutates the assetGraph into the bundleGraph we would
// expect from default bundler
/**
*
* The Bundler works by creating an IdealGraph, which contains a BundleGraph that models bundles
* connected to other bundles by what references them, and thus models BundleGroups.
*
* First, we enter `bundle({bundleGraph, config})`. Here, "bundleGraph" is actually just the
* assetGraph turned into a type `MutableBundleGraph`, which will then be mutated in decorate,
* and turned into what we expect the bundleGraph to be as per the old (default) bundler structure
* & what the rest of Parcel expects a BundleGraph to be.
*
* `bundle({bundleGraph, config})` First gets a Mapping of target to entries, In most cases there is
* only one target, and one or more entries. (Targets are pertinent in monorepos or projects where you
* will have two or more distDirs, or output folders.) Then calls create IdealGraph and Decorate per target.
*
*/
var _default = exports.default = new (_plugin().Bundler)({
loadConfig({
config,
options,
logger
}) {
return loadBundlerConfig(config, options, logger);
},
bundle({
bundleGraph,
config,
logger
}) {
let targetMap = getEntryByTarget(bundleGraph); // Organize entries by target output folder/ distDir
let graphs = [];
for (let entries of targetMap.values()) {
// Create separate bundleGraphs per distDir
graphs.push(createIdealGraph(bundleGraph, config, entries, logger));
}
for (let g of graphs) {
decorateLegacyGraph(g, bundleGraph); //mutate original graph
}
},
optimize() {}
});
function decorateLegacyGraph(idealGraph, bundleGraph) {
let idealBundleToLegacyBundle = new Map();
let {
bundleGraph: idealBundleGraph,
dependencyBundleGraph,
bundleGroupBundleIds,
manualAssetToBundle
} = idealGraph;
let entryBundleToBundleGroup = new Map();
// Step Create Bundles: Create bundle groups, bundles, and shared bundles and add assets to them
for (let [bundleNodeId, idealBundle] of idealBundleGraph.nodes.entries()) {
if (!idealBundle || idealBundle === 'root') continue;
let entryAsset = idealBundle.mainEntryAsset;
let bundleGroups = [];
let bundleGroup;
let bundle;
if (bundleGroupBundleIds.has(bundleNodeId)) {
(0, _assert().default)(idealBundle.manualSharedBundle == null, 'Unstable Manual Shared Bundle feature is processing a manualSharedBundle as a BundleGroup');
let dependencies = dependencyBundleGraph.getNodeIdsConnectedTo(dependencyBundleGraph.getNodeIdByContentKey(String(bundleNodeId)), _graph().ALL_EDGE_TYPES).map(nodeId => {
let dependency = (0, _nullthrows().default)(dependencyBundleGraph.getNode(nodeId));
(0, _assert().default)(dependency.type === 'dependency');
return dependency.value;
});
(0, _assert().default)(entryAsset != null, 'Processing a bundleGroup with no entry asset');
for (let dependency of dependencies) {
bundleGroup = bundleGraph.createBundleGroup(dependency, idealBundle.target);
bundleGroups.push(bundleGroup);
}
(0, _assert().default)(bundleGroup);
entryBundleToBundleGroup.set(bundleNodeId, bundleGroup);
bundle = (0, _nullthrows().default)(bundleGraph.createBundle({
entryAsset: (0, _nullthrows().default)(entryAsset),
needsStableName: idealBundle.needsStableName,
bundleBehavior: idealBundle.bundleBehavior,
target: idealBundle.target,
manualSharedBundle: idealBundle.manualSharedBundle
}));
bundleGraph.addBundleToBundleGroup(bundle, bundleGroup);
} else if (idealBundle.sourceBundles.size > 0 && !idealBundle.mainEntryAsset) {
let uniqueKey = idealBundle.uniqueKey != null ? idealBundle.uniqueKey : [...idealBundle.assets].map(asset => asset.id).join(',');
bundle = (0, _nullthrows().default)(bundleGraph.createBundle({
uniqueKey,
needsStableName: idealBundle.needsStableName,
bundleBehavior: idealBundle.bundleBehavior,
type: idealBundle.type,
target: idealBundle.target,
env: idealBundle.env,
manualSharedBundle: idealBundle.manualSharedBundle
}));
} else if (idealBundle.uniqueKey != null) {
bundle = (0, _nullthrows().default)(bundleGraph.createBundle({
uniqueKey: idealBundle.uniqueKey,
needsStableName: idealBundle.needsStableName,
bundleBehavior: idealBundle.bundleBehavior,
type: idealBundle.type,
target: idealBundle.target,
env: idealBundle.env,
manualSharedBundle: idealBundle.manualSharedBundle
}));
} else {
(0, _assert().default)(entryAsset != null);
bundle = (0, _nullthrows().default)(bundleGraph.createBundle({
entryAsset,
needsStableName: idealBundle.needsStableName,
bundleBehavior: idealBundle.bundleBehavior,
target: idealBundle.target,
manualSharedBundle: idealBundle.manualSharedBundle
}));
}
idealBundleToLegacyBundle.set(idealBundle, bundle);
for (let asset of idealBundle.assets) {
bundleGraph.addAssetToBundle(asset, bundle);
}
}
// Step Internalization: Internalize dependencies for bundles
for (let idealBundle of idealBundleGraph.nodes) {
if (!idealBundle || idealBundle === 'root') continue;
let bundle = (0, _nullthrows().default)(idealBundleToLegacyBundle.get(idealBundle));
if (idealBundle.internalizedAssets) {
idealBundle.internalizedAssets.forEach(internalized => {
let incomingDeps = bundleGraph.getIncomingDependencies(idealGraph.assets[internalized]);
for (let incomingDep of incomingDeps) {
if (incomingDep.priority === 'lazy' && incomingDep.specifierType !== 'url' && bundle.hasDependency(incomingDep)) {
bundleGraph.internalizeAsyncDependency(bundle, incomingDep);
}
}
});
}
}
// Unstable Manual Shared Bundles
// NOTE: This only works under the assumption that manual shared bundles would have
// always already been loaded before the bundle that requires internalization.
for (let manualSharedAsset of manualAssetToBundle.keys()) {
let incomingDeps = bundleGraph.getIncomingDependencies(manualSharedAsset);
for (let incomingDep of incomingDeps) {
if (incomingDep.priority === 'lazy' && incomingDep.specifierType !== 'url') {
let bundles = bundleGraph.getBundlesWithDependency(incomingDep);
for (let bundle of bundles) {
bundleGraph.internalizeAsyncDependency(bundle, incomingDep);
}
}
}
}
// Step Add to BundleGroups: Add bundles to their bundle groups
idealBundleGraph.traverse((nodeId, _, actions) => {
let node = idealBundleGraph.getNode(nodeId);
if (node === 'root') {
return;
}
actions.skipChildren();
let outboundNodeIds = idealBundleGraph.getNodeIdsConnectedFrom(nodeId);
let entryBundle = (0, _nullthrows().default)(idealBundleGraph.getNode(nodeId));
(0, _assert().default)(entryBundle !== 'root');
let legacyEntryBundle = (0, _nullthrows().default)(idealBundleToLegacyBundle.get(entryBundle));
for (let id of outboundNodeIds) {
let siblingBundle = (0, _nullthrows().default)(idealBundleGraph.getNode(id));
(0, _assert().default)(siblingBundle !== 'root');
let legacySiblingBundle = (0, _nullthrows().default)(idealBundleToLegacyBundle.get(siblingBundle));
bundleGraph.createBundleReference(legacyEntryBundle, legacySiblingBundle);
}
});
// Step References: Add references to all bundles
for (let [asset, references] of idealGraph.assetReference) {
for (let [dependency, bundle] of references) {
let legacyBundle = (0, _nullthrows().default)(idealBundleToLegacyBundle.get(bundle));
bundleGraph.createAssetReference(dependency, asset, legacyBundle);
}
}
for (let {
from,
to
} of idealBundleGraph.getAllEdges()) {
let sourceBundle = (0, _nullthrows().default)(idealBundleGraph.getNode(from));
if (sourceBundle === 'root') {
continue;
}
(0, _assert().default)(sourceBundle !== 'root');
let legacySourceBundle = (0, _nullthrows().default)(idealBundleToLegacyBundle.get(sourceBundle));
let targetBundle = (0, _nullthrows().default)(idealBundleGraph.getNode(to));
if (targetBundle === 'root') {
continue;
}
(0, _assert().default)(targetBundle !== 'root');
let legacyTargetBundle = (0, _nullthrows().default)(idealBundleToLegacyBundle.get(targetBundle));
bundleGraph.createBundleReference(legacySourceBundle, legacyTargetBundle);
}
}
function createIdealGraph(assetGraph, config, entries, logger) {
// Asset to the bundle and group it's an entry of
let bundleRoots = new Map();
let bundles = new Map();
let dependencyBundleGraph = new (_graph().ContentGraph)();
let assetReference = new (_utils().DefaultMap)(() => []);
// A Graph of Bundles and a root node (dummy string), which models only Bundles, and connections to their
// referencing Bundle. There are no actual BundleGroup nodes, just bundles that take on that role.
let bundleGraph = new (_graph().Graph)();
let stack = [];
let bundleRootEdgeTypes = {
parallel: 1,
lazy: 2
};
// Graph that models bundleRoots, with parallel & async deps only to inform reachability
let bundleRootGraph = new (_graph().Graph)();
let assetToBundleRootNodeId = new Map();
let bundleGroupBundleIds = new Set();
let bundleGraphRootNodeId = (0, _nullthrows().default)(bundleGraph.addNode('root'));
bundleGraph.setRootNodeId(bundleGraphRootNodeId);
// Step Create Entry Bundles
for (let [asset, dependency] of entries) {
let bundle = createBundle({
asset,
target: (0, _nullthrows().default)(dependency.target),
needsStableName: dependency.isEntry
});
let nodeId = bundleGraph.addNode(bundle);
bundles.set(asset.id, nodeId);
bundleRoots.set(asset, [nodeId, nodeId]);
bundleGraph.addEdge(bundleGraphRootNodeId, nodeId);
dependencyBundleGraph.addEdge(dependencyBundleGraph.addNodeByContentKeyIfNeeded(dependency.id, {
value: dependency,
type: 'dependency'
}), dependencyBundleGraph.addNodeByContentKeyIfNeeded(String(nodeId), {
value: bundle,
type: 'bundle'
}), dependencyPriorityEdges[dependency.priority]);
bundleGroupBundleIds.add(nodeId);
}
let assets = [];
let assetToIndex = new Map();
//Manual is a map of the user-given name to the bundle node Id that corresponds to ALL the assets that match any glob in that user-specified array
let manualSharedMap = new Map();
// May need a map to be able to look up NON- bundle root assets which need special case instructions
// Use this when placing assets into bundles, to avoid duplication
let manualAssetToBundle = new Map();
let {
manualAssetToConfig,
constantModuleToMSB
} = function makeManualAssetToConfigLookup() {
let manualAssetToConfig = new Map();
let constantModuleToMSB = new (_utils().DefaultMap)(() => []);
if (config.manualSharedBundles.length === 0) {
return {
manualAssetToConfig,
constantModuleToMSB
};
}
let parentsToConfig = new (_utils().DefaultMap)(() => []);
for (let c of config.manualSharedBundles) {
if (c.root != null) {
parentsToConfig.get(_path().default.join(config.projectRoot, c.root)).push(c);
}
}
let numParentsToFind = parentsToConfig.size;
let configToParentAsset = new Map();
assetGraph.traverse((node, _, actions) => {
if (node.type === 'asset' && parentsToConfig.has(node.value.filePath)) {
for (let c of parentsToConfig.get(node.value.filePath)) {
configToParentAsset.set(c, node.value);
}
numParentsToFind--;
if (numParentsToFind === 0) {
// If we've found all parents we can stop traversal
actions.stop();
}
}
});
// Process in reverse order so earlier configs take precedence
for (let c of config.manualSharedBundles.reverse()) {
if (c.root != null && !configToParentAsset.has(c)) {
logger.warn({
origin: '@parcel/bundler-default',
message: `Manual shared bundle "${c.name}" skipped, no root asset found`
});
continue;
}
let parentAsset = configToParentAsset.get(c);
let assetRegexes = c.assets.map(glob => (0, _utils().globToRegex)(glob));
assetGraph.traverse((node, _, actions) => {
if (node.type === 'asset' && (!Array.isArray(c.types) || c.types.includes(node.value.type))) {
// +1 accounts for leading slash
let projectRelativePath = node.value.filePath.slice(config.projectRoot.length + 1);
if (!assetRegexes.some(regex => regex.test(projectRelativePath))) {
return;
}
// We track all matching MSB's for constant modules as they are never duplicated
// and need to be assigned to all matching bundles
if (node.value.meta.isConstantModule === true) {
constantModuleToMSB.get(node.value).push(c);
}
manualAssetToConfig.set(node.value, c);
return;
}
if (node.type === 'dependency' && node.value.priority === 'lazy' && parentAsset) {
// Don't walk past the bundle group assets
actions.skipChildren();
}
}, parentAsset);
}
return {
manualAssetToConfig,
constantModuleToMSB
};
}();
let manualBundleToInternalizedAsset = new (_utils().DefaultMap)(() => []);
/**
* Step Create Bundles: Traverse the assetGraph (aka MutableBundleGraph) and create bundles
* for asset type changes, parallel, inline, and async or lazy dependencies,
* adding only that asset to each bundle, not its entire subgraph.
*/
assetGraph.traverse({
enter(node, context, actions) {
if (node.type === 'asset') {
if ((context === null || context === void 0 ? void 0 : context.type) === 'dependency' && context !== null && context !== void 0 && context.value.isEntry && !entries.has(node.value)) {
// Skip whole subtrees of other targets by skipping those entries
actions.skipChildren();
return node;
}
assetToIndex.set(node.value, assets.length);
assets.push(node.value);
let bundleIdTuple = bundleRoots.get(node.value);
if (bundleIdTuple && bundleIdTuple[0] === bundleIdTuple[1]) {
// Push to the stack (only) when a new bundle is created
stack.push([node.value, bundleIdTuple[0]]);
} else if (bundleIdTuple) {
// Otherwise, push on the last bundle that marks the start of a BundleGroup
stack.push([node.value, stack[stack.length - 1][1]]);
}
} else if (node.type === 'dependency') {
if (context == null) {
return node;
}
let dependency = node.value;
(0, _assert().default)((context === null || context === void 0 ? void 0 : context.type) === 'asset');
let assets = assetGraph.getDependencyAssets(dependency);
if (assets.length === 0) {
return node;
}
for (let childAsset of assets) {
let bundleId = bundles.get(childAsset.id);
let bundle;
// MSB Step 1: Match glob on filepath and type for any asset
let manualSharedBundleKey;
let manualSharedObject = manualAssetToConfig.get(childAsset);
if (manualSharedObject) {
// MSB Step 2: Generate a key for which to look up this manual bundle with
manualSharedBundleKey = manualSharedObject.name + ',' + childAsset.type;
}
if (
// MSB Step 3: If a bundle for these globs already exsits, use it
manualSharedBundleKey != null && manualSharedMap.has(manualSharedBundleKey)) {
bundleId = (0, _nullthrows().default)(manualSharedMap.get(manualSharedBundleKey));
}
if (dependency.priority === 'lazy' || childAsset.bundleBehavior === 'isolated' // An isolated Dependency, or Bundle must contain all assets it needs to load.
) {
if (bundleId == null) {
var _dependency$bundleBeh;
let firstBundleGroup = (0, _nullthrows().default)(bundleGraph.getNode(stack[0][1]));
(0, _assert().default)(firstBundleGroup !== 'root');
bundle = createBundle({
asset: childAsset,
target: firstBundleGroup.target,
needsStableName: dependency.bundleBehavior === 'inline' || childAsset.bundleBehavior === 'inline' ? false : dependency.isEntry || dependency.needsStableName,
bundleBehavior: (_dependency$bundleBeh = dependency.bundleBehavior) !== null && _dependency$bundleBeh !== void 0 ? _dependency$bundleBeh : childAsset.bundleBehavior
});
bundleId = bundleGraph.addNode(bundle);
bundles.set(childAsset.id, bundleId);
bundleRoots.set(childAsset, [bundleId, bundleId]);
bundleGroupBundleIds.add(bundleId);
bundleGraph.addEdge(bundleGraphRootNodeId, bundleId);
if (manualSharedObject) {
// MSB Step 4: If this was the first instance of a match, mark mainAsset for internalization
// since MSBs should not have main entry assets
manualBundleToInternalizedAsset.get(bundleId).push(childAsset);
}
} else {
bundle = (0, _nullthrows().default)(bundleGraph.getNode(bundleId));
(0, _assert().default)(bundle !== 'root');
if (
// If this dependency requests isolated, but the bundle is not,
// make the bundle isolated for all uses.
dependency.bundleBehavior === 'isolated' && bundle.bundleBehavior == null) {
bundle.bundleBehavior = dependency.bundleBehavior;
}
}
dependencyBundleGraph.addEdge(dependencyBundleGraph.addNodeByContentKeyIfNeeded(dependency.id, {
value: dependency,
type: 'dependency'
}), dependencyBundleGraph.addNodeByContentKeyIfNeeded(String(bundleId), {
value: bundle,
type: 'bundle'
}), dependencyPriorityEdges[dependency.priority]);
} else if (dependency.priority === 'parallel' || childAsset.bundleBehavior === 'inline') {
// The referencing bundleRoot is the root of a Bundle that first brings in another bundle (essentially the FIRST parent of a bundle, this may or may not be a bundleGroup)
let [referencingBundleRoot, bundleGroupNodeId] = (0, _nullthrows().default)(stack[stack.length - 1]);
let bundleGroup = (0, _nullthrows().default)(bundleGraph.getNode(bundleGroupNodeId));
(0, _assert().default)(bundleGroup !== 'root');
let referencingBundleId = (0, _nullthrows().default)(bundleRoots.get(referencingBundleRoot))[0];
let referencingBundle = (0, _nullthrows().default)(bundleGraph.getNode(referencingBundleId));
(0, _assert().default)(referencingBundle !== 'root');
if (bundleId == null) {
var _dependency$bundleBeh2;
bundle = createBundle({
// Bundles created from type changes shouldn't have an entry asset.
asset: childAsset,
type: childAsset.type,
env: childAsset.env,
bundleBehavior: (_dependency$bundleBeh2 = dependency.bundleBehavior) !== null && _dependency$bundleBeh2 !== void 0 ? _dependency$bundleBeh2 : childAsset.bundleBehavior,
target: referencingBundle.target,
needsStableName: childAsset.bundleBehavior === 'inline' || dependency.bundleBehavior === 'inline' || dependency.priority === 'parallel' && !dependency.needsStableName ? false : referencingBundle.needsStableName
});
bundleId = bundleGraph.addNode(bundle);
} else {
bundle = bundleGraph.getNode(bundleId);
(0, _assert().default)(bundle != null && bundle !== 'root');
if (
// If this dependency requests isolated, but the bundle is not,
// make the bundle isolated for all uses.
dependency.bundleBehavior === 'isolated' && bundle.bundleBehavior == null) {
bundle.bundleBehavior = dependency.bundleBehavior;
}
}
bundles.set(childAsset.id, bundleId);
// A bundle can belong to multiple bundlegroups, all the bundle groups of it's
// ancestors, and all async and entry bundles before it are "bundle groups"
// TODO: We may need to track bundles to all bundleGroups it belongs to in the future.
bundleRoots.set(childAsset, [bundleId, bundleGroupNodeId]);
bundleGraph.addEdge(referencingBundleId, bundleId);
if (bundleId != bundleGroupNodeId) {
dependencyBundleGraph.addEdge(dependencyBundleGraph.addNodeByContentKeyIfNeeded(dependency.id, {
value: dependency,
type: 'dependency'
}), dependencyBundleGraph.addNodeByContentKeyIfNeeded(String(bundleId), {
value: bundle,
type: 'bundle'
}), dependencyPriorityEdges.parallel);
}
assetReference.get(childAsset).push([dependency, bundle]);
} else {
bundleId = null;
}
if (manualSharedObject && bundleId != null) {
// MSB Step 5: At this point we've either created or found an existing MSB bundle
// add the asset if it doesn't already have it and set key
(0, _assert().default)(bundle !== 'root' && bundle != null && bundleId != null);
manualAssetToBundle.set(childAsset, bundleId);
if (!bundle.assets.has(childAsset)) {
// Add asset to bundle
bundle.assets.add(childAsset);
bundle.size += childAsset.stats.size;
}
bundles.set(childAsset.id, bundleId);
bundleRoots.set(childAsset, [bundleId, bundleId]);
(0, _assert().default)(manualSharedBundleKey != null);
// Ensure we set key to BundleId so the next glob match uses the appropriate bundle
if (!manualSharedMap.has(manualSharedBundleKey)) {
manualSharedMap.set(manualSharedBundleKey, bundleId);
}
bundle.manualSharedBundle = manualSharedObject.name;
bundle.uniqueKey = manualSharedObject.name + childAsset.type;
}
}
}
return node;
},
exit(node) {
var _stack;
if (((_stack = stack[stack.length - 1]) === null || _stack === void 0 ? void 0 : _stack[0]) === node.value) {
stack.pop();
}
}
}, null, {
skipUnusedDependencies: true
});
// Strip MSBs of entries
for (let [nodeId, internalizedAssets] of manualBundleToInternalizedAsset.entries()) {
let bundle = bundleGraph.getNode(nodeId);
(0, _assert().default)(bundle != null && bundle !== 'root');
if (!bundle.internalizedAssets) {
bundle.internalizedAssets = new (_graph().BitSet)(assets.length);
}
for (let asset of internalizedAssets) {
bundle.internalizedAssets.add((0, _nullthrows().default)(assetToIndex.get(asset)));
}
bundle.mainEntryAsset = null;
bundleGroupBundleIds.delete(nodeId); // manual bundles can now act as shared, non-bundle group, should they be non-bundleRoots as well?
}
/**
* Step Determine Reachability: Determine reachability for every asset from each bundleRoot.
* This is later used to determine which bundles to place each asset in. We build up two
* structures, one traversal each. ReachableRoots to store sync relationships,
* and bundleRootGraph to store the minimal availability through `parallel` and `async` relationships.
* The two graphs, are used to build up ancestorAssets, a structure which holds all availability by
* all means for each asset.
*/
let rootNodeId = bundleRootGraph.addNode(-1);
bundleRootGraph.setRootNodeId(rootNodeId);
for (let [root] of bundleRoots) {
let nodeId = bundleRootGraph.addNode((0, _nullthrows().default)(assetToIndex.get(root)));
assetToBundleRootNodeId.set(root, nodeId);
if (entries.has(root)) {
bundleRootGraph.addEdge(rootNodeId, nodeId);
}
}
// reachableRoots is an array of bit sets for each asset. Each bit set
// indicates which bundle roots are reachable from that asset synchronously.
let reachableRoots = [];
for (let i = 0; i < assets.length; i++) {
reachableRoots.push(new (_graph().BitSet)(bundleRootGraph.nodes.length));
}
// reachableAssets is the inverse mapping of reachableRoots. For each bundle root,
// it contains a bit set that indicates which assets are reachable from it.
let reachableAssets = [];
// ancestorAssets maps bundle roots to the set of all assets available to it at runtime,
// including in earlier parallel bundles. These are intersected through all paths to
// the bundle to ensure that the available assets are always present no matter in which
// order the bundles are loaded.
let ancestorAssets = [];
let inlineConstantDeps = new (_utils().DefaultMap)(() => new Set());
for (let [bundleRootId, assetId] of bundleRootGraph.nodes.entries()) {
let reachable = new (_graph().BitSet)(assets.length);
reachableAssets.push(reachable);
ancestorAssets.push(null);
if (bundleRootId == rootNodeId || assetId == null) continue;
// Add sync relationships to ReachableRoots
let root = assets[assetId];
assetGraph.traverse((node, _, actions) => {
if (node.value === root) {
return;
}
if (node.type === 'dependency') {
let dependency = node.value;
if (dependency.priority !== 'sync' && dependencyBundleGraph.hasContentKey(dependency.id)) {
let assets = assetGraph.getDependencyAssets(dependency);
if (assets.length === 0) {
return;
}
(0, _assert().default)(assets.length === 1);
let bundleRoot = assets[0];
let bundle = (0, _nullthrows().default)(bundleGraph.getNode((0, _nullthrows().default)(bundles.get(bundleRoot.id))));
if (bundle !== 'root' && bundle.bundleBehavior == null && !bundle.env.isIsolated() && bundle.env.context === root.env.context) {
bundleRootGraph.addEdge(bundleRootId, (0, _nullthrows().default)(assetToBundleRootNodeId.get(bundleRoot)), dependency.priority === 'parallel' ? bundleRootEdgeTypes.parallel : bundleRootEdgeTypes.lazy);
}
}
if (dependency.priority !== 'sync') {
actions.skipChildren();
}
return;
}
//asset node type
let asset = node.value;
if (asset.bundleBehavior != null) {
actions.skipChildren();
return;
}
let assetIndex = (0, _nullthrows().default)(assetToIndex.get(node.value));
reachable.add(assetIndex);
reachableRoots[assetIndex].add(bundleRootId);
if (asset.meta.isConstantModule === true) {
let parents = assetGraph.getIncomingDependencies(asset).map(dep => (0, _nullthrows().default)(assetGraph.getAssetWithDependency(dep)));
for (let parent of parents) {
inlineConstantDeps.get(parent).add(asset);
}
}
return;
}, root, {
skipUnusedDependencies: true
});
}
for (let entry of entries.keys()) {
// Initialize an empty set of ancestors available to entries
let entryId = (0, _nullthrows().default)(assetToBundleRootNodeId.get(entry));
ancestorAssets[entryId] = new (_graph().BitSet)(assets.length);
}
// Step Determine Availability
// Visit nodes in a topological order, visiting parent nodes before child nodes.
// This allows us to construct an understanding of which assets will already be
// loaded and available when a bundle runs, by pushing available assets downwards and
// computing the intersection of assets available through all possible paths to a bundle.
// We call this structure ancestorAssets, a Map that tracks a bundleRoot,
// to all assets available to it (meaning they will exist guaranteed when the bundleRoot is loaded)
// The topological sort ensures all parents are visited before the node we want to process.
for (let nodeId of bundleRootGraph.topoSort(_graph().ALL_EDGE_TYPES)) {
if (nodeId === rootNodeId) continue;
const bundleRoot = assets[(0, _nullthrows().default)(bundleRootGraph.getNode(nodeId))];
let bundleGroupId = (0, _nullthrows().default)(bundleRoots.get(bundleRoot))[1];
// At a BundleRoot, we access it's available assets (via ancestorAssets),
// and add to that all assets within the bundles in that BundleGroup.
// This set is available to all bundles in a particular bundleGroup because
// bundleGroups are just bundles loaded at the same time. However it is
// not true that a bundle's available assets = all assets of all the bundleGroups
// it belongs to. It's the intersection of those sets.
let available;
if (bundleRoot.bundleBehavior === 'isolated') {
available = new (_graph().BitSet)(assets.length);
} else {
available = (0, _nullthrows().default)(ancestorAssets[nodeId]).clone();
for (let bundleIdInGroup of [bundleGroupId, ...bundleGraph.getNodeIdsConnectedFrom(bundleGroupId)]) {
let bundleInGroup = (0, _nullthrows().default)(bundleGraph.getNode(bundleIdInGroup));
(0, _assert().default)(bundleInGroup !== 'root');
if (bundleInGroup.bundleBehavior != null) {
continue;
}
for (let bundleRoot of bundleInGroup.assets) {
// Assets directly connected to current bundleRoot
available.add((0, _nullthrows().default)(assetToIndex.get(bundleRoot)));
available.union(reachableAssets[(0, _nullthrows().default)(assetToBundleRootNodeId.get(bundleRoot))]);
}
}
}
// Now that we have bundleGroup availability, we will propagate that down to all the children
// of this bundleGroup. For a child, we also must maintain parallel availability. If it has
// parallel siblings that come before it, those, too, are available to it. Add those parallel
// available assets to the set of available assets for this child as well.
let children = bundleRootGraph.getNodeIdsConnectedFrom(nodeId, _graph().ALL_EDGE_TYPES);
let parallelAvailability = new (_graph().BitSet)(assets.length);
for (let childId of children) {
let assetId = (0, _nullthrows().default)(bundleRootGraph.getNode(childId));
let child = assets[assetId];
let bundleBehavior = getBundleFromBundleRoot(child).bundleBehavior;
if (bundleBehavior != null) {
continue;
}
let isParallel = bundleRootGraph.hasEdge(nodeId, childId, bundleRootEdgeTypes.parallel);
// Most of the time, a child will have many parent bundleGroups,
// so the next time we peek at a child from another parent, we will
// intersect the availability built there with the previously computed
// availability. this ensures no matter which bundleGroup loads a particular bundle,
// it will only assume availability of assets it has under any circumstance
const childAvailableAssets = ancestorAssets[childId];
let currentChildAvailable = isParallel ? _graph().BitSet.union(parallelAvailability, available) : available;
if (childAvailableAssets != null) {
childAvailableAssets.intersect(currentChildAvailable);
} else {
ancestorAssets[childId] = currentChildAvailable.clone();
}
if (isParallel) {
parallelAvailability.union(reachableAssets[childId]);
parallelAvailability.add(assetId); //The next sibling should have older sibling available via parallel
}
}
}
// Step Internalize async bundles - internalize Async bundles if and only if,
// the bundle is synchronously available elsewhere.
// We can query sync assets available via reachableRoots. If the parent has
// the bundleRoot by reachableRoots AND ancestorAssets, internalize it.
for (let [id, bundleRootId] of bundleRootGraph.nodes.entries()) {
if (bundleRootId == null || id === rootNodeId) continue;
let bundleRoot = assets[bundleRootId];
if (manualAssetToConfig.has(bundleRoot)) {
// We internalize for MSBs later, we should never delete MSBs
continue;
}
let parentRoots = bundleRootGraph.getNodeIdsConnectedTo(id, _graph().ALL_EDGE_TYPES);
let canDelete = getBundleFromBundleRoot(bundleRoot).bundleBehavior !== 'isolated';
if (parentRoots.length === 0) continue;
for (let parentId of parentRoots) {
var _ancestorAssets$paren;
if (parentId === rootNodeId) {
// connected to root.
canDelete = false;
continue;
}
if (reachableAssets[parentId].has(bundleRootId) || (_ancestorAssets$paren = ancestorAssets[parentId]) !== null && _ancestorAssets$paren !== void 0 && _ancestorAssets$paren.has(bundleRootId)) {
let parentAssetId = (0, _nullthrows().default)(bundleRootGraph.getNode(parentId));
let parent = assets[parentAssetId];
let parentBundle = bundleGraph.getNode((0, _nullthrows().default)(bundles.get(parent.id)));
(0, _assert().default)(parentBundle != null && parentBundle !== 'root');
if (!parentBundle.internalizedAssets) {
parentBundle.internalizedAssets = new (_graph().BitSet)(assets.length);
}
parentBundle.internalizedAssets.add(bundleRootId);
} else {
canDelete = false;
}
}
if (canDelete) {
deleteBundle(bundleRoot);
}
}
function assignInlineConstants(parentAsset, bundle) {
for (let inlineConstant of inlineConstantDeps.get(parentAsset)) {
if (!bundle.assets.has(inlineConstant)) {
bundle.assets.add(inlineConstant);
bundle.size += inlineConstant.stats.size;
}
}
}
// Step Insert Or Share: Place all assets into bundles or create shared bundles. Each asset
// is placed into a single bundle based on the bundle entries it is reachable from.
// This creates a maximally code split bundle graph with no duplication.
let reachable = new (_graph().BitSet)(assets.length);
let reachableNonEntries = new (_graph().BitSet)(assets.length);
let reachableIntersection = new (_graph().BitSet)(assets.length);
for (let i = 0; i < assets.length; i++) {
let asset = assets[i];
let manualSharedObject = manualAssetToConfig.get(asset);
if (bundleRoots.has(asset) && inlineConstantDeps.get(asset).size > 0) {
let entryBundleId = (0, _nullthrows().default)(bundleRoots.get(asset))[0];
let entryBundle = (0, _nullthrows().default)(bundleGraph.getNode(entryBundleId));
(0, _assert().default)(entryBundle !== 'root');
assignInlineConstants(asset, entryBundle);
}
if (asset.meta.isConstantModule === true) {
// Ignore constant modules as they are placed with their direct parents
continue;
}
// Unreliable bundleRoot assets which need to pulled in by shared bundles or other means.
// Filter out entries, since they can't have shared bundles.
// Neither can non-splittable, isolated, or needing of stable name bundles.
// Reserve those filtered out bundles since we add the asset back into them.
reachableNonEntries.clear();
reachableRoots[i].forEach(nodeId => {
var _ancestorAssets$nodeI;
let assetId = bundleRootGraph.getNode(nodeId);
if (assetId == null) return; // deleted
let a = assets[assetId];
if (entries.has(a) || !a.isBundleSplittable || bundleRoots.get(a) && (getBundleFromBundleRoot(a).needsStableName || getBundleFromBundleRoot(a).bundleBehavior === 'isolated')) {
// Add asset to non-splittable bundles.
addAssetToBundleRoot(asset, a);
} else if (!((_ancestorAssets$nodeI = ancestorAssets[nodeId]) !== null && _ancestorAssets$nodeI !== void 0 && _ancestorAssets$nodeI.has(i))) {
// Filter out bundles from this asset's reachable array if
// bundle does not contain the asset in its ancestry
reachableNonEntries.add(assetId);
}
});
reachable.bits.set(reachableNonEntries.bits);
// If we encounter a "manual" asset, draw an edge from reachable to its MSB
if (manualSharedObject && !reachable.empty()) {
let bundle;
let bundleId;
let manualSharedBundleKey = manualSharedObject.name + ',' + asset.type;
let sourceBundles = [];
reachable.forEach(id => {
sourceBundles.push((0, _nullthrows().default)(bundleRoots.get(assets[id]))[0]);
});
if (!manualSharedMap.has(manualSharedBundleKey)) {
let firstSourceBundle = (0, _nullthrows().default)(bundleGraph.getNode(sourceBundles[0]));
(0, _assert().default)(firstSourceBundle !== 'root');
bundle = createBundle({
uniqueKey: manualSharedBundleKey,
target: firstSourceBundle.target,
type: asset.type,
env: firstSourceBundle.env,
manualSharedBundle: manualSharedObject === null || manualSharedObject === void 0 ? void 0 : manualSharedObject.name
});
bundle.sourceBundles = new Set(sourceBundles);
bundle.assets.add(asset);
bundleId = bundleGraph.addNode(bundle);
manualSharedMap.set(manualSharedBundleKey, bundleId);
} else {
bundleId = (0, _nullthrows().default)(manualSharedMap.get(manualSharedBundleKey));
bundle = (0, _nullthrows().default)(bundleGraph.getNode(bundleId));
(0, _assert().default)(bundle != null && bundle !== 'root', 'We tried to use the root incorrectly');
if (!bundle.assets.has(asset)) {
bundle.assets.add(asset);
bundle.size += asset.stats.size;
}
for (let s of sourceBundles) {
if (s != bundleId) {
bundle.sourceBundles.add(s);
}
}
}
for (let sourceBundleId of sourceBundles) {
if (bundleId !== sourceBundleId) {
bundleGraph.addEdge(sourceBundleId, bundleId);
}
}
dependencyBundleGraph.addNodeByContentKeyIfNeeded(String(bundleId), {
value: bundle,
type: 'bundle'
});
continue;
}
// Finally, filter out bundleRoots (bundles) from this assets
// reachable if they are subgraphs, and reuse that subgraph bundle
// by drawing an edge. Essentially, if two bundles within an asset's
// reachable array, have an ancestor-subgraph relationship, draw that edge.
// This allows for us to reuse a bundle instead of making a shared bundle if
// a bundle represents the exact set of assets a set of bundles would share
// if a bundle b is a subgraph of another bundle f, reuse it, drawing an edge between the two
if (config.disableSharedBundles === false) {
reachableNonEntries.forEach(candidateId => {
let candidateSourceBundleRoot = assets[candidateId];
let candidateSourceBundleId = (0, _nullthrows().default)(bundleRoots.get(candidateSourceBundleRoot))[0];
if (candidateSourceBundleRoot.env.isIsolated()) {
return;
}
let reuseableBundleId = bundles.get(asset.id);
if (reuseableBundleId != null) {
reachable.delete(candidateId);
bundleGraph.addEdge(candidateSourceBundleId, reuseableBundleId);
let reusableBundle = bundleGraph.getNode(reuseableBundleId);
(0, _assert().default)(reusableBundle !== 'root' && reusableBundle != null);
reusableBundle.sourceBundles.add(candidateSourceBundleId);
} else {
// Asset is not a bundleRoot, but if its ancestor bundle (in the asset's reachable) can be
// reused as a subgraph of another bundleRoot in its reachable, reuse it
reachableIntersection.bits.set(reachableNonEntries.bits);
reachableIntersection.intersect(reachableAssets[(0, _nullthrows().default)(assetToBundleRootNodeId.get(candidateSourceBundleRoot))]);
reachableIntersection.forEach(otherCandidateId => {
let otherReuseCandidate = assets[otherCandidateId];
if (candidateSourceBundleRoot === otherReuseCandidate) return;
let reusableBundleId = (0, _nullthrows().default)(bundles.get(otherReuseCandidate.id));
reachable.delete(candidateId);
bundleGraph.addEdge((0, _nullthrows().default)(bundles.get(candidateSourceBundleRoot.id)), reusableBundleId);
let reusableBundle = bundleGraph.getNode(reusableBundleId);
(0, _assert().default)(reusableBundle !== 'root' && reusableBundle != null);
reusableBundle.sourceBundles.add(candidateSourceBundleId);
});
}
});
}
let reachableArray = [];
reachable.forEach(id => {
reachableArray.push(assets[id]);
});
// Create shared bundles for splittable bundles.
if (config.disableSharedBundles === false && reachableArray.length > config.minBundles) {
let sourceBundles = reachableArray.map(a => (0, _nullthrows().default)(bundleRoots.get(a))[0]);
let key = reachableArray.map(a => a.id).join(',') + '.' + asset.type;
let bundleId = bundles.get(key);
let bundle;
if (bundleId == null) {
let firstSourceBundle = (0, _nullthrows().default)(bundleGraph.getNode(sourceBundles[0]));
(0, _assert().default)(firstSourceBundle !== 'root');
bundle = createBundle({
target: firstSourceBundle.target,
type: asset.type,
env: firstSourceBundle.env
});
bundle.sourceBundles = new Set(sourceBundles);
let sharedInternalizedAssets = firstSourceBundle.internalizedAssets ? firstSourceBundle.internalizedAssets.clone() : new (_graph().BitSet)(assets.length);
for (let p of sourceBundles) {
let parentBundle = (0, _nullthrows().default)(bundleGraph.getNode(p));
(0, _assert().default)(parentBundle !== 'root');
if (parentBundle === firstSourceBundle) continue;
if (parentBundle.internalizedAssets) {
sharedInternalizedAssets.intersect(parentBundle.internalizedAssets);
} else {
sharedInternalizedAssets.clear();
}
}
bundle.internalizedAssets = sharedInternalizedAssets;
bundleId = bundleGraph.addNode(bundle);
bundles.set(key, bundleId);
} else {
bundle = (0, _nullthrows().default)(bundleGraph.getNode(bundleId));
(0, _assert().default)(bundle !== 'root');
}
bundle.assets.add(asset);
bundle.size += asset.stats.size;
assignInlineConstants(asset, bundle);
for (let sourceBundleId of sourceBundles) {
if (bundleId !== sourceBundleId) {
bundleGraph.addEdge(sourceBundleId, bundleId);
}
}
dependencyBundleGraph.addNodeByContentKeyIfNeeded(String(bundleId), {
value: bundle,
type: 'bundle'
});
} else if (config.disableSharedBundles === true || reachableArray.length <= config.minBundles) {
for (let root of reachableArray) {
addAssetToBundleRoot(asset, root);
}
}
}
let manualSharedBundleIds = new Set([...manualSharedMap.values()]);
// Step split manual shared bundles for those that have the "split" property set
let remainderMap = new (_utils().DefaultMap)(() => []);
for (let id of manualSharedMap.values()) {
let manualBundle = bundleGraph.getNode(id);
(0, _assert().default)(manualBundle !== 'root' && manualBundle != null);
if (manualBundle.sourceBundles.size > 0) {
var _manualAssetToConfig$;
let firstSourceBundle = (0, _nullthrows().default)(bundleGraph.getNode([...manualBundle.sourceBundles][0]));
(0, _assert().default)(firstSourceBundle !== 'root');
let firstAsset = [...manualBundle.assets][0];
let manualSharedObject = manualAssetToConfig.get(firstAsset);
(0, _assert().default)(manualSharedObject != null);
let modNum = (_manualAssetToConfig$ = manualAssetToConfig.get(firstAsset)) === null || _manualAssetToConfig$ === void 0 ? void 0 : _manualAssetToConfig$.split;
if (modNum != null) {
for (let a of [...manualBundle.assets]) {
let numRep = getBigIntFromContentKey(a.id);
// $FlowFixMe Flow doesn't know about BigInt
let r = Number(numRep % BigInt(modNum));
remainderMap.get(r).push(a);
}
for (let i = 1; i < [...remainderMap.keys()].length; i++) {
let bundle = createBundle({
uniqueKey: manualSharedObject.name + firstSourceBundle.type + i,
target: firstSourceBundle.target,
type: firstSourceBundle.type,
env: firstSourceBundle.env,
manualSharedBundle: manualSharedObject.name
});
bundle.sourceBundles = manualBundle.sourceBundles;
bundle.internalizedAssets = manualBundle.internalizedAssets;
let bundleId = bundleGraph.addNode(bundle);
manualSharedBundleIds.add(bundleId);
for (let sourceBundleId of manualBundle.sourceBundles) {
if (bundleId !== sourceBundleId) {
bundleGraph.addEdge(sourceBundleId, bundleId);
}
}
for (let sp of remainderMap.get(i)) {
bundle.assets.add(sp);
bundle.size += sp.stats.size;
manualBundle.assets.delete(sp);
manualBundle.size -= sp.stats.size;
}
}
}
}
}
// Step insert constant modules into manual shared bundles.
// We have to do this separately as they're the only case where a single asset can
// match multiple MSB's
for (let [asset, msbs] of constantModuleToMSB.entries()) {
for (let manualSharedObject of msbs) {
let bundleId = manualSharedMap.get(manualSharedObject.name + ',js');
if (bundleId == null) continue;
let bundle = (0, _nullthrows().default)(bundleGraph.getNode(bundleId));
(0, _assert().default)(bundle != null && bundle !== 'root', 'We tried to use the root incorrectly');
if (!bundle.assets.has(asset)) {
bundle.assets.add(asset);
bundle.size += asset.stats.size;
}
}
}
// Step Merge Share Bundles: Merge any shared bundles under the minimum bundle size back into
// their source bundles, and remove the bundle.
// We should include "bundle reuse" as shared bundles that may be removed but the bundle itself would have to be retained
for (let [bundleNodeId, bundle] of bundleGraph.nodes.entries()) {
if (!bundle || bundle === 'root') continue;
if (bundle.sourceBundles.size > 0 && bundle.mainEntryAsset == null && bundle.size < config.minBundleSize && !manualSharedBundleIds.has(bundleNodeId)) {
removeBundle(bundleGraph, bundleNodeId, assetReference);
}
}
let modifiedSourceBundles = new Set();
// Step Remove Shared Bundles: Remove shared bundles from bundle groups that hit the parallel request limit.
if (config.disableSharedBundles === false) {
for (let bundleGroupId of bundleGraph.getNodeIdsConnectedFrom(rootNodeId)) {
// Find shared bundles in this bundle group.
let bundleId = bundleGroupId;
// We should include "bundle reuse" as shared bundles that may be removed but the bundle itself would have to be retained
let bundleIdsInGroup = getBundlesForBundleGroup(bundleId); //get all bundlegrups this bundle is an ancestor of
// Filter out inline assests as they should not contribute to PRL
let numBundlesContributingToPRL = bundleIdsInGroup.reduce((count, b) => {
let bundle = (0, _nullthrows().default)(bundleGraph.getNode(b));
(0, _assert().default)(bundle !== 'root');
return count + (bundle.bundleBehavior !== 'inline');
}, 0);
if (numBundlesContributingToPRL > config.maxParallelRequests) {
let sharedBundleIdsInBundleGroup = bundleIdsInGroup.filter(b => {
let bundle = (0, _nullthrows().default)(bundleGraph.getNode(b));
// shared bundles must have source bundles, we could have a bundle
// connected to another bundle that isnt a shared bundle, so check
return bundle !== 'root' && bundle.sourceBundles.size > 0 && bundleId != b && !manualSharedBundleIds.has(b);
});
// Sort the bundles so the smallest ones are removed first.
let sharedBundlesInGroup = sharedBundleIdsInBundleGroup.map(id => ({
id,
bundle: (0, _nullthrows().default)(bundleGraph.getNode(id))
})).map(({
id,
bundle
}) => {
// For Flow
(0, _assert().default)(bundle !== 'root');
return {
id,
bundle
};
}).sort((a, b) => b.bundle.size - a.bundle.size);
// Remove bundles until the bundle group is within the parallel request limit.
while (sharedBundlesInGroup.length > 0 && numBundlesContributingToPRL > config.maxParallelRequests) {
let bundleTuple = sharedBundlesInGroup.pop();
let bundleToRemove = bundleTuple.bundle;
let bundleIdToRemove = bundleTuple.id;
//TODO add integration test where bundles in bunlde group > max parallel request limit & only remove a couple shared bundles
// but total # bundles still exceeds limit due to non shared bundles
// Add all assets in the shared bundle into the source bundles that are within this bundle group.
let sourceBundles = [...bundleToRemove.sourceBundles].filter(b => bundleIdsInGroup.includes(b));
for (let sourceBundleId of sourceBundles) {
let sourceBundle = (0, _nullthrows().default)(bundleGraph.getNode(sourceBundleId));
(0, _assert().default)(sourceBundle !== 'root');
modifiedSourceBundles.add(sourceBundle);
bundleToRemove.sourceBundles.delete(sourceBundleId);
for (let asset of bundleToRemove.assets) {
addAssetToBundleRoot(asset, (0, _nullthrows().default)(sourceBundle.mainEntryAsset));
}
//This case is specific to reused bundles, which can have shared bundles attached to it
for (let childId of bundleGraph.getNodeIdsConnectedFrom(bundleIdToRemove)) {
let child = bundleGraph.getNode(childId);
(0, _assert().default)(child !== 'root' && child != null);
child.sourceBundles.add(sourceBundleId);
bundleGraph.addEdge(sourceBundleId, childId);
}
// needs to add test case where shared bundle is removed from ONE bundlegroup but not from the whole graph!
// Remove the edge from this bundle group to the shared bundle.
// If there is now only a single bundle group that contains this bundle,
// merge it into the remaining source bundles. If it is orphaned entirely, remove it.
let incomingNodeCount = bundleGraph.getNodeIdsConnectedTo(bundleIdToRemove).length;
if (incomingNodeCount <= 2 &&
//Never fully remove reused bundles
bundleToRemove.mainEntryAsset == null) {
// If one bundle group removes a shared bundle, but the other *can* keep it, still remove because that shared bundle is pointless (only one source bundle)
removeBundle(bundleGraph, bundleIdToRemove, assetReference);
// Stop iterating through bundleToRemove's sourceBundles as the bundle has been removed.
break;
} else {
bundleGraph.removeEdge(sourceBundleId, bundleIdToRemove);
}
}
numBundlesContributingToPRL--;
}
}
}
}
function getBigIntFromContentKey(contentKey) {
let b = Buffer.alloc(64);
b.write(contentKey);
// $FlowFixMe Flow doesn't have BigInt types in this version
return b.readBigInt64BE();
}
// Fix asset order in source bundles as they are likely now incorrect after shared bundle deletion
if (modifiedSourceBundles.size > 0) {
let assetOrderMap = new Map(assets.map((a, index) => [a, index]));
for (let bundle of modifiedSourceBundles) {
bundle.assets = new Set([...bundle.assets].sort((a, b) => {
let aIndex = (0, _nullthrows().default)(assetOrderMap.get(a));
let bIndex = (0, _nullthrows().default)(assetOrderMap.get(b));
return aIndex - bIndex;
}));
}
}
function deleteBundle(bundleRoot) {
bundleGraph.removeNode((0, _nullthrows().default)(bundles.get(bundleRoot.id)));
bundleRoots.delete(bundleRoot);
bundles.delete(bundleRoot.id);
let bundleRootId = assetToBundleRootNodeId.get(bundleRoot);
if (bundleRootId != null && bundleRootGraph.hasNode(bundleRootId)) {
bundleRootGraph.removeNode(bundleRootId);
}
}
function getBundlesForBundleGroup(bundleGroupId) {
let bundlesInABundleGroup = [];
bundleGraph.traverse(nodeId => {
bundlesInABundleGroup.push(nodeId);
}, bundleGroupId);
return bundlesInABundleGroup;
}
function getBundleFromBundleRoot(bundleRoot) {
let bundle = bundleGraph.getNode((0, _nullthrows().default)(bundleRoots.get(bundleRoot))[0]);
(0, _assert().default)(bundle !== 'root' && bundle != null);
return bundle;
}
function addAssetToBundleRoot(asset, bundleRoot) {
let [bundleId, bundleGroupId] = (0, _nullthrows().default)(bundleRoots.get(bundleRoot));
let bundle = (0, _nullthrows().default)(bundleGraph.getNode(bundleId));
(0, _assert().default)(bundle !== 'root');
if (asset.type !== bundle.type) {
let bundleGroup = (0, _nullthrows().default)(bundleGraph.getNode(bundleGroupId));
(0, _assert().default)(bundleGroup !== 'root');
let key = (0, _nullthrows().default)(bundleGroup.mainEntryAsset).id + '.' + asset.type;
let typeChangeBundleId = bundles.get(key);
if (typeChangeBundleId == null) {
let typeChangeBundle = createBundle({
uniqueKey: key,
needsStableName: bundle.needsStableName,
bundleBehavior: bundle.bundleBehavior,
type: asset.type,
target: bundle.target,
env: bundle.env
});
typeChangeBundleId = bundleGraph.addNode(typeChangeBundle);
bundleGraph.addEdge(bundleId, typeChangeBundleId);
bundles.set(key, typeChangeBundleId);
bundle = typeChangeBundle;
} else {
bundle = (0, _nullthrows().default)(bundleGraph.getNode(typeChangeBundleId));
(0, _assert().default)(bundle !== 'root');
}
}
bundle.assets.add(asset);
bundle.size += asset.stats.size;
assignInlineConstants(asset, bundle);
}
function removeBundle(bundleGraph, bundleId, assetReference) {
let bundle = (0, _nullthrows().default)(bundleGraph.getNode(bundleId));
(0, _assert().default)(bundle !== 'root');
for (let asset of bundle.assets) {
assetReference.set(asset, assetReference.get(asset).filter(t => !t.includes(bundle)));
for (let sourceBundleId of bundle.sourceBundles) {
let sourceBundle = (0, _nullthrows().default)(bundleGraph.getNode(sourceBundleId));
(0, _assert().default)(sourceBundle !== 'root');
addAssetToBundleRoot(asset, (0, _nullthrows().default)(sourceBundle.mainEntryAsset));
}
}
bundleGraph.removeNode(bundleId);
}
return {
assets,
bundleGraph,
dependencyBundleGraph,
bundleGroupBundleIds,
assetReference,
manualAssetToBundle
};
}
const CONFIG_SCHEMA = {
type: 'object',
properties: {
http: {
type: 'number',
enum: Object.keys(HTTP_OPTIONS).map(k => Number(k))
},
manualSharedBundles: {
type: 'array',
items: {
type: 'object',
properties: {
name: {
type: 'string'
},
assets: {
type: 'array',
items: {
type: 'string'
}
},
types: {
type: 'array',
items: {
type: 'string'
}
},
root: {
type: 'string'
},
split: {
type: 'number'
}
},
required: ['name', 'assets'],
additionalProperties: false
}
},
minBundles: {
type: 'number'
},
minBundleSize: {
type: 'number'
},
maxParallelRequests: {
type: 'number'
},
disableSharedBundles: {
type: 'boolean'
}
},
additionalProperties: false
};
function createBundle(opts) {
var _opts$type, _opts$env, _opts$bundleBehavior;
if (opts.asset == null) {
return {
uniqueKey: opts.uniqueKey,
assets: new Set(),
mainEntryAsset: null,
size: 0,
sourceBundles: new Set(),
target: opts.target,
type: (0, _nullthrows().default)(opts.type),
env: (0, _nullthrows().default)(opts.env),
needsStableName: Boolean(opts.needsStableName),
bundleBehavior: opts.bundleBehavior,
manualSharedBundle: opts.manualSharedBundle
};
}
let asset = (0, _nullthrows().default)(opts.asset);
return {
uniqueKey: opts.uniqueKey,
assets: new Set([asset]),
mainEntryAsset: asset,
size: asset.stats.size,
sourceBundles: new Set(),
target: opts.target,
type: (_opts$type = opts.type) !== null && _opts$type !== void 0 ? _opts$type : asset.type,
env: (_opts$env = opts.env) !== null && _opts$env !== void 0 ? _opts$env : asset.env,
needsStableName: Boolean(opts.needsStableName),
bundleBehavior: (_opts$bundleBehavior = opts.bundleBehavior) !== null && _opts$bundleBehavior !== void 0 ? _opts$bundleBehavior : asset.bundleBehavior,
manualSharedBundle: opts.manualSharedBundle
};
}
function resolveModeConfig(config, mode) {
let generalConfig = {};
let modeConfig = {};
for (const key of Object.keys(config)) {
if (key === 'development' || key === 'production') {
if (key === mode) {
modeConfig = config[key];
}
} else {
generalConfig[key] = config[key];
}
}
// $FlowFixMe Not sure how to convince flow here...
return {
...generalConfig,
...modeConfig
};
}
async function loadBundlerConfig(config, options, logger) {
var _modeConfig$http, _modeConfig$minBundle, _modeConfig$minBundle2, _modeConfig$maxParall, _modeConfig$disableSh, _modeConfig$manualSha;
let conf = await config.getConfig([], {
packageKey: '@parcel/bundler-default'
});
if (!conf) {
const modDefault = {
...HTTP_OPTIONS['2'],
projectRoot: options.projectRoot
};
return modDefault;
}
(0, _assert().default)((conf === null || conf === void 0 ? void 0 : conf.contents) != null);
let modeConfig = resolveModeConfig(conf.contents, options.mode);
// minBundles will be ignored if shared bundles are disabled
if (modeConfig.minBundles != null && modeConfig.disableSharedBundles === true) {
logger.warn({
origin: '@parcel/bundler-default',
message: `The value of "${modeConfig.minBundles}" set for minBundles will not be used as shared bundles have been disabled`
});
}
// minBundleSize will be ignored if shared bundles are disabled
if (modeConfig.minBundleSize != null && modeConfig.disableSharedBundles === true) {
logger.warn({
origin: '@parcel/bundler-default',
message: `The value of "${modeConfig.minBundleSize}" set for minBundleSize will not be used as shared bundles have been disabled`
});
}
// maxParallelRequests will be ignored if shared bundles are disabled
if (modeConfig.maxParallelRequests != null && modeConfig.disableSharedBundles === true) {
logger.warn({
origin: '@parcel/bundler-default',
message: `The value of "${modeConfig.maxParallelRequests}" set for maxParallelRequests will not be used as shared bundles have been disabled`
});
}
if (modeConfig.manualSharedBundles) {
let nameArray = modeConfig.manualSharedBundles.map(a => a.name);
let nameSet = new Set(nameArray);
(0, _assert().default)(nameSet.size == nameArray.length, 'The name field must be unique for property manualSharedBundles');
}
_utils().validateSchema.diagnostic(CONFIG_SCHEMA, {
data: modeConfig,
source: await options.inputFS.readFile(conf.filePath, 'utf8'),
filePath: conf.filePath,
prependKey: `/${(0, _diagnostic().encodeJSONKeyComponent)('@parcel/bundler-default')}`
}, '@parcel/bundler-default', 'Invalid config for @parcel/bundler-default');
let http = (_modeConfig$http = modeConfig.http) !== null && _modeConfig$http !== void 0 ? _modeConfig$http : 2;
let defaults = HTTP_OPTIONS[http];
return {
minBundles: (_modeConfig$minBundle = modeConfig.minBundles) !== null && _modeConfig$minBundle !== void 0 ? _modeConfig$minBundle : defaults.minBundles,
minBundleSize: (_modeConfig$minBundle2 = modeConfig.minBundleSize) !== null && _modeConfig$minBundle2 !== void 0 ? _modeConfig$minBundle2 : defaults.minBundleSize,
maxParallelRequests: (_modeConfig$maxParall = modeConfig.maxParallelRequests) !== null && _modeConfig$maxParall !== void 0 ? _modeConfig$maxParall : defaults.maxParallelRequests,
projectRoot: options.projectRoot,
disableSharedBundles: (_modeConfig$disableSh = modeConfig.disableSharedBundles) !== null && _modeConfig$disableSh !== void 0 ? _modeConfig$disableSh : defaults.disableSharedBundles,
manualSharedBundles: (_modeConfig$manualSha = modeConfig.manualSharedBundles) !== null && _modeConfig$manualSha !== void 0 ? _modeConfig$manualSha : defaults.manualSharedBundles
};
}
function getEntryByTarget(bundleGraph) {
// Find entries from assetGraph per target
let targets = new (_utils().DefaultMap)(() => new Map());
bundleGraph.traverse({
enter(node, context, actions) {
if (node.type !== 'asset') {
return node;
}
(0, _assert().default)(context != null && context.type === 'dependency' && context.value.isEntry && context.value.target != null);
targets.get(context.value.target.distDir).set(node.value, context.value);
actions.skipChildren();
return node;
}
});
return targets;
}