Skip to content

Commit

Permalink
Pass resolution dependencies through to Graph, invalidate modules on …
Browse files Browse the repository at this point in the history
…changes (facebook#1161)

Summary: Pull Request resolved: facebook#1161

Differential Revision: D52391695
  • Loading branch information
robhogan authored and facebook-github-bot committed Dec 25, 2023
1 parent 0c2940a commit b5e4d2c
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 9 deletions.
59 changes: 59 additions & 0 deletions packages/metro/src/DeltaBundler/Graph.js
Expand Up @@ -149,6 +149,9 @@ export class Graph<T = MixedOutput> {
/** Resolved context parameters from `require.context`. */
#resolvedContexts: Map<string, RequireContext> = new Map();

+#resolutionDependencies: Map<string, $ReadOnlySet<string>> = new Map();
+#inverseResolutionDependencies: Map<string, CountingSet<string>> = new Map();

constructor(options: GraphInputOptions) {
this.entryPoints = options.entryPoints;
this.transformOptions = options.transformOptions;
Expand All @@ -175,6 +178,15 @@ export class Graph<T = MixedOutput> {
paths.filter(path => this.dependencies.has(path)),
);

for (const modifiedPath of paths) {
const modulePaths = this.#inverseResolutionDependencies.get(modifiedPath);
if (modulePaths != null) {
for (const modulePath of modulePaths) {
modifiedPathsInBaseGraph.add(modulePath);
}
}
}

const allModifiedPaths = new Set(paths);

const delta = await this._buildDelta(
Expand Down Expand Up @@ -284,6 +296,36 @@ export class Graph<T = MixedOutput> {
};
}

_updateInverseResolutionDependencies(
modulePath: string,
previous: $ReadOnlySet<string>,
next: $ReadOnlySet<string>,
): void {
for (const prevResolutionDep of previous) {
if (!next.has(prevResolutionDep)) {
const inverse = nullthrows(
this.#inverseResolutionDependencies.get(prevResolutionDep),
);
inverse.delete(modulePath);
if (inverse.size === 0) {
this.#inverseResolutionDependencies.delete(prevResolutionDep);
}
}
}

for (const nextResolutionDep of next) {
if (!previous.has(nextResolutionDep)) {
let inverse =
this.#inverseResolutionDependencies.get(nextResolutionDep);
if (inverse == null) {
inverse = new CountingSet();
this.#inverseResolutionDependencies.set(nextResolutionDep, inverse);
}
inverse.add(modulePath);
}
}
}

_recursivelyCommitModule(
path: string,
delta: Delta<T>,
Expand All @@ -295,6 +337,7 @@ export class Graph<T = MixedOutput> {
const {
dependencies: currentDependencies,
resolvedContexts,
resolutionDependencies,
...transformResult
} = currentModule;

Expand All @@ -307,6 +350,13 @@ export class Graph<T = MixedOutput> {
dependencies: new Map(previousDependencies),
};

this._updateInverseResolutionDependencies(
path,
this.#resolutionDependencies.get(path) ?? new Set(),
resolutionDependencies,
);
this.#resolutionDependencies.set(path, resolutionDependencies);

// Update the module information.
this.dependencies.set(nextModule.path, nextModule);

Expand Down Expand Up @@ -638,6 +688,9 @@ export class Graph<T = MixedOutput> {
getSource,
output,
unstable_transformResultKey,
resolutionDependencies: nullthrows(
this.#resolutionDependencies.get(module.path),
),
});
}

Expand Down Expand Up @@ -665,6 +718,12 @@ export class Graph<T = MixedOutput> {
this.#gc.possibleCycleRoots.delete(module.path);
this.#gc.color.delete(module.path);
this.#resolvedContexts.delete(module.path);
this._updateInverseResolutionDependencies(
module.path,
nullthrows(this.#resolutionDependencies.get(module.path)),
new Set(),
);
this.#resolutionDependencies.delete(module.path);
}

// Mark a module as a possible cycle root
Expand Down
Expand Up @@ -90,6 +90,7 @@ describe('GraphTraversal', () => {
]),
getSource: expect.any(Function),
output: [],
resolutionDependencies: new Set(),
resolvedContexts: new Map(),
});
});
Expand Down Expand Up @@ -134,6 +135,7 @@ describe('GraphTraversal', () => {
},
],
]),
resolutionDependencies: new Set(),
resolvedContexts: new Map([
['key-virtual', expectedResolvedContext],
]),
Expand All @@ -145,6 +147,7 @@ describe('GraphTraversal', () => {
'/contextMatch',
{
dependencies: new Map(),
resolutionDependencies: new Set(),
resolvedContexts: new Map(),
output: [],
getSource: expect.any(Function),
Expand All @@ -166,6 +169,7 @@ describe('GraphTraversal', () => {
},
],
]),
resolutionDependencies: new Set(),
resolvedContexts: new Map(),
output: [],
getSource: expect.any(Function),
Expand Down
13 changes: 11 additions & 2 deletions packages/metro/src/DeltaBundler/buildSubgraph.js
Expand Up @@ -33,9 +33,12 @@ function resolveDependencies(
): {
dependencies: Map<string, Dependency>,
resolvedContexts: Map<string, RequireContext>,
resolutionDependencies: Set<string>,
} {
const maybeResolvedDeps = new Map<string, void | Dependency>();
const resolvedContexts = new Map<string, RequireContext>();
const resolutionDependencies = new Set<string>();

for (const dep of dependencies) {
let resolvedDep;
const key = dep.data.key;
Expand Down Expand Up @@ -66,8 +69,14 @@ function resolveDependencies(
};
} else {
try {
const resolution = resolve(parentPath, dep);
if (resolution.dependencies) {
for (const resolutionDependency of resolution.dependencies) {
resolutionDependencies.add(resolutionDependency);
}
}
resolvedDep = {
absolutePath: resolve(parentPath, dep).filePath,
absolutePath: resolution.filePath,
data: dep,
};
} catch (error) {
Expand Down Expand Up @@ -98,7 +107,7 @@ function resolveDependencies(
resolvedDeps.set(key, resolvedDep);
}
}
return {dependencies: resolvedDeps, resolvedContexts};
return {dependencies: resolvedDeps, resolvedContexts, resolutionDependencies};
}

export async function buildSubgraph<T>(
Expand Down
2 changes: 2 additions & 0 deletions packages/metro/src/DeltaBundler/types.flow.js
Expand Up @@ -76,6 +76,7 @@ export type ModuleData<T = MixedOutput> = $ReadOnly<{
output: $ReadOnlyArray<T>,
getSource: () => Buffer,
unstable_transformResultKey?: ?string,
resolutionDependencies: $ReadOnlySet<string>,
}>;

export type Dependencies<T = MixedOutput> = Map<string, Module<T>>;
Expand Down Expand Up @@ -138,6 +139,7 @@ export type AllowOptionalDependencies =

export type BundlerResolution = $ReadOnly<{
type: 'sourceFile',
dependencies?: $ReadOnlySet<string>,
filePath: string,
}>;

Expand Down
2 changes: 1 addition & 1 deletion packages/metro/src/node-haste/DependencyGraph.js
Expand Up @@ -205,6 +205,7 @@ class DependencyGraph extends EventEmitter {
mainFields: this._config.resolver.resolverMainFields,
moduleCache: this._moduleCache,
nodeModulesPaths: this._config.resolver.nodeModulesPaths,
pathLookup: mixedPath => this._fileSystem.lookup(mixedPath),
preferNativePlatform: true,
projectRoot: this._config.projectRoot,
reporter: this._config.reporter,
Expand Down Expand Up @@ -236,7 +237,6 @@ class DependencyGraph extends EventEmitter {
this._config.resolver.unstable_enableIncrementalResolution,
unstable_enablePackageExports:
this._config.resolver.unstable_enablePackageExports,
unstable_getRealPath: getRealPathIfFile,
});
}

Expand Down
48 changes: 42 additions & 6 deletions packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js
Expand Up @@ -17,11 +17,11 @@ import type {
} from '../../DeltaBundler/types.flow';
import type {Reporter} from '../../lib/reporting';
import type {ResolverInputOptions} from '../../shared/types.flow';
import type {LookupResult} from 'metro-file-map/src/flow-types';
import type {
CustomResolver,
DoesFileExist,
FileCandidates,
GetRealPath,
Resolution,
ResolveAsset,
} from 'metro-resolver';
Expand Down Expand Up @@ -68,6 +68,7 @@ type Options<TPackage> = $ReadOnly<{
mainFields: $ReadOnlyArray<string>,
moduleCache: ModuleishCache<TPackage>,
nodeModulesPaths: $ReadOnlyArray<string>,
pathLookup: ?(path: string) => LookupResult,
preferNativePlatform: boolean,
projectRoot: string,
reporter: Reporter,
Expand All @@ -80,7 +81,6 @@ type Options<TPackage> = $ReadOnly<{
}>,
unstable_enableIncrementalResolution: boolean,
unstable_enablePackageExports: boolean,
unstable_getRealPath: ?GetRealPath,
}>;

class ModuleResolver<TPackage: Packageish> {
Expand Down Expand Up @@ -142,16 +142,47 @@ class ModuleResolver<TPackage: Packageish> {
extraNodeModules,
mainFields,
nodeModulesPaths,
pathLookup,
preferNativePlatform,
resolveAsset,
resolveRequest,
sourceExts,
unstable_conditionNames,
unstable_conditionsByPlatform,
unstable_enableIncrementalResolution,
unstable_enablePackageExports,
unstable_getRealPath,
} = this._options;

const resolutionDependencies = unstable_enableIncrementalResolution
? new Set<string>()
: null;
const unstable_getRealPath =
pathLookup == null
? null
: resolutionDependencies != null
? (mixedPath: string) => {
const result = pathLookup(mixedPath);
for (const link of result.links) {
resolutionDependencies.add(
path.resolve(this._options.projectRoot, link),
);
}
if (!result.exists) {
resolutionDependencies.add(
path.resolve(this._options.projectRoot, result.missing),
);
}
return result.exists && result.type === 'f'
? result.realPath
: null;
}
: (mixedPath: string) => {
const result = pathLookup(mixedPath);
return result.exists && result.type === 'f'
? result.realPath
: null;
};

try {
const result = Resolver.resolve(
createDefaultContext(
Expand Down Expand Up @@ -188,7 +219,7 @@ class ModuleResolver<TPackage: Packageish> {
dependency.name,
platform,
);
return this._getFileResolvedModule(result);
return this._getFileResolvedModule(result, resolutionDependencies);
} catch (error) {
if (error instanceof Resolver.FailedToResolvePathError) {
const {candidates} = error;
Expand Down Expand Up @@ -274,10 +305,15 @@ class ModuleResolver<TPackage: Packageish> {
/**
* TODO: Return Resolution instead of coercing to BundlerResolution here
*/
_getFileResolvedModule(resolution: Resolution): BundlerResolution {
_getFileResolvedModule(
resolution: Resolution,
resolutionDependencies: ?$ReadOnlySet<string>,
): BundlerResolution {
switch (resolution.type) {
case 'sourceFile':
return resolution;
return resolutionDependencies
? {...resolution, dependencies: resolutionDependencies}
: resolution;
case 'assetFiles':
// FIXME: we should forward ALL the paths/metadata,
// not just an arbitrary item!
Expand Down

0 comments on commit b5e4d2c

Please sign in to comment.