Skip to content

Commit

Permalink
fix: cache edge function dependency tracing (#6440)
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardoboucas committed Mar 15, 2024
1 parent 10965ab commit a2917d2
Showing 1 changed file with 22 additions and 7 deletions.
29 changes: 22 additions & 7 deletions src/lib/edge-functions/registry.ts
Expand Up @@ -26,6 +26,8 @@ export interface Config {
edge_functions?: Declaration[]
[key: string]: unknown
}

type DependencyCache = Record<string, string[]>
type EdgeFunctionEvent = 'buildError' | 'loaded' | 'reloaded' | 'reloading' | 'removed'
type Route = Omit<Manifest['routes'][0], 'pattern'> & { pattern: RegExp }
type RunIsolate = Awaited<ReturnType<typeof import('@netlify/edge-bundler').serve>>
Expand All @@ -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<string, ModuleJson>,
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.
Expand All @@ -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]
})
}

Expand Down Expand Up @@ -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)
})
Expand Down

2 comments on commit a2917d2

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📊 Benchmark results

  • Dependency count: 1,326
  • Package size: 298 MB
  • Number of ts-expect-error directives: 1,120

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📊 Benchmark results

  • Dependency count: 1,326
  • Package size: 298 MB
  • Number of ts-expect-error directives: 1,120

Please sign in to comment.