diff --git a/packages/metro/src/DeltaBundler/__tests__/traverseDependencies-test.js b/packages/metro/src/DeltaBundler/__tests__/traverseDependencies-test.js index c7ae6b1e..491a05b3 100644 --- a/packages/metro/src/DeltaBundler/__tests__/traverseDependencies-test.js +++ b/packages/metro/src/DeltaBundler/__tests__/traverseDependencies-test.js @@ -319,7 +319,7 @@ describe('edge cases', () => { expect( getPaths( - await traverseDependencies(['/foo'], dependencyGraph, {}, edges), + await traverseDependencies([...files], dependencyGraph, {}, edges), ), ).toEqual({ added: new Set(['/foo', '/baz-moved']), @@ -335,7 +335,7 @@ describe('edge cases', () => { expect( getPaths( - await traverseDependencies(['/foo'], dependencyGraph, {}, edges), + await traverseDependencies([...files], dependencyGraph, {}, edges), ), ).toEqual({ added: new Set(['/foo', '/qux']), diff --git a/packages/metro/src/DeltaBundler/traverseDependencies.js b/packages/metro/src/DeltaBundler/traverseDependencies.js index fc5a1022..fe74f45a 100644 --- a/packages/metro/src/DeltaBundler/traverseDependencies.js +++ b/packages/metro/src/DeltaBundler/traverseDependencies.js @@ -41,7 +41,7 @@ type Result = {added: Map, deleted: Set}; * (a file should not be deleted if it has been added, but it should if it * just has been modified). **/ -type ResultWithModifiedFiles = { +type Delta = { added: Map, modified: Map, deleted: Set, @@ -68,7 +68,11 @@ async function traverseDependencies( edges: DependencyEdges, onProgress?: (numProcessed: number, total: number) => mixed = () => {}, ): Promise { - const changes = []; + const delta = { + added: new Map(), + modified: new Map(), + deleted: new Set(), + }; await Promise.all( paths.map(async path => { @@ -78,14 +82,15 @@ async function traverseDependencies( return; } - changes.push( - await traverseDependenciesForSingleFile( - edge, - dependencyGraph, - transformOptions, - edges, - onProgress, - ), + delta.modified.set(edge.path, edge); + + await traverseDependenciesForSingleFile( + edge, + dependencyGraph, + transformOptions, + edges, + delta, + onProgress, ); }), ); @@ -94,29 +99,26 @@ async function traverseDependencies( const deleted = new Set(); const modified = new Map(); - for (const change of changes) { - for (const [path, edge] of change.added) { - added.set(path, edge); - } - - for (const [path, edge] of change.modified) { - modified.set(path, edge); - } + for (const [path, edge] of delta.added) { + added.set(path, edge); } - for (const change of changes) { - for (const path of change.deleted) { - // If a dependency has been marked as added, it should never be included - // in as added. - // At the same time, if a dependency has been marked both as added and - // deleted, it means that this is a renamed file (or that dependency - // has been removed from one path but added back in a different path). - // In this case the addition and deletion "get cancelled". - const markedAsAdded = added.delete(path); + for (const [path, edge] of delta.modified) { + added.set(path, edge); + modified.set(path, edge); + } - if (!markedAsAdded || modified.has(path)) { - deleted.add(path); - } + for (const path of delta.deleted) { + // If a dependency has been marked as deleted, it should never be included + // in the added group. + // At the same time, if a dependency has been marked both as added and + // deleted, it means that this is a renamed file (or that dependency + // has been removed from one path but added back in a different path). + // In this case the addition and deletion "get cancelled". + const markedAsAdded = added.delete(path); + + if (!markedAsAdded || modified.has(path)) { + deleted.add(path); } } @@ -135,13 +137,25 @@ async function initialTraverseDependencies( ): Promise { const edge = createEdge(dependencyGraph.getModuleForPath(path), edges); - return await traverseDependenciesForSingleFile( + const delta = { + added: new Map([[edge.path, edge]]), + modified: new Map(), + deleted: new Set(), + }; + + await traverseDependenciesForSingleFile( edge, dependencyGraph, transformOptions, edges, + delta, onProgress, ); + + return { + added: reorderDependencies(edge, delta.added), + deleted: delta.deleted, + }; } async function traverseDependenciesForSingleFile( @@ -149,17 +163,19 @@ async function traverseDependenciesForSingleFile( dependencyGraph: DependencyGraph, transformOptions: JSTransformerOptions, edges: DependencyEdges, + delta: Delta, onProgress?: (numProcessed: number, total: number) => mixed = () => {}, -): Promise { +): Promise { let numProcessed = 0; let total = 1; onProgress(numProcessed, total); - const result = await processEdge( + await processEdge( edge, dependencyGraph, transformOptions, edges, + delta, () => { total++; onProgress(numProcessed, total); @@ -172,14 +188,6 @@ async function traverseDependenciesForSingleFile( numProcessed++; onProgress(numProcessed, total); - - const modified = new Map([[edge.path, edge]]); - - return { - added: reorderDependencies(edge, result.added), - deleted: result.deleted, - modified, - }; } async function processEdge( @@ -187,9 +195,10 @@ async function processEdge( dependencyGraph: DependencyGraph, transformOptions: JSTransformerOptions, edges: DependencyEdges, + delta: Delta, onDependencyAdd: () => mixed, onDependencyAdded: () => mixed, -): Promise { +): Promise { const previousDependencies = new Set(edge.dependencies.values()); const result = await dependencyGraph @@ -217,15 +226,12 @@ async function processEdge( edge.dependencies.set(relativePath, absolutePath); }); - const deleted = []; for (const absolutePath of previousDependencies.values()) { if (!currentDependencies.has(absolutePath)) { - deleted.push(removeDependency(edge, absolutePath, edges)); + removeDependency(edge, absolutePath, edges, delta); } } - const added = new Map([[edge.path, edge]]); - // Check all the module dependencies and start traversing the tree from each // added and removed dependency, to get all the modules that have to be added // and removed from the dependency graph. @@ -235,26 +241,18 @@ async function processEdge( return; } - const dependencies = await addDependency( + await addDependency( edge, absolutePath, dependencyGraph, transformOptions, edges, + delta, onDependencyAdd, onDependencyAdded, ); - - for (const [path, edge] of dependencies) { - added.set(path, edge); - } }), ); - - return { - added, - deleted: flatten(deleted), - }; } async function addDependency( @@ -263,47 +261,49 @@ async function addDependency( dependencyGraph: DependencyGraph, transformOptions: JSTransformerOptions, edges: DependencyEdges, + delta: Delta, onDependencyAdd: () => mixed, onDependencyAdded: () => mixed, -): Promise> { +): Promise { const existingEdge = edges.get(path); // The new dependency was already in the graph, we don't need to do anything. if (existingEdge) { existingEdge.inverseDependencies.add(parentEdge.path); - return new Map(); + return; } const edge = createEdge(dependencyGraph.getModuleForPath(path), edges); edge.inverseDependencies.add(parentEdge.path); + delta.added.set(edge.path, edge); onDependencyAdd(); - const {added} = await processEdge( + await processEdge( edge, dependencyGraph, transformOptions, edges, + delta, onDependencyAdd, onDependencyAdded, ); onDependencyAdded(); - - return added; } function removeDependency( parentEdge: DependencyEdge, absolutePath: string, edges: DependencyEdges, -): Set { + delta: Delta, +): void { const edge = edges.get(absolutePath); if (!edge) { - return new Set(); + return; } edge.inverseDependencies.delete(parentEdge.path); @@ -311,26 +311,20 @@ function removeDependency( // This module is still used by another modules, so we cannot remove it from // the bundle. if (edge.inverseDependencies.size) { - return new Set(); + return; } - const removedDependencies = new Set([edge.path]); + delta.deleted.add(edge.path); // Now we need to iterate through the module dependencies in order to // clean up everything (we cannot read the module because it may have // been deleted). for (const depAbsolutePath of edge.dependencies.values()) { - const removed = removeDependency(edge, depAbsolutePath, edges); - - for (const removedDependency of removed.values()) { - removedDependencies.add(removedDependency); - } + removeDependency(edge, depAbsolutePath, edges, delta); } // This module is not used anywhere else!! we can clear it from the bundle destroyEdge(edge, edges); - - return removedDependencies; } function createEdge(module: Module, edges: DependencyEdges): DependencyEdge { @@ -416,18 +410,6 @@ function reorderDependencies( return orderedDependencies; } -function flatten(input: Iterable>): Set { - const output = new Set(); - - for (const items of input) { - for (const item of items) { - output.add(item); - } - } - - return output; -} - module.exports = { initialTraverseDependencies, traverseDependencies,