mirror of https://github.com/status-im/metro.git
Add multiple entrypoint support to the dependency traversal logic
Reviewed By: davidaurelio Differential Revision: D7180692 fbshipit-source-id: 65b1992abbf10e753b6895623824ff90d7cadc24
This commit is contained in:
parent
5e9cf9ec4b
commit
45123d822b
|
@ -12,7 +12,7 @@
|
|||
|
||||
const {
|
||||
initialTraverseDependencies,
|
||||
reorderDependencies,
|
||||
reorderGraph,
|
||||
traverseDependencies,
|
||||
} = require('./traverseDependencies');
|
||||
const {EventEmitter} = require('events');
|
||||
|
@ -60,13 +60,15 @@ class DeltaCalculator extends EventEmitter {
|
|||
this._options = options;
|
||||
this._dependencyGraph = dependencyGraph;
|
||||
|
||||
const entryFilePath = this._dependencyGraph.getAbsolutePath(
|
||||
this._options.entryFile,
|
||||
);
|
||||
// The traverse dependencies logic supports multiple entry points, but
|
||||
// currently metro only supports to pass a single entry point when bundling.
|
||||
const entryPoints = [
|
||||
this._dependencyGraph.getAbsolutePath(this._options.entryFile),
|
||||
];
|
||||
|
||||
this._graph = {
|
||||
dependencies: new Map(),
|
||||
entryFile: entryFilePath,
|
||||
entryPoints,
|
||||
};
|
||||
|
||||
this._dependencyGraph
|
||||
|
@ -87,7 +89,7 @@ class DeltaCalculator extends EventEmitter {
|
|||
// Clean up all the cache data structures to deallocate memory.
|
||||
this._graph = {
|
||||
dependencies: new Map(),
|
||||
entryFile: this._options.entryFile,
|
||||
entryPoints: [this._options.entryFile],
|
||||
};
|
||||
this._modifiedFiles = new Set();
|
||||
this._deletedFiles = new Set();
|
||||
|
@ -148,10 +150,7 @@ class DeltaCalculator extends EventEmitter {
|
|||
|
||||
// Return all the modules if the client requested a reset delta.
|
||||
if (reset) {
|
||||
this._graph.dependencies = reorderDependencies(
|
||||
this._graph.dependencies.get(this._graph.entryFile),
|
||||
this._graph.dependencies,
|
||||
);
|
||||
reorderGraph(this._graph);
|
||||
|
||||
return {
|
||||
modified: this._graph.dependencies,
|
||||
|
@ -202,7 +201,7 @@ class DeltaCalculator extends EventEmitter {
|
|||
const {added} = await initialTraverseDependencies(
|
||||
{
|
||||
dependencies: new Map(),
|
||||
entryFile: path,
|
||||
entryPoints: [path],
|
||||
},
|
||||
this._dependencyGraph,
|
||||
transformOptionsForBlacklist,
|
||||
|
|
|
@ -15,7 +15,6 @@ jest.mock('../traverseDependencies');
|
|||
|
||||
const {
|
||||
initialTraverseDependencies,
|
||||
reorderDependencies,
|
||||
traverseDependencies,
|
||||
} = require('../traverseDependencies');
|
||||
|
||||
|
@ -198,8 +197,6 @@ describe('DeltaCalculator', () => {
|
|||
});
|
||||
|
||||
it('should return a full delta when passing reset=true', async () => {
|
||||
reorderDependencies.mockImplementation((_, edges) => edges);
|
||||
|
||||
await deltaCalculator.getDelta({reset: false});
|
||||
|
||||
const result = await deltaCalculator.getDelta({reset: true});
|
||||
|
|
|
@ -59,6 +59,8 @@ Object {
|
|||
"path": "/baz",
|
||||
},
|
||||
},
|
||||
"entryFile": "/bundle",
|
||||
"entryPoints": Array [
|
||||
"/bundle",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -62,7 +62,7 @@ describe('traverseDependencies', function() {
|
|||
|
||||
const graph = {
|
||||
dependencies: new Map(),
|
||||
entryFile: entryPath,
|
||||
entryPoints: [entryPath],
|
||||
};
|
||||
|
||||
const {added} = await traverseDependencies.initialTraverseDependencies(
|
||||
|
@ -5073,7 +5073,7 @@ describe('traverseDependencies', function() {
|
|||
return traverseDependencies.initialTraverseDependencies(
|
||||
{
|
||||
dependencies: new Map(),
|
||||
entryFile: '/root/index.js',
|
||||
entryPoints: ['/root/index.js'],
|
||||
},
|
||||
dependencyGraph,
|
||||
emptyTransformOptions,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
const {
|
||||
initialTraverseDependencies,
|
||||
reorderGraph,
|
||||
traverseDependencies,
|
||||
} = require('../traverseDependencies');
|
||||
|
||||
|
@ -172,7 +173,7 @@ beforeEach(async () => {
|
|||
|
||||
graph = {
|
||||
dependencies: new Map(),
|
||||
entryFile: '/bundle',
|
||||
entryPoints: ['/bundle'],
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -377,6 +378,33 @@ describe('edge cases', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it('should traverse a graph from multiple entry points', async () => {
|
||||
entryModule = Actions.createFile('/bundle-2');
|
||||
|
||||
Actions.addDependency('/bundle-2', '/bundle-2-foo');
|
||||
Actions.addDependency('/bundle-2', '/bundle-2-bar');
|
||||
Actions.addDependency('/bundle-2', '/bar');
|
||||
|
||||
files = new Set();
|
||||
|
||||
graph = {
|
||||
dependencies: new Map(),
|
||||
entryPoints: ['/bundle', '/bundle-2'],
|
||||
};
|
||||
|
||||
await initialTraverseDependencies(graph, dependencyGraph, {});
|
||||
|
||||
expect([...graph.dependencies.keys()]).toEqual([
|
||||
'/bundle',
|
||||
'/foo',
|
||||
'/bar',
|
||||
'/baz',
|
||||
'/bundle-2',
|
||||
'/bundle-2-foo',
|
||||
'/bundle-2-bar',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should traverse the dependency tree in a deterministic order', async () => {
|
||||
// Mocks the shallow dependency call, always resolving the module in
|
||||
// `slowPath` after the module in `fastPath`.
|
||||
|
@ -416,7 +444,7 @@ describe('edge cases', () => {
|
|||
async function assertOrder() {
|
||||
graph = {
|
||||
dependencies: new Map(),
|
||||
entryFile: '/bundle',
|
||||
entryPoints: ['/bundle'],
|
||||
};
|
||||
|
||||
expect(
|
||||
|
@ -483,3 +511,33 @@ describe('edge cases', () => {
|
|||
expect(moduleFoo.read).toHaveBeenCalledWith({inlineRequires: true});
|
||||
});
|
||||
});
|
||||
|
||||
describe('reorderGraph', () => {
|
||||
it('should reorder any unordered graph in DFS order', async () => {
|
||||
const graph = {
|
||||
dependencies: new Map([
|
||||
['/2', {dependencies: new Map(), path: '/2'}],
|
||||
[
|
||||
'/0',
|
||||
{path: '/0', dependencies: new Map([['/1', '/1'], ['/2', '/2']])},
|
||||
],
|
||||
['/1', {dependencies: new Map([['/2', '/2']]), path: '/1'}],
|
||||
['/3', {dependencies: new Map(), path: '/3'}],
|
||||
['/b', {dependencies: new Map([['/3', '/3']]), path: '/b'}],
|
||||
['/a', {dependencies: new Map([['/0', '/0']]), path: '/a'}],
|
||||
]),
|
||||
entryPoints: ['/a', '/b'],
|
||||
};
|
||||
|
||||
reorderGraph(graph);
|
||||
|
||||
expect([...graph.dependencies.keys()]).toEqual([
|
||||
'/a',
|
||||
'/0',
|
||||
'/1',
|
||||
'/2',
|
||||
'/b',
|
||||
'/3',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -35,7 +35,7 @@ export type DependencyEdges = Map<string, DependencyEdge>;
|
|||
|
||||
export type Graph = {|
|
||||
dependencies: DependencyEdges,
|
||||
entryFile: string,
|
||||
entryPoints: $ReadOnlyArray<string>,
|
||||
|};
|
||||
|
||||
type Result = {added: Map<string, DependencyEdge>, deleted: Set<string>};
|
||||
|
@ -67,7 +67,7 @@ type Delta = {
|
|||
* since the last traversal.
|
||||
*/
|
||||
async function traverseDependencies(
|
||||
paths: Array<string>,
|
||||
paths: $ReadOnlyArray<string>,
|
||||
dependencyGraph: DependencyGraph,
|
||||
transformOptions: JSTransformerOptions,
|
||||
graph: Graph,
|
||||
|
@ -139,29 +139,23 @@ async function initialTraverseDependencies(
|
|||
transformOptions: JSTransformerOptions,
|
||||
onProgress?: (numProcessed: number, total: number) => mixed = () => {},
|
||||
): Promise<Result> {
|
||||
const edge = createEdge(
|
||||
dependencyGraph.getModuleForPath(graph.entryFile),
|
||||
graph,
|
||||
graph.entryPoints.forEach(entryPoint =>
|
||||
createEdge(dependencyGraph.getModuleForPath(entryPoint), graph),
|
||||
);
|
||||
|
||||
const delta = {
|
||||
added: new Map([[edge.path, edge]]),
|
||||
modified: new Map(),
|
||||
deleted: new Set(),
|
||||
};
|
||||
|
||||
await traverseDependenciesForSingleFile(
|
||||
edge,
|
||||
await traverseDependencies(
|
||||
graph.entryPoints,
|
||||
dependencyGraph,
|
||||
transformOptions,
|
||||
graph,
|
||||
delta,
|
||||
onProgress,
|
||||
);
|
||||
|
||||
reorderGraph(graph);
|
||||
|
||||
return {
|
||||
added: reorderDependencies(edge, delta.added),
|
||||
deleted: delta.deleted,
|
||||
added: graph.dependencies,
|
||||
deleted: new Set(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -391,30 +385,37 @@ function resolveDependencies(
|
|||
|
||||
/**
|
||||
* Retraverse the dependency graph in DFS order to reorder the modules and
|
||||
* guarantee the same order between runs.
|
||||
* guarantee the same order between runs. This method mutates the passed graph.
|
||||
*/
|
||||
function reorderGraph(graph: Graph) {
|
||||
const parent = {
|
||||
dependencies: new Map(graph.entryPoints.map(e => [e, e])),
|
||||
};
|
||||
|
||||
const dependencies = reorderDependencies(parent, graph.dependencies);
|
||||
|
||||
graph.dependencies = dependencies;
|
||||
}
|
||||
|
||||
function reorderDependencies(
|
||||
edge: ?DependencyEdge,
|
||||
edge: {|dependencies: Map<string, string>|} | DependencyEdge,
|
||||
dependencies: Map<string, DependencyEdge>,
|
||||
orderedDependencies?: Map<string, DependencyEdge> = new Map(),
|
||||
): Map<string, DependencyEdge> {
|
||||
if (
|
||||
!edge ||
|
||||
!dependencies.has(edge.path) ||
|
||||
orderedDependencies.has(edge.path)
|
||||
) {
|
||||
return orderedDependencies;
|
||||
if (edge.path) {
|
||||
if (orderedDependencies.has(edge.path)) {
|
||||
return orderedDependencies;
|
||||
}
|
||||
|
||||
orderedDependencies.set(edge.path, edge);
|
||||
}
|
||||
|
||||
orderedDependencies.set(edge.path, edge);
|
||||
|
||||
edge.dependencies.forEach(path =>
|
||||
reorderDependencies(
|
||||
dependencies.get(path),
|
||||
dependencies,
|
||||
orderedDependencies,
|
||||
),
|
||||
);
|
||||
edge.dependencies.forEach(path => {
|
||||
const dep = dependencies.get(path);
|
||||
if (dep) {
|
||||
reorderDependencies(dep, dependencies, orderedDependencies);
|
||||
}
|
||||
});
|
||||
|
||||
return orderedDependencies;
|
||||
}
|
||||
|
@ -422,5 +423,5 @@ function reorderDependencies(
|
|||
module.exports = {
|
||||
initialTraverseDependencies,
|
||||
traverseDependencies,
|
||||
reorderDependencies,
|
||||
reorderGraph,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue