diff --git a/src/lib/edge-functions/registry.ts b/src/lib/edge-functions/registry.ts index b4829b7fd63..e157058de41 100644 --- a/src/lib/edge-functions/registry.ts +++ b/src/lib/edge-functions/registry.ts @@ -26,6 +26,8 @@ export interface Config { edge_functions?: Declaration[] [key: string]: unknown } + +type DependencyCache = Record type EdgeFunctionEvent = 'buildError' | 'loaded' | 'reloaded' | 'reloading' | 'removed' type Route = Omit & { pattern: RegExp } type RunIsolate = Awaited> @@ -49,13 +51,21 @@ interface EdgeFunctionsRegistryOptions { } /** - * Helper method which, given a edge bundler graph module and an index of modules by path, traverses its dependency tree - * and returns an array of all of ist local dependencies + * Given an Edge Bundler module graph and an index of modules by path, + * traverses its dependency tree and returns an array of all of its + * local dependencies. */ function traverseLocalDependencies( - { dependencies = [] }: ModuleJson, + { dependencies = [], specifier }: ModuleJson, modulesByPath: Map, + cache: DependencyCache, ): string[] { + // If we've already traversed this specifier, return the cached list of + // dependencies. + if (cache[specifier] !== undefined) { + return cache[specifier] + } + return dependencies.flatMap((dependency) => { // We're interested in tracking local dependencies, so we only look at // specifiers with the `file:` protocol. @@ -66,17 +76,20 @@ function traverseLocalDependencies( ) { return [] } + const { specifier: dependencyURL } = dependency.code const dependencyPath = fileURLToPath(dependencyURL) const dependencyModule = modulesByPath.get(dependencyPath) - // No module indexed for this dependency + // No module indexed for this dependency. if (dependencyModule === undefined) { return [dependencyPath] } - // Keep traversing the child dependencies and return the current dependency path - return [...traverseLocalDependencies(dependencyModule, modulesByPath), dependencyPath] + // Keep traversing the child dependencies and return the current dependency path. + cache[specifier] = [...traverseLocalDependencies(dependencyModule, modulesByPath, cache), dependencyPath] + + return cache[specifier] }) } @@ -485,9 +498,11 @@ export class EdgeFunctionsRegistry { } }) + const dependencyCache: DependencyCache = {} + // We start from our functions and we traverse through their dependency tree functionModules.forEach(({ functionName, module }) => { - const traversedPaths = traverseLocalDependencies(module, modulesByPath) + const traversedPaths = traverseLocalDependencies(module, modulesByPath, dependencyCache) traversedPaths.forEach((dependencyPath) => { this.dependencyPaths.add(dependencyPath, functionName) })