Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions src/commands/deploy/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import { SiteInfo } from '../../utils/types.js'
import type { DeployOptionValues } from './option_values.js'
import boxen from 'boxen'
import terminalLink from 'terminal-link'
import { anyEdgeFunctionsDirectoryExists } from '../../lib/edge-functions/get-directories.js'

const triggerDeploy = async ({
api,
Expand Down Expand Up @@ -727,8 +728,11 @@ const bundleEdgeFunctions = async (options: DeployOptionValues, command: BaseCom
// We log our own progress so we don't want this as well. Plus, this logs much of the same
// information as the build that (likely) came before this as part of the deploy build.
quiet: options.debug ?? true,
// @ts-expect-error FIXME(serhalp): This is missing from the `runCoreSteps` type in @netlify/build
// (cachedConfig type error hides this one, but it still is valid) @ts-expect-error FIXME(serhalp): This is missing from the `runCoreSteps` type in @netlify/build
edgeFunctionsBootstrapURL: await getBootstrapURL(),
// @ts-expect-error 'CachedConfig' is not assignable to type 'Record<string, unknown>'.
// Index signature for type 'string' is missing in type 'CachedConfig'.
cachedConfig: command.netlify.cachedConfig,
Comment on lines +731 to +735
Copy link
Contributor Author

@pieh pieh Oct 24, 2025

Choose a reason for hiding this comment

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

this is a bit frustrating, once I do add cachedConfig here, it no longer complain about edgeFunctionsBootstrapURL and now it actually complain about @ts-expect-error for it ... but this is still valid, just somehow hidden because of cachedConfig type error ...

Passing cachedConfig seems needed to properly support --cwd other/dir case, as otherwise bundling was trying to look in current directory and there doesn't seem to be other arguments we can pass to tell it to look elsewhere (despite passing cwd explitly above).

})

if (!success) {
Expand Down Expand Up @@ -867,10 +871,11 @@ const prepAndRunDeploy = async ({
const functionsFolder = getFunctionsFolder({ workingDir, options, config, site, siteData })
const { configPath } = site

const edgeFunctionsConfig = command.netlify.config.edge_functions

// build flag wasn't used and edge functions exist
if (!options.build && edgeFunctionsConfig && edgeFunctionsConfig.length !== 0) {
// build flag wasn't used and edge functions directories exist
if (!options.build && (await anyEdgeFunctionsDirectoryExists(command))) {
// for the case of directories existing but not containing any edge functions,
// there is early bail in edge functions bundling after scanning for edge functions
// for this case and to avoid replicating scanning logic here, we defer to the bundling step
await bundleEdgeFunctions(options, command)
}
Comment on lines +874 to 880
Copy link
Contributor Author

Choose a reason for hiding this comment

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

the previous condition doesn't seem to be met unless you specify some edge functions configuration in toml (?) so instead we check if there are edge functions dir present and trigger on-demand edge bundling if they are

if directories exist but contain on edge functions - there will be early bail - that's just edge bundling function step in @netlify/build works, so I opted not trying to repeat same logic here


Expand Down
32 changes: 32 additions & 0 deletions src/lib/edge-functions/get-directories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { join } from 'path'

import { getPathInProject } from '../settings.js'
import { INTERNAL_EDGE_FUNCTIONS_FOLDER } from './consts.js'
import BaseCommand from '../../commands/base-command.js'
import { fileExistsAsync } from '../fs.js'

export const getUserEdgeFunctionsDirectory = (command: BaseCommand): string | undefined => {
return command.netlify.config.build.edge_functions
}

export const getInternalEdgeFunctionsDirectory = (command: BaseCommand): string => {
return join(command.workingDir, getPathInProject([INTERNAL_EDGE_FUNCTIONS_FOLDER]))
}

export const getFrameworkEdgeFunctionsDirectory = (command: BaseCommand): string => {
return command.netlify.frameworksAPIPaths.edgeFunctions.path
}

const getAllEdgeFunctionsDirectories = (command: BaseCommand) => {
return [
getUserEdgeFunctionsDirectory(command),
getInternalEdgeFunctionsDirectory(command),
getFrameworkEdgeFunctionsDirectory(command),
].filter(Boolean) as string[]
}

export const anyEdgeFunctionsDirectoryExists = async (command: BaseCommand): Promise<boolean> => {
const directoriesToCheck = getAllEdgeFunctionsDirectories(command)

return (await Promise.all(directoriesToCheck.map(fileExistsAsync))).some(Boolean)
}
5 changes: 0 additions & 5 deletions src/lib/edge-functions/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ export const initializeProxy = async ({
siteInfo: $TSFixMe
state: LocalState
}) => {
const userFunctionsPath = config.build.edge_functions
const isolatePort = await getAvailablePort()
const runtimeFeatureFlags = ['edge_functions_bootstrap_failure_mode', 'edge_functions_bootstrap_populate_environment']
const protocol = settings.https ? 'https' : 'http'
Expand All @@ -132,7 +131,6 @@ export const initializeProxy = async ({
config,
configPath,
debug,
directory: userFunctionsPath,
env: configEnv,
featureFlags: buildFeatureFlags,
getUpdatedConfig,
Expand Down Expand Up @@ -207,7 +205,6 @@ const prepareServer = async ({
config,
configPath,
debug,
directory,
env: configEnv,
featureFlags,
getUpdatedConfig,
Expand All @@ -221,7 +218,6 @@ const prepareServer = async ({
config: NormalizedCachedConfigConfig
configPath: string
debug: boolean
directory?: string
env: Record<string, { sources: string[]; value: string }>
featureFlags: FeatureFlags
getUpdatedConfig: () => Promise<NormalizedCachedConfigConfig>
Expand Down Expand Up @@ -261,7 +257,6 @@ const prepareServer = async ({
config,
configPath,
debug,
directories: directory ? [directory] : [],
env: configEnv,
featureFlags,
getUpdatedConfig,
Expand Down
26 changes: 12 additions & 14 deletions src/lib/edge-functions/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ import type { FeatureFlags } from '../../utils/feature-flags.js'
import { MultiMap } from '../../utils/multimap.js'
import { getPathInProject } from '../settings.js'

import { DIST_IMPORT_MAP_PATH, INTERNAL_EDGE_FUNCTIONS_FOLDER } from './consts.js'
import { DIST_IMPORT_MAP_PATH } from './consts.js'
import {
getFrameworkEdgeFunctionsDirectory,
getInternalEdgeFunctionsDirectory,
getUserEdgeFunctionsDirectory,
} from './get-directories.js'

type DependencyCache = Record<string, string[]>
type EdgeFunctionEvent = 'buildError' | 'loaded' | 'reloaded' | 'reloading' | 'removed'
Expand All @@ -38,7 +43,6 @@ interface EdgeFunctionsRegistryOptions {
config: NormalizedCachedConfigConfig
configPath: string
debug: boolean
directories: string[]
env: Record<string, { sources: string[]; value: string }>
featureFlags: FeatureFlags
getUpdatedConfig: () => Promise<NormalizedCachedConfigConfig>
Expand Down Expand Up @@ -105,7 +109,6 @@ export class EdgeFunctionsRegistry {
// Mapping file URLs to names of functions that use them as dependencies.
private dependencyPaths = new MultiMap<string, string>()

private directories: string[]
private directoryWatchers = new Map<string, import('chokidar').FSWatcher>()
private env: Record<string, string>
private featureFlags: FeatureFlags
Expand Down Expand Up @@ -133,7 +136,6 @@ export class EdgeFunctionsRegistry {
command,
config,
configPath,
directories,
env,
featureFlags,
getUpdatedConfig,
Expand All @@ -146,7 +148,6 @@ export class EdgeFunctionsRegistry {
this.command = command
this.bundler = bundler
this.configPath = configPath
this.directories = directories
this.featureFlags = featureFlags
this.getUpdatedConfig = getUpdatedConfig
this.runIsolate = runIsolate
Expand Down Expand Up @@ -563,16 +564,12 @@ export class EdgeFunctionsRegistry {
return { functionsConfig, graph, success }
}

private get internalDirectory() {
return join(this.projectDir, getPathInProject([INTERNAL_EDGE_FUNCTIONS_FOLDER]))
}

private get internalImportMapPath() {
return join(this.projectDir, getPathInProject([DIST_IMPORT_MAP_PATH]))
}

private async readDeployConfig() {
const manifestPath = join(this.internalDirectory, 'manifest.json')
const manifestPath = join(getInternalEdgeFunctionsDirectory(this.command), 'manifest.json')
try {
const contents = await readFile(manifestPath, 'utf8')
const manifest = JSON.parse(contents)
Expand All @@ -592,15 +589,16 @@ export class EdgeFunctionsRegistry {

this.declarationsFromDeployConfig = deployConfig.functions
this.importMapFromDeployConfig = deployConfig.import_map
? join(this.internalDirectory, deployConfig.import_map)
? join(getInternalEdgeFunctionsDirectory(this.command), deployConfig.import_map)
: undefined
}

private async scanForFunctions() {
const userFunctionDirectory = getUserEdgeFunctionsDirectory(this.command)
const [frameworkFunctions, integrationFunctions, userFunctions] = await Promise.all([
this.usesFrameworksAPI ? this.bundler.find([this.command.netlify.frameworksAPIPaths.edgeFunctions.path]) : [],
this.bundler.find([this.internalDirectory]),
this.bundler.find(this.directories),
this.usesFrameworksAPI ? this.bundler.find([getFrameworkEdgeFunctionsDirectory(this.command)]) : [],
this.bundler.find([getInternalEdgeFunctionsDirectory(this.command)]),
userFunctionDirectory ? this.bundler.find([userFunctionDirectory]) : [],
this.scanForDeployConfig(),
])
const internalFunctions = [...frameworkFunctions, ...integrationFunctions]
Expand Down
Loading
Loading