Skip to content

Commit

Permalink
feat: detect internal functions created after dev server already star…
Browse files Browse the repository at this point in the history
…ted (#6257)

* refactor: store projectDir as class member

* fix: always scan for internal edge functions

* refactor: add some types

* fix: scan for declarations in deployconfig

* refactor: some typescript

* fix: always watch internal functions dir

this has the side-effect that we're *always* starting the function server!

* refactor: some cleanup now that we're always starting the functions server

* chore: prettier

* fix: read import map from deploy config at runtime

* chore: remove unused code

* chore: prettier

* fix: check if import_map is defined

* fix: deploying needs functions-internal folder even if empty

* fix: functions server is now always started

* chore: remove dangling console.error

* chore: fix some more types

* chore: fix some more types

* fix: site root always exists

* chore: more types

* chore: mooore types

* chore: moar types

* fix: implement precedence for user functions

before this commit, we were relying on the order of calling `scanDirectories`
to set things up right. now that internal functions can be added
during dev, we need to handle precedence more explicitly!

* chore: prettier

* fix: try removing clash in sitenames

* chore: debug this schmu

* fix: try awaiting the expectation

* refactor: use build instead of deprecated buildAsync

* chore: disable ssh

* chore: prettier

* fix: one more try

* fix: this time I got you!

* fix: root is not always defined

* fix: make builderror type error
  • Loading branch information
Skn0tt authored Jan 2, 2024
1 parent d74c00d commit 02e1069
Show file tree
Hide file tree
Showing 27 changed files with 1,469 additions and 777 deletions.
1,408 changes: 1,081 additions & 327 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
"@netlify/build": "29.31.0",
"@netlify/build-info": "7.11.3",
"@netlify/config": "20.10.0",
"@netlify/edge-bundler": "10.1.3",
"@netlify/edge-bundler": "11.0.0",
"@netlify/local-functions-proxy": "1.1.1",
"@netlify/zip-it-and-ship-it": "9.28.1",
"@octokit/rest": "19.0.13",
Expand Down
14 changes: 8 additions & 6 deletions src/commands/deploy/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,6 @@ const runDeploy = async ({
deployToProduction,
// @ts-expect-error TS(7031) FIXME: Binding element 'functionsConfig' implicitly has a... Remove this comment to see the full error message
functionsConfig,
// @ts-expect-error TS(7031) FIXME: Binding element 'functionsFolder' implicitly has a... Remove this comment to see the full error message
functionsFolder,
// @ts-expect-error TS(7031) FIXME: Binding element 'options' implicitly has an 'a... Remove this comment to see the full error message
options,
Expand All @@ -429,6 +428,8 @@ const runDeploy = async ({
skipFunctionsCache,
// @ts-expect-error TS(7031) FIXME: Binding element 'title' implicitly has an 'any' ty... Remove this comment to see the full error message
title,
}: {
functionsFolder?: string
}) => {
let results
let deployId
Expand All @@ -444,13 +445,14 @@ const runDeploy = async ({
results = await api.createSiteDeploy({ siteId, title, body: { draft, branch: alias } })
deployId = results.id

// @ts-expect-error TS(2345) FIXME: Argument of type '{ base: any; packagePath: any; }... Remove this comment to see the full error message
const internalFunctionsFolder = await getInternalFunctionsDir({ base: site.root, packagePath })
const internalFunctionsFolder = await getInternalFunctionsDir({ base: site.root, packagePath, ensureExists: true })

// The order of the directories matter: zip-it-and-ship-it will prioritize
// functions from the rightmost directories. In this case, we want user
// functions to take precedence over internal functions.
const functionDirectories = [internalFunctionsFolder, functionsFolder].filter(Boolean)
const functionDirectories = [internalFunctionsFolder, functionsFolder].filter((folder): folder is string =>
Boolean(folder),
)
const manifestPath = skipFunctionsCache ? null : await getFunctionsManifestPath({ base: site.root, packagePath })

const redirectsPath = `${deployFolder}/_redirects`
Expand All @@ -475,11 +477,10 @@ const runDeploy = async ({
uploadDeployBlobs({ deployId, siteId, silent, options, cachedConfig: command.netlify.cachedConfig })

results = await deploySite(api, siteId, deployFolder, {
// @ts-expect-error FIXME
config,
// @ts-expect-error TS(2322) FIXME: Type 'any[]' is not assignable to type 'never[]'.
fnDir: functionDirectories,
functionsConfig,
// @ts-expect-error TS(2322) FIXME: Type '(event: any) => void' is not assignable to t... Remove this comment to see the full error message
statusCb: silent ? () => {} : deployProgressCb(),
deployTimeout,
syncFileLimit: SYNC_FILE_LIMIT,
Expand Down Expand Up @@ -732,6 +733,7 @@ const prepAndRunDeploy = async ({
})

const results = await runDeploy({
// @ts-expect-error FIXME
alias,
api,
command,
Expand Down
4 changes: 4 additions & 0 deletions src/commands/serve/serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ export const serve = async (options: OptionValues, command: BaseCommand) => {
siteInfo,
})

if (!site.root) {
throw new Error('Site root not found')
}

// Ensure the internal functions directory exists so that the functions
// server and registry are initialized, and any functions created by
// Netlify Build are loaded.
Expand Down
54 changes: 0 additions & 54 deletions src/lib/edge-functions/internal.ts

This file was deleted.

35 changes: 6 additions & 29 deletions src/lib/edge-functions/proxy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Buffer } from 'buffer'
import { rm } from 'fs/promises'
import type { IncomingMessage } from 'http'
import { join, resolve } from 'path'

import * as bundler from '@netlify/edge-bundler'
Expand All @@ -13,7 +14,6 @@ import { startSpinner, stopSpinner } from '../spinner.js'
import { getBootstrapURL } from './bootstrap.js'
import { DIST_IMPORT_MAP_PATH, EDGE_FUNCTIONS_SERVE_FOLDER } from './consts.js'
import { headers, getFeatureFlagsHeader, getInvocationMetadataHeader } from './headers.js'
import { getInternalFunctions } from './internal.js'
import { EdgeFunctionsRegistry } from './registry.js'

const headersSymbol = Symbol('Edge Functions Headers')
Expand Down Expand Up @@ -134,12 +134,6 @@ export const initializeProxy = async ({
// @ts-expect-error TS(7031) FIXME: Binding element 'state' implicitly has an 'any' ty... Remove this comment to see the full error message
state,
}) => {
const {
functions: internalFunctions,
// @ts-expect-error TS(2339) FIXME: Property 'importMap' does not exist on type '{ fun... Remove this comment to see the full error message
importMap,
path: internalFunctionsPath,
} = await getInternalFunctions(projectDir)
const userFunctionsPath = config.build.edge_functions
const isolatePort = await getAvailablePort()
const buildFeatureFlags = {
Expand All @@ -159,19 +153,13 @@ export const initializeProxy = async ({
env: configEnv,
featureFlags: buildFeatureFlags,
getUpdatedConfig,
importMaps: [importMap].filter(Boolean),
inspectSettings,
internalDirectory: internalFunctionsPath,
internalFunctions,
port: isolatePort,
projectDir,
repositoryRoot,
})
const hasEdgeFunctions = userFunctionsPath !== undefined || internalFunctionsPath

// @ts-expect-error TS(7006) FIXME: Parameter 'req' implicitly has an 'any' type.
return async (req) => {
if (req.headers[headers.Passthrough] !== undefined || !hasEdgeFunctions) {
return async (req: IncomingMessage & { [headersSymbol]: Record<string, string> }) => {
if (req.headers[headers.Passthrough] !== undefined) {
return
}

Expand All @@ -196,8 +184,8 @@ export const initializeProxy = async ({

await registry.initialize()

const url = new URL(req.url, `http://${LOCAL_HOST}:${mainPort}`)
const { functionNames, invocationMetadata } = registry.matchURLPath(url.pathname, req.method)
const url = new URL(req.url!, `http://${LOCAL_HOST}:${mainPort}`)
const { functionNames, invocationMetadata } = registry.matchURLPath(url.pathname, req.method!)

if (functionNames.length === 0) {
return
Expand Down Expand Up @@ -240,24 +228,15 @@ const prepareServer = async ({
featureFlags,
// @ts-expect-error TS(7031) FIXME: Binding element 'getUpdatedConfig' implicitly has ... Remove this comment to see the full error message
getUpdatedConfig,
// @ts-expect-error TS(7031) FIXME: Binding element 'importMaps' implicitly has an 'an... Remove this comment to see the full error message
importMaps,
// @ts-expect-error TS(7031) FIXME: Binding element 'inspectSettings' implicitly has a... Remove this comment to see the full error message
inspectSettings,
// @ts-expect-error TS(7031) FIXME: Binding element 'internalDirectory' implicitly has... Remove this comment to see the full error message
internalDirectory,
// @ts-expect-error TS(7031) FIXME: Binding element 'internalFunctions' implicitly has... Remove this comment to see the full error message
internalFunctions,
// @ts-expect-error TS(7031) FIXME: Binding element 'port' implicitly has an 'any' typ... Remove this comment to see the full error message
port,
// @ts-expect-error TS(7031) FIXME: Binding element 'projectDir' implicitly has an 'an... Remove this comment to see the full error message
projectDir,
// @ts-expect-error TS(7031) FIXME: Binding element 'repositoryRoot' implicitly has an... Remove this comment to see the full error message
repositoryRoot,
}) => {
// Merging internal with user-defined import maps.
const importMapPaths = [...importMaps, config.functions['*'].deno_import_map]

try {
const distImportMapPath = getPathInProject([DIST_IMPORT_MAP_PATH])
const servePath = resolve(projectDir, getPathInProject([EDGE_FUNCTIONS_SERVE_FOLDER]))
Expand All @@ -277,7 +256,6 @@ const prepareServer = async ({
)}. The file does not seem to have a function as the default export.`,
formatImportError: (name) =>
`${NETLIFYDEVERR} ${chalk.red('Failed')} to run Edge Function ${chalk.yellow(name)}:`,
importMapPaths,
inspectSettings,
port,
rootPath: repositoryRoot,
Expand All @@ -291,8 +269,7 @@ const prepareServer = async ({
directories: [directory].filter(Boolean),
env: configEnv,
getUpdatedConfig,
internalDirectories: [internalDirectory].filter(Boolean),
internalFunctions,
importMapFromTOML: config.functions['*'].deno_import_map,
projectDir,
runIsolate,
servePath,
Expand Down
Loading

2 comments on commit 02e1069

@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,410
  • Package size: 422 MB
  • Number of ts-expect-error directives: 1,189

@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,410
  • Package size: 422 MB
  • Number of ts-expect-error directives: 1,189

Please sign in to comment.