@parcel/core
Advanced tools
Comparing version 2.0.0-nightly.255 to 2.0.0-nightly.256
@@ -37,8 +37,7 @@ "use strict"; | ||
function nodeFromAssetGroup(assetGroup, deferred = false) { | ||
function nodeFromAssetGroup(assetGroup) { | ||
return { | ||
id: (0, _utils.md5FromObject)(assetGroup), | ||
type: 'asset_group', | ||
value: assetGroup, | ||
deferred | ||
value: assetGroup | ||
}; | ||
@@ -69,7 +68,4 @@ } | ||
}; | ||
} // Types that are considered incomplete when they don't have a child node | ||
} | ||
const INCOMPLETE_TYPES = ['entry_specifier', 'entry_file', 'dependency', 'asset_group']; | ||
class AssetGraph extends _Graph.default { | ||
@@ -79,10 +75,4 @@ constructor(...args) { | ||
_defineProperty(this, "onNodeAdded", void 0); | ||
_defineProperty(this, "onNodeRemoved", void 0); | ||
_defineProperty(this, "onIncompleteNode", void 0); | ||
_defineProperty(this, "incompleteNodeIds", new Set()); | ||
_defineProperty(this, "hash", void 0); | ||
@@ -96,3 +86,2 @@ } | ||
res.incompleteNodeIds = opts.incompleteNodeIds; | ||
res.hash = opts.hash; | ||
@@ -106,3 +95,2 @@ return res; | ||
return { ...super.serialize(), | ||
incompleteNodeIds: this.incompleteNodeIds, | ||
hash: this.hash | ||
@@ -113,9 +101,5 @@ }; | ||
initOptions({ | ||
onNodeAdded, | ||
onNodeRemoved, | ||
onIncompleteNode | ||
onNodeRemoved | ||
} = {}) { | ||
this.onNodeAdded = onNodeAdded; | ||
this.onNodeRemoved = onNodeRemoved; | ||
this.onIncompleteNode = onIncompleteNode; | ||
} | ||
@@ -149,9 +133,2 @@ | ||
this.hash = null; | ||
let existingNode = this.getNode(node.id); | ||
if (INCOMPLETE_TYPES.includes(node.type) && !node.complete && !node.deferred && (!existingNode || existingNode.deferred)) { | ||
this.markIncomplete(node); | ||
} | ||
this.onNodeAdded && this.onNodeAdded(node); | ||
return super.addNode(node); | ||
@@ -162,3 +139,2 @@ } | ||
this.hash = null; | ||
this.incompleteNodeIds.delete(node.id); | ||
this.onNodeRemoved && this.onNodeRemoved(node); | ||
@@ -168,22 +144,11 @@ return super.removeNode(node); | ||
markIncomplete(node) { | ||
this.incompleteNodeIds.add(node.id); | ||
if (this.onIncompleteNode) { | ||
this.onIncompleteNode(node); | ||
} | ||
} | ||
hasIncompleteNodes() { | ||
return this.incompleteNodeIds.size > 0; | ||
} | ||
resolveEntry(entry, resolved) { | ||
let entrySpecifierNode = nodeFromEntrySpecifier(entry); | ||
resolveEntry(entry, resolved, correspondingRequest) { | ||
let entrySpecifierNode = (0, _nullthrows.default)(this.getNode(nodeFromEntrySpecifier(entry).id)); | ||
(0, _assert.default)(entrySpecifierNode.type === 'entry_specifier'); | ||
entrySpecifierNode.correspondingRequest = correspondingRequest; | ||
let entryFileNodes = resolved.map(file => nodeFromEntryFile(file)); | ||
this.replaceNodesConnectedTo(entrySpecifierNode, entryFileNodes); | ||
this.incompleteNodeIds.delete(entrySpecifierNode.id); | ||
} | ||
resolveTargets(entry, targets) { | ||
resolveTargets(entry, targets, correspondingRequest) { | ||
let depNodes = targets.map(target => nodeFromDep((0, _Dependency.createDependency)({ | ||
@@ -196,28 +161,124 @@ moduleSpecifier: entry.filePath, | ||
}))); | ||
let entryNode = nodeFromEntryFile(entry); | ||
let entryNode = (0, _nullthrows.default)(this.getNode(nodeFromEntryFile(entry).id)); | ||
(0, _assert.default)(entryNode.type === 'entry_file'); | ||
entryNode.correspondingRequest = correspondingRequest; | ||
if (this.hasNode(entryNode.id)) { | ||
this.replaceNodesConnectedTo(entryNode, depNodes); | ||
this.incompleteNodeIds.delete(entryNode.id); | ||
} | ||
} | ||
resolveDependency(dependency, assetGroupNode) { | ||
let depNode = this.nodes.get(dependency.id); | ||
resolveDependency(dependency, assetGroup, correspondingRequest) { | ||
let depNode = (0, _nullthrows.default)(this.nodes.get(dependency.id)); | ||
(0, _assert.default)(depNode.type === 'dependency'); | ||
if (!depNode) return; | ||
this.incompleteNodeIds.delete(depNode.id); | ||
depNode.correspondingRequest = correspondingRequest; | ||
if (assetGroupNode) { | ||
this.replaceNodesConnectedTo(depNode, [assetGroupNode]); | ||
if (!assetGroup) { | ||
return; | ||
} | ||
let assetGroupNode = nodeFromAssetGroup(assetGroup); | ||
let existingAssetGroupNode = this.getNode(assetGroupNode.id); | ||
this.replaceNodesConnectedTo(depNode, [existingAssetGroupNode !== null && existingAssetGroupNode !== void 0 ? existingAssetGroupNode : assetGroupNode]); | ||
} | ||
resolveAssetGroup(assetGroup, assets) { | ||
shouldVisitChild(node, childNode) { | ||
if (node.type !== 'dependency' || childNode.type !== 'asset_group' || childNode.deferred === false) { | ||
return true; | ||
} | ||
let sideEffects = childNode.value.sideEffects; | ||
let dependency = node.value; | ||
let previouslyDeferred = childNode.deferred; | ||
let defer = this.shouldDeferDependency(dependency, sideEffects); | ||
dependency.isDeferred = defer; | ||
node.hasDeferred = defer; | ||
childNode.deferred = defer; | ||
if (!previouslyDeferred && defer) { | ||
this.markParentsWithHasDeferred(node); | ||
} else if (previouslyDeferred && !defer) { | ||
this.unmarkParentsWithHasDeferred(node); | ||
} | ||
return !defer; | ||
} | ||
markParentsWithHasDeferred(node) { | ||
this.traverseAncestors(node, (_node, _, actions) => { | ||
if (_node.type === 'asset') { | ||
_node.hasDeferred = true; | ||
} else if (_node.type === 'asset_group') { | ||
_node.hasDeferred = true; | ||
actions.skipChildren(); | ||
} else if (node !== _node) { | ||
actions.skipChildren(); | ||
} | ||
}); | ||
} | ||
unmarkParentsWithHasDeferred(node) { | ||
this.traverseAncestors(node, (_node, ctx, actions) => { | ||
if (_node.type === 'asset') { | ||
let hasDeferred = this.getNodesConnectedFrom(_node).some(_childNode => _childNode.hasDeferred == null ? false : _childNode.hasDeferred); | ||
if (!hasDeferred) { | ||
delete _node.hasDeferred; | ||
} | ||
return { | ||
hasDeferred | ||
}; | ||
} else if (_node.type === 'asset_group') { | ||
if (!(ctx === null || ctx === void 0 ? void 0 : ctx.hasDeferred)) { | ||
delete _node.hasDeferred; | ||
} | ||
actions.skipChildren(); | ||
} else if (node !== _node) { | ||
actions.skipChildren(); | ||
} | ||
}); | ||
} // Defer transforming this dependency if it is marked as weak, there are no side effects, | ||
// no re-exported symbols are used by ancestor dependencies and the re-exporting asset isn't | ||
// using a wildcard and isn't an entry (in library mode). | ||
// This helps with performance building large libraries like `lodash-es`, which re-exports | ||
// a huge number of functions since we can avoid even transforming the files that aren't used. | ||
shouldDeferDependency(dependency, sideEffects) { | ||
let defer = false; | ||
if (dependency.isWeak && sideEffects === false && !dependency.symbols.has('*')) { | ||
let depNode = this.getNode(dependency.id); | ||
(0, _assert.default)(depNode); | ||
let assets = this.getNodesConnectedTo(depNode); | ||
let symbols = new Map([...dependency.symbols].map(([key, val]) => [val.local, key])); | ||
(0, _assert.default)(assets.length === 1); | ||
let firstAsset = assets[0]; | ||
(0, _assert.default)(firstAsset.type === 'asset'); | ||
let resolvedAsset = firstAsset.value; | ||
let deps = this.getIncomingDependencies(resolvedAsset); | ||
defer = deps.every(d => !(d.env.isLibrary && d.isEntry) && !d.symbols.has('*') && ![...d.symbols.keys()].some(symbol => { | ||
var _resolvedAsset$symbol, _resolvedAsset$symbol2; | ||
let assetSymbol = (_resolvedAsset$symbol = resolvedAsset.symbols) === null || _resolvedAsset$symbol === void 0 ? void 0 : (_resolvedAsset$symbol2 = _resolvedAsset$symbol.get(symbol)) === null || _resolvedAsset$symbol2 === void 0 ? void 0 : _resolvedAsset$symbol2.local; | ||
return assetSymbol != null && symbols.has(assetSymbol); | ||
})); | ||
} | ||
return defer; | ||
} | ||
resolveAssetGroup(assetGroup, assets, correspondingRequest) { | ||
let assetGroupNode = nodeFromAssetGroup(assetGroup); | ||
this.incompleteNodeIds.delete(assetGroupNode.id); | ||
assetGroupNode = this.getNode(assetGroupNode.id); | ||
if (!this.hasNode(assetGroupNode.id)) { | ||
if (!assetGroupNode) { | ||
return; | ||
} | ||
(0, _assert.default)(assetGroupNode.type === 'asset_group'); | ||
assetGroupNode.correspondingRequest = correspondingRequest; | ||
let dependentAssetKeys = []; | ||
@@ -224,0 +285,0 @@ let assetObjects = []; |
@@ -12,2 +12,4 @@ "use strict"; | ||
var _assert = _interopRequireDefault(require("assert")); | ||
var _path = _interopRequireDefault(require("path")); | ||
@@ -49,4 +51,2 @@ | ||
const requestPriorities = [['entry_request'], ['target_request'], ['dep_path_request', 'asset_request']]; | ||
class AssetGraphBuilder extends _events.default { | ||
@@ -94,2 +94,6 @@ constructor(...args) { | ||
_defineProperty(this, "entries", void 0); | ||
_defineProperty(this, "initialAssetGroups", void 0); | ||
_defineProperty(this, "handle", void 0); | ||
@@ -108,2 +112,4 @@ } | ||
this.optionsRef = optionsRef; | ||
this.entries = entries; | ||
this.initialAssetGroups = assetRequests; | ||
this.workerFarm = workerFarm; | ||
@@ -144,4 +150,3 @@ this.assetRequests = []; // TODO: changing these should not throw away the entire graph. | ||
this.assetGraph.initOptions({ | ||
onNodeRemoved: node => this.handleNodeRemovedFromAssetGraph(node), | ||
onIncompleteNode: node => this.handleIncompleteNode(node) | ||
onNodeRemoved: node => this.handleNodeRemovedFromAssetGraph(node) | ||
}); | ||
@@ -215,36 +220,33 @@ let assetGraph = this.assetGraph; | ||
this.rejected = new Map(); | ||
let lastQueueError; | ||
let root = this.assetGraph.getRootNode(); | ||
for (let currPriorities of requestPriorities) { | ||
if (!this.requestTracker.hasInvalidRequests()) { | ||
break; | ||
} | ||
if (!root) { | ||
throw new Error('A root node is required to traverse'); | ||
} | ||
let promises = []; | ||
let visited = new Set([root.id]); | ||
for (let request of this.requestTracker.getInvalidRequests()) { | ||
const visit = node => { | ||
let request = this.getCorrespondingRequest(node); | ||
if (!node.complete && !node.deferred && request != null && !this.requestTracker.hasValidResult((0, _nullthrows.default)(request).id)) { | ||
// $FlowFixMe | ||
if (currPriorities.includes(request.type)) { | ||
promises.push(this.queueRequest(request, { | ||
signal | ||
})); | ||
} | ||
this.queueRequest(request, { | ||
signal | ||
}).then(() => visitChildren(node)); | ||
} else { | ||
visitChildren(node); | ||
} | ||
}; | ||
if (lastQueueError) { | ||
throw lastQueueError; | ||
const visitChildren = node => { | ||
for (let child of this.assetGraph.getNodesConnectedFrom(node)) { | ||
if ((!visited.has(child.id) || child.hasDeferred) && this.assetGraph.shouldVisitChild(node, child)) { | ||
visited.add(child.id); | ||
visit(child); | ||
} | ||
} | ||
}; | ||
this.queue.run().catch(e => { | ||
lastQueueError = e; | ||
}); | ||
await Promise.all(promises); | ||
} | ||
if (this.assetGraph.hasIncompleteNodes()) { | ||
for (let id of this.assetGraph.incompleteNodeIds) { | ||
this.processIncompleteAssetGraphNode((0, _nullthrows.default)(this.assetGraph.getNode(id)), signal); | ||
} | ||
} | ||
visit(root); | ||
await this.queue.run(); | ||
@@ -254,2 +256,3 @@ let errors = []; | ||
for (let [requestId, error] of this.rejected) { | ||
// ? Is this still needed? | ||
if (this.requestTracker.isTracked(requestId)) { | ||
@@ -284,3 +287,3 @@ errors.push(error); | ||
configRef: this.configRef | ||
})); // Skip sending validation requests if no validators were no validators configured | ||
})); // Skip sending validation requests if no validators were configured | ||
@@ -331,5 +334,6 @@ if (trackedRequestsDesc.length === 0) { | ||
this.assetRequests.push(request); | ||
let assetActuallyChanged = !this.requestTracker.hasValidResult(request.id); | ||
let result = await this.assetRequestRunner.runRequest(request.request, runOpts); | ||
if (result != null) { | ||
if (assetActuallyChanged && result != null) { | ||
for (let asset of result.assets) { | ||
@@ -346,2 +350,9 @@ this.changedAssets.set(asset.id, asset); | ||
getCorrespondingRequest(node) { | ||
let requestNode = node.correspondingRequest != null ? this.requestGraph.getNode(node.correspondingRequest) : null; | ||
if (requestNode != null) { | ||
(0, _assert.default)(requestNode.type === 'request'); | ||
return requestNode.value; | ||
} | ||
switch (node.type) { | ||
@@ -390,16 +401,2 @@ case 'entry_specifier': | ||
processIncompleteAssetGraphNode(node, signal) { | ||
let request = (0, _nullthrows.default)(this.getCorrespondingRequest(node)); | ||
if (!this.requestTracker.hasValidResult(request.id)) { | ||
this.queueRequest(request, { | ||
signal | ||
}); | ||
} | ||
} | ||
handleIncompleteNode(node) { | ||
this.processIncompleteAssetGraphNode(node); | ||
} | ||
handleNodeRemovedFromAssetGraph(node) { | ||
@@ -406,0 +403,0 @@ let request = this.getCorrespondingRequest(node); |
@@ -64,3 +64,3 @@ "use strict"; | ||
onComplete(request, result, api) { | ||
this.assetGraph.resolveAssetGroup(request, result.assets); | ||
this.assetGraph.resolveAssetGroup(request, result.assets, api.getId()); | ||
let { | ||
@@ -67,0 +67,0 @@ assets, |
@@ -8,6 +8,2 @@ "use strict"; | ||
var _assert = _interopRequireDefault(require("assert")); | ||
var _AssetGraph = require("../AssetGraph"); | ||
var _RequestTracker = require("../RequestTracker"); | ||
@@ -51,79 +47,9 @@ | ||
if (!assetGroup) { | ||
this.assetGraph.resolveDependency(dependency, null); | ||
this.assetGraph.resolveDependency(dependency, null, api.getId()); | ||
return; | ||
} | ||
let defer = this.shouldDeferDependency(dependency, assetGroup.sideEffects); | ||
dependency.isDeferred = defer; | ||
let assetGroupNode = (0, _AssetGraph.nodeFromAssetGroup)(assetGroup, defer); | ||
let existingAssetGroupNode = this.assetGraph.getNode(assetGroupNode.id); | ||
this.assetGraph.resolveDependency(dependency, assetGroup, api.getId()); // ? Should this happen if asset is deferred? | ||
if (existingAssetGroupNode) { | ||
// Don't overwrite non-deferred asset groups with deferred ones | ||
(0, _assert.default)(existingAssetGroupNode.type === 'asset_group'); | ||
assetGroupNode.deferred = existingAssetGroupNode.deferred && defer; | ||
} | ||
this.assetGraph.resolveDependency(dependency, assetGroupNode); | ||
if (existingAssetGroupNode) { | ||
// Node already existed, that asset might have deferred dependencies, | ||
// recheck all dependencies of all assets of this asset group | ||
this.assetGraph.traverse((node, parent, actions) => { | ||
if (node == assetGroupNode) { | ||
return; | ||
} | ||
if (node.type === 'dependency' && !node.value.isDeferred) { | ||
actions.skipChildren(); | ||
return; | ||
} | ||
if (node.type == 'asset_group') { | ||
(0, _assert.default)(parent && parent.type === 'dependency'); | ||
if (node.deferred && !this.shouldDeferDependency(parent.value, node.value.sideEffects)) { | ||
parent.value.isDeferred = false; | ||
node.deferred = false; | ||
this.assetGraph.markIncomplete(node); | ||
} | ||
actions.skipChildren(); | ||
} | ||
return node; | ||
}, assetGroupNode); | ||
} // ? Should this happen if asset is deferred? | ||
api.invalidateOnFileDelete(assetGroup.filePath); // TODO: invalidate dep path requests that have failed and a file creation may fulfill the request | ||
} // Defer transforming this dependency if it is marked as weak, there are no side effects, | ||
// no re-exported symbols are used by ancestor dependencies and the re-exporting asset isn't | ||
// using a wildcard and isn't an entry (in library mode). | ||
// This helps with performance building large libraries like `lodash-es`, which re-exports | ||
// a huge number of functions since we can avoid even transforming the files that aren't used. | ||
shouldDeferDependency(dependency, sideEffects) { | ||
let defer = false; | ||
if (dependency.isWeak && sideEffects === false && !dependency.symbols.has('*')) { | ||
let depNode = this.assetGraph.getNode(dependency.id); | ||
(0, _assert.default)(depNode); | ||
let assets = this.assetGraph.getNodesConnectedTo(depNode); | ||
let symbols = new Map([...dependency.symbols].map(([key, val]) => [val.local, key])); | ||
(0, _assert.default)(assets.length === 1); | ||
let firstAsset = assets[0]; | ||
(0, _assert.default)(firstAsset.type === 'asset'); | ||
let resolvedAsset = firstAsset.value; | ||
let deps = this.assetGraph.getIncomingDependencies(resolvedAsset); | ||
defer = deps.every(d => !(d.env.isLibrary && d.isEntry) && !d.symbols.has('*') && ![...d.symbols.keys()].some(symbol => { | ||
var _resolvedAsset$symbol, _resolvedAsset$symbol2; | ||
let assetSymbol = (_resolvedAsset$symbol = resolvedAsset.symbols) === null || _resolvedAsset$symbol === void 0 ? void 0 : (_resolvedAsset$symbol2 = _resolvedAsset$symbol.get(symbol)) === null || _resolvedAsset$symbol2 === void 0 ? void 0 : _resolvedAsset$symbol2.local; | ||
return assetSymbol != null && symbols.has(assetSymbol); | ||
})); | ||
} | ||
return defer; | ||
api.invalidateOnFileDelete(assetGroup.filePath); | ||
} | ||
@@ -130,0 +56,0 @@ |
@@ -34,3 +34,3 @@ "use strict"; | ||
onComplete(request, result, api) { | ||
this.assetGraph.resolveEntry(request, result.entries); // Connect files like package.json that affect the entry | ||
this.assetGraph.resolveEntry(request, result.entries, api.getId()); // Connect files like package.json that affect the entry | ||
// resolution so we invalidate when they change. | ||
@@ -37,0 +37,0 @@ |
@@ -34,3 +34,3 @@ "use strict"; | ||
onComplete(request, result, api) { | ||
this.assetGraph.resolveTargets(request, result.targets); // Connect files like package.json that affect the target | ||
this.assetGraph.resolveTargets(request, result.targets, api.getId()); // Connect files like package.json that affect the target | ||
// resolution so we invalidate when they change. | ||
@@ -37,0 +37,0 @@ |
@@ -415,3 +415,4 @@ "use strict"; | ||
this.tracker.storeResult(requestId, result); | ||
} | ||
}, | ||
getId: () => requestId | ||
}; | ||
@@ -418,0 +419,0 @@ } |
{ | ||
"name": "@parcel/core", | ||
"version": "2.0.0-nightly.255+5175a66b", | ||
"version": "2.0.0-nightly.256+e8d7d944", | ||
"license": "MIT", | ||
@@ -19,13 +19,13 @@ "publishConfig": { | ||
"dependencies": { | ||
"@parcel/cache": "2.0.0-nightly.257+5175a66b", | ||
"@parcel/diagnostic": "2.0.0-nightly.257+5175a66b", | ||
"@parcel/events": "2.0.0-nightly.257+5175a66b", | ||
"@parcel/fs": "2.0.0-nightly.257+5175a66b", | ||
"@parcel/logger": "2.0.0-nightly.257+5175a66b", | ||
"@parcel/package-manager": "2.0.0-nightly.257+5175a66b", | ||
"@parcel/plugin": "2.0.0-nightly.257+5175a66b", | ||
"@parcel/cache": "2.0.0-nightly.258+e8d7d944", | ||
"@parcel/diagnostic": "2.0.0-nightly.258+e8d7d944", | ||
"@parcel/events": "2.0.0-nightly.258+e8d7d944", | ||
"@parcel/fs": "2.0.0-nightly.258+e8d7d944", | ||
"@parcel/logger": "2.0.0-nightly.258+e8d7d944", | ||
"@parcel/package-manager": "2.0.0-nightly.258+e8d7d944", | ||
"@parcel/plugin": "2.0.0-nightly.258+e8d7d944", | ||
"@parcel/source-map": "2.0.0-alpha.4.9", | ||
"@parcel/types": "2.0.0-nightly.257+5175a66b", | ||
"@parcel/utils": "2.0.0-nightly.257+5175a66b", | ||
"@parcel/workers": "2.0.0-nightly.257+5175a66b", | ||
"@parcel/types": "2.0.0-nightly.258+e8d7d944", | ||
"@parcel/utils": "2.0.0-nightly.258+e8d7d944", | ||
"@parcel/workers": "2.0.0-nightly.258+e8d7d944", | ||
"abortcontroller-polyfill": "^1.1.9", | ||
@@ -46,3 +46,3 @@ "browserslist": "^4.6.6", | ||
}, | ||
"gitHead": "5175a66b28cd2a6090b247204e550cc0264aabbe" | ||
"gitHead": "e8d7d94484f887c9f61093fca0c63b499305b933" | ||
} |
@@ -13,3 +13,2 @@ // @flow strict-local | ||
Entry, | ||
NodeId, | ||
Target, | ||
@@ -27,4 +26,2 @@ } from './types'; | ||
...GraphOpts<AssetGraphNode>, | ||
onIncompleteNode?: (node: AssetGraphNode) => mixed, | ||
onNodeAdded?: (node: AssetGraphNode) => mixed, | ||
onNodeRemoved?: (node: AssetGraphNode) => mixed, | ||
@@ -52,6 +49,3 @@ |}; | ||
export function nodeFromAssetGroup( | ||
assetGroup: AssetGroup, | ||
deferred: boolean = false, | ||
) { | ||
export function nodeFromAssetGroup(assetGroup: AssetGroup) { | ||
return { | ||
@@ -61,3 +55,2 @@ id: md5FromObject(assetGroup), | ||
value: assetGroup, | ||
deferred, | ||
}; | ||
@@ -90,15 +83,4 @@ } | ||
// Types that are considered incomplete when they don't have a child node | ||
const INCOMPLETE_TYPES = [ | ||
'entry_specifier', | ||
'entry_file', | ||
'dependency', | ||
'asset_group', | ||
]; | ||
export default class AssetGraph extends Graph<AssetGraphNode> { | ||
onNodeAdded: ?(node: AssetGraphNode) => mixed; | ||
onNodeRemoved: ?(node: AssetGraphNode) => mixed; | ||
onIncompleteNode: ?(node: AssetGraphNode) => mixed; | ||
incompleteNodeIds: Set<NodeId> = new Set(); | ||
hash: ?string; | ||
@@ -111,3 +93,2 @@ | ||
// $FlowFixMe Added in Flow 0.121.0 upgrade in #4381 | ||
res.incompleteNodeIds = opts.incompleteNodeIds; | ||
res.hash = opts.hash; | ||
@@ -122,3 +103,2 @@ return res; | ||
...super.serialize(), | ||
incompleteNodeIds: this.incompleteNodeIds, | ||
hash: this.hash, | ||
@@ -128,10 +108,4 @@ }; | ||
initOptions({ | ||
onNodeAdded, | ||
onNodeRemoved, | ||
onIncompleteNode, | ||
}: AssetGraphOpts = {}) { | ||
this.onNodeAdded = onNodeAdded; | ||
initOptions({onNodeRemoved}: AssetGraphOpts = {}) { | ||
this.onNodeRemoved = onNodeRemoved; | ||
this.onIncompleteNode = onIncompleteNode; | ||
} | ||
@@ -159,12 +133,2 @@ | ||
this.hash = null; | ||
let existingNode = this.getNode(node.id); | ||
if ( | ||
INCOMPLETE_TYPES.includes(node.type) && | ||
!node.complete && | ||
!node.deferred && | ||
(!existingNode || existingNode.deferred) | ||
) { | ||
this.markIncomplete(node); | ||
} | ||
this.onNodeAdded && this.onNodeAdded(node); | ||
return super.addNode(node); | ||
@@ -175,3 +139,2 @@ } | ||
this.hash = null; | ||
this.incompleteNodeIds.delete(node.id); | ||
this.onNodeRemoved && this.onNodeRemoved(node); | ||
@@ -181,21 +144,21 @@ return super.removeNode(node); | ||
markIncomplete(node: AssetGraphNode) { | ||
this.incompleteNodeIds.add(node.id); | ||
if (this.onIncompleteNode) { | ||
this.onIncompleteNode(node); | ||
} | ||
} | ||
hasIncompleteNodes() { | ||
return this.incompleteNodeIds.size > 0; | ||
} | ||
resolveEntry(entry: string, resolved: Array<Entry>) { | ||
let entrySpecifierNode = nodeFromEntrySpecifier(entry); | ||
resolveEntry( | ||
entry: string, | ||
resolved: Array<Entry>, | ||
correspondingRequest: string, | ||
) { | ||
let entrySpecifierNode = nullthrows( | ||
this.getNode(nodeFromEntrySpecifier(entry).id), | ||
); | ||
invariant(entrySpecifierNode.type === 'entry_specifier'); | ||
entrySpecifierNode.correspondingRequest = correspondingRequest; | ||
let entryFileNodes = resolved.map(file => nodeFromEntryFile(file)); | ||
this.replaceNodesConnectedTo(entrySpecifierNode, entryFileNodes); | ||
this.incompleteNodeIds.delete(entrySpecifierNode.id); | ||
} | ||
resolveTargets(entry: Entry, targets: Array<Target>) { | ||
resolveTargets( | ||
entry: Entry, | ||
targets: Array<Target>, | ||
correspondingRequest: string, | ||
) { | ||
let depNodes = targets.map(target => | ||
@@ -213,6 +176,7 @@ nodeFromDep( | ||
let entryNode = nodeFromEntryFile(entry); | ||
let entryNode = nullthrows(this.getNode(nodeFromEntryFile(entry).id)); | ||
invariant(entryNode.type === 'entry_file'); | ||
entryNode.correspondingRequest = correspondingRequest; | ||
if (this.hasNode(entryNode.id)) { | ||
this.replaceNodesConnectedTo(entryNode, depNodes); | ||
this.incompleteNodeIds.delete(entryNode.id); | ||
} | ||
@@ -223,19 +187,131 @@ } | ||
dependency: Dependency, | ||
assetGroupNode: AssetGroupNode | null, | ||
assetGroup: AssetGroup | null, | ||
correspondingRequest: string, | ||
) { | ||
let depNode = this.nodes.get(dependency.id); | ||
let depNode = nullthrows(this.nodes.get(dependency.id)); | ||
invariant(depNode.type === 'dependency'); | ||
if (!depNode) return; | ||
this.incompleteNodeIds.delete(depNode.id); | ||
depNode.correspondingRequest = correspondingRequest; | ||
if (assetGroupNode) { | ||
this.replaceNodesConnectedTo(depNode, [assetGroupNode]); | ||
if (!assetGroup) { | ||
return; | ||
} | ||
let assetGroupNode = nodeFromAssetGroup(assetGroup); | ||
let existingAssetGroupNode = this.getNode(assetGroupNode.id); | ||
this.replaceNodesConnectedTo(depNode, [ | ||
existingAssetGroupNode ?? assetGroupNode, | ||
]); | ||
} | ||
resolveAssetGroup(assetGroup: AssetGroup, assets: Array<Asset>) { | ||
shouldVisitChild(node: AssetGraphNode, childNode: AssetGraphNode) { | ||
if ( | ||
node.type !== 'dependency' || | ||
childNode.type !== 'asset_group' || | ||
childNode.deferred === false | ||
) { | ||
return true; | ||
} | ||
let sideEffects = childNode.value.sideEffects; | ||
let dependency = node.value; | ||
let previouslyDeferred = childNode.deferred; | ||
let defer = this.shouldDeferDependency(dependency, sideEffects); | ||
dependency.isDeferred = defer; | ||
node.hasDeferred = defer; | ||
childNode.deferred = defer; | ||
if (!previouslyDeferred && defer) { | ||
this.markParentsWithHasDeferred(node); | ||
} else if (previouslyDeferred && !defer) { | ||
this.unmarkParentsWithHasDeferred(node); | ||
} | ||
return !defer; | ||
} | ||
markParentsWithHasDeferred(node: DependencyNode) { | ||
this.traverseAncestors(node, (_node, _, actions) => { | ||
if (_node.type === 'asset') { | ||
_node.hasDeferred = true; | ||
} else if (_node.type === 'asset_group') { | ||
_node.hasDeferred = true; | ||
actions.skipChildren(); | ||
} else if (node !== _node) { | ||
actions.skipChildren(); | ||
} | ||
}); | ||
} | ||
unmarkParentsWithHasDeferred(node: DependencyNode) { | ||
this.traverseAncestors(node, (_node, ctx, actions) => { | ||
if (_node.type === 'asset') { | ||
let hasDeferred = this.getNodesConnectedFrom(_node).some(_childNode => | ||
_childNode.hasDeferred == null ? false : _childNode.hasDeferred, | ||
); | ||
if (!hasDeferred) { | ||
delete _node.hasDeferred; | ||
} | ||
return {hasDeferred}; | ||
} else if (_node.type === 'asset_group') { | ||
if (!ctx?.hasDeferred) { | ||
delete _node.hasDeferred; | ||
} | ||
actions.skipChildren(); | ||
} else if (node !== _node) { | ||
actions.skipChildren(); | ||
} | ||
}); | ||
} | ||
// Defer transforming this dependency if it is marked as weak, there are no side effects, | ||
// no re-exported symbols are used by ancestor dependencies and the re-exporting asset isn't | ||
// using a wildcard and isn't an entry (in library mode). | ||
// This helps with performance building large libraries like `lodash-es`, which re-exports | ||
// a huge number of functions since we can avoid even transforming the files that aren't used. | ||
shouldDeferDependency(dependency: Dependency, sideEffects: ?boolean) { | ||
let defer = false; | ||
if ( | ||
dependency.isWeak && | ||
sideEffects === false && | ||
!dependency.symbols.has('*') | ||
) { | ||
let depNode = this.getNode(dependency.id); | ||
invariant(depNode); | ||
let assets = this.getNodesConnectedTo(depNode); | ||
let symbols = new Map( | ||
[...dependency.symbols].map(([key, val]) => [val.local, key]), | ||
); | ||
invariant(assets.length === 1); | ||
let firstAsset = assets[0]; | ||
invariant(firstAsset.type === 'asset'); | ||
let resolvedAsset = firstAsset.value; | ||
let deps = this.getIncomingDependencies(resolvedAsset); | ||
defer = deps.every( | ||
d => | ||
!(d.env.isLibrary && d.isEntry) && | ||
!d.symbols.has('*') && | ||
![...d.symbols.keys()].some(symbol => { | ||
let assetSymbol = resolvedAsset.symbols?.get(symbol)?.local; | ||
return assetSymbol != null && symbols.has(assetSymbol); | ||
}), | ||
); | ||
} | ||
return defer; | ||
} | ||
resolveAssetGroup( | ||
assetGroup: AssetGroup, | ||
assets: Array<Asset>, | ||
correspondingRequest: string, | ||
) { | ||
let assetGroupNode = nodeFromAssetGroup(assetGroup); | ||
this.incompleteNodeIds.delete(assetGroupNode.id); | ||
if (!this.hasNode(assetGroupNode.id)) { | ||
assetGroupNode = this.getNode(assetGroupNode.id); | ||
if (!assetGroupNode) { | ||
return; | ||
} | ||
invariant(assetGroupNode.type === 'asset_group'); | ||
assetGroupNode.correspondingRequest = correspondingRequest; | ||
@@ -242,0 +318,0 @@ let dependentAssetKeys = []; |
@@ -21,2 +21,3 @@ // @flow strict-local | ||
import nullthrows from 'nullthrows'; | ||
import invariant from 'assert'; | ||
import path from 'path'; | ||
@@ -52,8 +53,2 @@ import {md5FromObject, md5FromString, PromiseQueue} from '@parcel/utils'; | ||
const requestPriorities: $ReadOnlyArray<$ReadOnlyArray<string>> = [ | ||
['entry_request'], | ||
['target_request'], | ||
['dep_path_request', 'asset_request'], | ||
]; | ||
type AssetGraphBuildRequest = | ||
@@ -86,2 +81,4 @@ | EntryRequest | ||
cacheKey: string; | ||
entries: ?Array<string>; | ||
initialAssetGroups: ?Array<AssetRequestDesc>; | ||
@@ -100,2 +97,4 @@ handle: Handle; | ||
this.optionsRef = optionsRef; | ||
this.entries = entries; | ||
this.initialAssetGroups = assetRequests; | ||
this.workerFarm = workerFarm; | ||
@@ -129,3 +128,2 @@ this.assetRequests = []; | ||
onNodeRemoved: node => this.handleNodeRemovedFromAssetGraph(node), | ||
onIncompleteNode: node => this.handleIncompleteNode(node), | ||
}); | ||
@@ -209,34 +207,40 @@ | ||
this.rejected = new Map(); | ||
let lastQueueError; | ||
for (let currPriorities of requestPriorities) { | ||
if (!this.requestTracker.hasInvalidRequests()) { | ||
break; | ||
} | ||
let promises = []; | ||
for (let request of this.requestTracker.getInvalidRequests()) { | ||
// $FlowFixMe | ||
let assetGraphBuildRequest: AssetGraphBuildRequest = (request: any); | ||
if (currPriorities.includes(request.type)) { | ||
promises.push(this.queueRequest(assetGraphBuildRequest, {signal})); | ||
} | ||
} | ||
if (lastQueueError) { | ||
throw lastQueueError; | ||
} | ||
this.queue.run().catch(e => { | ||
lastQueueError = e; | ||
}); | ||
await Promise.all(promises); | ||
let root = this.assetGraph.getRootNode(); | ||
if (!root) { | ||
throw new Error('A root node is required to traverse'); | ||
} | ||
if (this.assetGraph.hasIncompleteNodes()) { | ||
for (let id of this.assetGraph.incompleteNodeIds) { | ||
this.processIncompleteAssetGraphNode( | ||
nullthrows(this.assetGraph.getNode(id)), | ||
let visited = new Set([root.id]); | ||
const visit = node => { | ||
let request = this.getCorrespondingRequest(node); | ||
if ( | ||
!node.complete && | ||
!node.deferred && | ||
request != null && | ||
!this.requestTracker.hasValidResult(nullthrows(request).id) | ||
) { | ||
// $FlowFixMe | ||
this.queueRequest(request, { | ||
signal, | ||
); | ||
}).then(() => visitChildren(node)); | ||
} else { | ||
visitChildren(node); | ||
} | ||
} | ||
}; | ||
const visitChildren = node => { | ||
for (let child of this.assetGraph.getNodesConnectedFrom(node)) { | ||
if ( | ||
(!visited.has(child.id) || child.hasDeferred) && | ||
this.assetGraph.shouldVisitChild(node, child) | ||
) { | ||
visited.add(child.id); | ||
visit(child); | ||
} | ||
} | ||
}; | ||
visit(root); | ||
await this.queue.run(); | ||
@@ -246,2 +250,3 @@ | ||
for (let [requestId, error] of this.rejected) { | ||
// ? Is this still needed? | ||
if (this.requestTracker.isTracked(requestId)) { | ||
@@ -262,3 +267,2 @@ errors.push(error); | ||
this.changedAssets = new Map(); | ||
return {assetGraph: this.assetGraph, changedAssets: changedAssets}; | ||
@@ -285,3 +289,3 @@ } | ||
// Skip sending validation requests if no validators were no validators configured | ||
// Skip sending validation requests if no validators were configured | ||
if (trackedRequestsDesc.length === 0) { | ||
@@ -311,2 +315,3 @@ return; | ||
} | ||
try { | ||
@@ -330,2 +335,5 @@ await this.runRequest(request, runOpts); | ||
this.assetRequests.push(request); | ||
let assetActuallyChanged = !this.requestTracker.hasValidResult( | ||
request.id, | ||
); | ||
let result = await this.assetRequestRunner.runRequest( | ||
@@ -335,3 +343,3 @@ request.request, | ||
); | ||
if (result != null) { | ||
if (assetActuallyChanged && result != null) { | ||
for (let asset of result.assets) { | ||
@@ -347,2 +355,10 @@ this.changedAssets.set(asset.id, asset); | ||
getCorrespondingRequest(node: AssetGraphNode) { | ||
let requestNode = | ||
node.correspondingRequest != null | ||
? this.requestGraph.getNode(node.correspondingRequest) | ||
: null; | ||
if (requestNode != null) { | ||
invariant(requestNode.type === 'request'); | ||
return requestNode.value; | ||
} | ||
switch (node.type) { | ||
@@ -384,15 +400,2 @@ case 'entry_specifier': { | ||
processIncompleteAssetGraphNode(node: AssetGraphNode, signal: ?AbortSignal) { | ||
let request = nullthrows(this.getCorrespondingRequest(node)); | ||
if (!this.requestTracker.hasValidResult(request.id)) { | ||
this.queueRequest(request, { | ||
signal, | ||
}); | ||
} | ||
} | ||
handleIncompleteNode(node: AssetGraphNode) { | ||
this.processIncompleteAssetGraphNode(node); | ||
} | ||
handleNodeRemovedFromAssetGraph(node: AssetGraphNode) { | ||
@@ -399,0 +402,0 @@ let request = this.getCorrespondingRequest(node); |
@@ -286,3 +286,2 @@ // @flow strict-local | ||
await this.#assetGraphBuilder.validate(); | ||
return event; | ||
@@ -289,0 +288,0 @@ } catch (e) { |
@@ -73,3 +73,3 @@ // @flow strict-local | ||
) { | ||
this.assetGraph.resolveAssetGroup(request, result.assets); | ||
this.assetGraph.resolveAssetGroup(request, result.assets, api.getId()); | ||
@@ -76,0 +76,0 @@ let {assets, configRequests} = result; |
@@ -7,4 +7,2 @@ // @flow strict-local | ||
import invariant from 'assert'; | ||
import {nodeFromAssetGroup} from '../AssetGraph'; | ||
import {RequestRunner} from '../RequestTracker'; | ||
@@ -57,91 +55,11 @@ import ResolverRunner from '../ResolverRunner'; | ||
if (!assetGroup) { | ||
this.assetGraph.resolveDependency(dependency, null); | ||
this.assetGraph.resolveDependency(dependency, null, api.getId()); | ||
return; | ||
} | ||
let defer = this.shouldDeferDependency(dependency, assetGroup.sideEffects); | ||
dependency.isDeferred = defer; | ||
this.assetGraph.resolveDependency(dependency, assetGroup, api.getId()); | ||
let assetGroupNode = nodeFromAssetGroup(assetGroup, defer); | ||
let existingAssetGroupNode = this.assetGraph.getNode(assetGroupNode.id); | ||
if (existingAssetGroupNode) { | ||
// Don't overwrite non-deferred asset groups with deferred ones | ||
invariant(existingAssetGroupNode.type === 'asset_group'); | ||
assetGroupNode.deferred = existingAssetGroupNode.deferred && defer; | ||
} | ||
this.assetGraph.resolveDependency(dependency, assetGroupNode); | ||
if (existingAssetGroupNode) { | ||
// Node already existed, that asset might have deferred dependencies, | ||
// recheck all dependencies of all assets of this asset group | ||
this.assetGraph.traverse((node, parent, actions) => { | ||
if (node == assetGroupNode) { | ||
return; | ||
} | ||
if (node.type === 'dependency' && !node.value.isDeferred) { | ||
actions.skipChildren(); | ||
return; | ||
} | ||
if (node.type == 'asset_group') { | ||
invariant(parent && parent.type === 'dependency'); | ||
if ( | ||
node.deferred && | ||
!this.shouldDeferDependency(parent.value, node.value.sideEffects) | ||
) { | ||
parent.value.isDeferred = false; | ||
node.deferred = false; | ||
this.assetGraph.markIncomplete(node); | ||
} | ||
actions.skipChildren(); | ||
} | ||
return node; | ||
}, assetGroupNode); | ||
} | ||
// ? Should this happen if asset is deferred? | ||
api.invalidateOnFileDelete(assetGroup.filePath); | ||
// TODO: invalidate dep path requests that have failed and a file creation may fulfill the request | ||
} | ||
// Defer transforming this dependency if it is marked as weak, there are no side effects, | ||
// no re-exported symbols are used by ancestor dependencies and the re-exporting asset isn't | ||
// using a wildcard and isn't an entry (in library mode). | ||
// This helps with performance building large libraries like `lodash-es`, which re-exports | ||
// a huge number of functions since we can avoid even transforming the files that aren't used. | ||
shouldDeferDependency(dependency: Dependency, sideEffects: ?boolean) { | ||
let defer = false; | ||
if ( | ||
dependency.isWeak && | ||
sideEffects === false && | ||
!dependency.symbols.has('*') | ||
) { | ||
let depNode = this.assetGraph.getNode(dependency.id); | ||
invariant(depNode); | ||
let assets = this.assetGraph.getNodesConnectedTo(depNode); | ||
let symbols = new Map( | ||
[...dependency.symbols].map(([key, val]) => [val.local, key]), | ||
); | ||
invariant(assets.length === 1); | ||
let firstAsset = assets[0]; | ||
invariant(firstAsset.type === 'asset'); | ||
let resolvedAsset = firstAsset.value; | ||
let deps = this.assetGraph.getIncomingDependencies(resolvedAsset); | ||
defer = deps.every( | ||
d => | ||
!(d.env.isLibrary && d.isEntry) && | ||
!d.symbols.has('*') && | ||
![...d.symbols.keys()].some(symbol => { | ||
let assetSymbol = resolvedAsset.symbols?.get(symbol)?.local; | ||
return assetSymbol != null && symbols.has(assetSymbol); | ||
}), | ||
); | ||
} | ||
return defer; | ||
} | ||
} |
@@ -42,3 +42,3 @@ // @flow strict-local | ||
onComplete(request: FilePath, result: EntryResult, api: RequestRunnerAPI) { | ||
this.assetGraph.resolveEntry(request, result.entries); | ||
this.assetGraph.resolveEntry(request, result.entries, api.getId()); | ||
@@ -45,0 +45,0 @@ // Connect files like package.json that affect the entry |
@@ -44,3 +44,3 @@ // @flow strict-local | ||
) { | ||
this.assetGraph.resolveTargets(request, result.targets); | ||
this.assetGraph.resolveTargets(request, result.targets, api.getId()); | ||
@@ -47,0 +47,0 @@ // Connect files like package.json that affect the target |
@@ -376,2 +376,3 @@ // @flow strict-local | ||
storeResult: (result: mixed) => void, | ||
getId: () => string, | ||
|}; | ||
@@ -452,2 +453,3 @@ | ||
}, | ||
getId: () => requestId, | ||
}; | ||
@@ -454,0 +456,0 @@ |
@@ -181,3 +181,8 @@ // @flow strict-local | ||
export type AssetNode = {|id: string, +type: 'asset', value: Asset|}; | ||
export type AssetNode = {| | ||
id: string, | ||
+type: 'asset', | ||
value: Asset, | ||
hasDeferred?: boolean, | ||
|}; | ||
@@ -189,2 +194,4 @@ export type DependencyNode = {| | ||
complete?: boolean, | ||
correspondingRequest?: string, | ||
hasDeferred?: boolean, | ||
|}; | ||
@@ -214,3 +221,5 @@ | ||
value: AssetGroup, | ||
deferred: boolean, | ||
deferred?: boolean, | ||
correspondingRequest?: string, | ||
hasDeferred?: boolean, | ||
|}; | ||
@@ -234,2 +243,3 @@ | ||
value: ModuleSpecifier, | ||
correspondingRequest?: string, | ||
|}; | ||
@@ -246,2 +256,3 @@ | ||
value: Entry, | ||
correspondingRequest?: string, | ||
|}; | ||
@@ -248,0 +259,0 @@ |
// @flow | ||
import assert from 'assert'; | ||
import nullthrows from 'nullthrows'; | ||
import AssetGraph, { | ||
@@ -8,2 +9,3 @@ nodeFromAssetGroup, | ||
nodeFromEntryFile, | ||
nodeFromAsset, | ||
} from '../src/AssetGraph'; | ||
@@ -14,2 +16,4 @@ import {createDependency} from '../src/Dependency'; | ||
const invariant = assert; | ||
const DEFAULT_ENV = createEnvironment({ | ||
@@ -52,5 +56,7 @@ context: 'browser', | ||
graph.resolveEntry('/path/to/index1', [ | ||
{filePath: '/path/to/index1/src/main.js'}, | ||
]); | ||
graph.resolveEntry( | ||
'/path/to/index1', | ||
[{filePath: '/path/to/index1/src/main.js'}], | ||
'123', | ||
); | ||
@@ -76,12 +82,24 @@ assert( | ||
graph.resolveEntry('/path/to/index1', [ | ||
graph.resolveEntry( | ||
'/path/to/index1', | ||
[{filePath: '/path/to/index1/src/main.js'}], | ||
'1', | ||
); | ||
graph.resolveEntry( | ||
'/path/to/index2', | ||
[{filePath: '/path/to/index2/src/main.js'}], | ||
'2', | ||
); | ||
graph.resolveTargets( | ||
{filePath: '/path/to/index1/src/main.js'}, | ||
]); | ||
graph.resolveEntry('/path/to/index2', [ | ||
TARGETS, | ||
'3', | ||
); | ||
graph.resolveTargets( | ||
{filePath: '/path/to/index2/src/main.js'}, | ||
]); | ||
TARGETS, | ||
'4', | ||
); | ||
graph.resolveTargets({filePath: '/path/to/index1/src/main.js'}, TARGETS); | ||
graph.resolveTargets({filePath: '/path/to/index2/src/main.js'}, TARGETS); | ||
assert( | ||
@@ -158,6 +176,12 @@ graph.nodes.has( | ||
graph.resolveEntry('/path/to/index', [ | ||
graph.resolveEntry( | ||
'/path/to/index', | ||
[{filePath: '/path/to/index/src/main.js'}], | ||
'1', | ||
); | ||
graph.resolveTargets( | ||
{filePath: '/path/to/index/src/main.js'}, | ||
]); | ||
graph.resolveTargets({filePath: '/path/to/index/src/main.js'}, TARGETS); | ||
TARGETS, | ||
'2', | ||
); | ||
@@ -172,3 +196,3 @@ let dep = createDependency({ | ||
graph.resolveDependency(dep, nodeFromAssetGroup(req)); | ||
graph.resolveDependency(dep, req, '3'); | ||
assert(graph.nodes.has(nodeFromAssetGroup(req).id)); | ||
@@ -178,3 +202,3 @@ assert(graph.hasEdge(dep.id, nodeFromAssetGroup(req).id)); | ||
let req2 = {filePath: '/index.jsx', env: DEFAULT_ENV}; | ||
graph.resolveDependency(dep, nodeFromAssetGroup(req2)); | ||
graph.resolveDependency(dep, req2, '4'); | ||
assert(!graph.nodes.has(nodeFromAssetGroup(req).id)); | ||
@@ -185,3 +209,3 @@ assert(graph.nodes.has(nodeFromAssetGroup(req2).id)); | ||
graph.resolveDependency(dep, nodeFromAssetGroup(req2)); | ||
graph.resolveDependency(dep, req2, '5'); | ||
assert(graph.nodes.has(nodeFromAssetGroup(req2).id)); | ||
@@ -198,6 +222,12 @@ assert(graph.hasEdge(dep.id, nodeFromAssetGroup(req2).id)); | ||
graph.resolveEntry('/path/to/index', [ | ||
graph.resolveEntry( | ||
'/path/to/index', | ||
[{filePath: '/path/to/index/src/main.js'}], | ||
'1', | ||
); | ||
graph.resolveTargets( | ||
{filePath: '/path/to/index/src/main.js'}, | ||
]); | ||
graph.resolveTargets({filePath: '/path/to/index/src/main.js'}, TARGETS); | ||
TARGETS, | ||
'2', | ||
); | ||
@@ -213,3 +243,3 @@ let dep = createDependency({ | ||
let req = {filePath, env: DEFAULT_ENV}; | ||
graph.resolveDependency(dep, nodeFromAssetGroup(req)); | ||
graph.resolveDependency(dep, req, '3'); | ||
let sourcePath = filePath; | ||
@@ -270,3 +300,3 @@ let assets = [ | ||
graph.resolveAssetGroup(req, assets); | ||
graph.resolveAssetGroup(req, assets, '4'); | ||
assert(graph.nodes.has('1')); | ||
@@ -317,3 +347,3 @@ assert(graph.nodes.has('2')); | ||
graph.resolveAssetGroup(req, assets2); | ||
graph.resolveAssetGroup(req, assets2, '5'); | ||
assert(graph.nodes.has('1')); | ||
@@ -338,4 +368,12 @@ assert(graph.nodes.has('2')); | ||
graph.resolveEntry('./index', [{filePath: '/path/to/index/src/main.js'}]); | ||
graph.resolveTargets({filePath: '/path/to/index/src/main.js'}, TARGETS); | ||
graph.resolveEntry( | ||
'./index', | ||
[{filePath: '/path/to/index/src/main.js'}], | ||
'1', | ||
); | ||
graph.resolveTargets( | ||
{filePath: '/path/to/index/src/main.js'}, | ||
TARGETS, | ||
'2', | ||
); | ||
@@ -350,3 +388,3 @@ let dep = createDependency({ | ||
let req = {filePath, env: DEFAULT_ENV}; | ||
graph.resolveDependency(dep, nodeFromAssetGroup(req)); | ||
graph.resolveDependency(dep, req, '123'); | ||
let sourcePath = filePath; | ||
@@ -397,3 +435,3 @@ let dep1 = createDependency({ | ||
graph.resolveAssetGroup(req, assets); | ||
graph.resolveAssetGroup(req, assets, '3'); | ||
assert(graph.nodes.has('1')); | ||
@@ -410,2 +448,45 @@ assert(graph.nodes.has('2')); | ||
}); | ||
it('should support marking and unmarking parents with hasDeferred', () => { | ||
let graph = new AssetGraph(); | ||
let assetGroup = {filePath: '/index.js', env: DEFAULT_ENV}; | ||
let assetGroupNode = nodeFromAssetGroup(assetGroup); | ||
graph.initialize({assetGroups: [assetGroup]}); | ||
let dependency = createDependency({ | ||
moduleSpecifier: './utils', | ||
env: DEFAULT_ENV, | ||
sourcePath: '/index.js', | ||
}); | ||
let depNode = nodeFromDep(dependency); | ||
let asset = createAsset({ | ||
id: '1', | ||
filePath: '/index.js', | ||
type: 'js', | ||
isSource: true, | ||
hash: '#1', | ||
stats, | ||
dependencies: new Map([['utils', dependency]]), | ||
env: DEFAULT_ENV, | ||
includedFiles: new Map(), | ||
}); | ||
let assetNode = nodeFromAsset(asset); | ||
graph.resolveAssetGroup(assetGroup, [asset], '1'); | ||
graph.markParentsWithHasDeferred(depNode); | ||
let node = nullthrows(graph.getNode(assetNode.id)); | ||
invariant(node.type === 'asset'); | ||
assert(node.hasDeferred); | ||
node = nullthrows(graph.getNode(assetGroupNode.id)); | ||
invariant(node.type === 'asset_group'); | ||
assert(node.hasDeferred); | ||
graph.unmarkParentsWithHasDeferred(depNode); | ||
node = nullthrows(graph.getNode(assetNode.id)); | ||
invariant(node.type === 'asset'); | ||
assert(!node.hasDeferred); | ||
node = nullthrows(graph.getNode(assetGroupNode.id)); | ||
invariant(node.type === 'asset_group'); | ||
assert(!node.hasDeferred); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
724971
21219