Skip to content

Commit fa811f2

Browse files
feat: add serverAddress to request handler (#308)
* feat: add `serverAddress` to request handler * refactor: move property to upper interface * fix: set server address * refactor: revert logging change * refactor: simplify `getServerAddress` method
1 parent 478d431 commit fa811f2

File tree

7 files changed

+260
-119
lines changed

7 files changed

+260
-119
lines changed

packages/dev/src/main.ts

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,6 @@ export interface Features {
8282
enabled?: boolean
8383
}
8484

85-
/**
86-
* If your local development setup has its own HTTP server (e.g. Vite), set
87-
* its address here.
88-
*/
89-
serverAddress?: string
90-
9185
/**
9286
* Configuration options for serving static files.
9387
*/
@@ -107,6 +101,12 @@ interface NetlifyDevOptions extends Features {
107101
apiToken?: string
108102
logger?: Logger
109103
projectRoot?: string
104+
105+
/**
106+
* If your local development setup has its own HTTP server (e.g. Vite), set
107+
* its address here.
108+
*/
109+
serverAddress?: string | null
110110
}
111111

112112
const notFoundHandler = async () => new Response('Not found', { status: 404 })
@@ -121,6 +121,13 @@ interface HandleOptions {
121121
* {@link} https://docs.netlify.com/routing/headers/
122122
*/
123123
headersCollector?: HeadersCollector
124+
125+
/**
126+
* If your local development setup has its own HTTP server (e.g. Vite), you
127+
* can supply its address here. It will override any value defined in the
128+
* top-level `serverAddress` setting.
129+
*/
130+
serverAddress?: string
124131
}
125132

126133
export type ResponseType = 'edge-function' | 'function' | 'image' | 'redirect' | 'static'
@@ -149,7 +156,7 @@ export class NetlifyDev {
149156
#logger: Logger
150157
#projectRoot: string
151158
#redirectsHandler?: RedirectsHandler
152-
#server?: string | HTTPServer
159+
#serverAddress?: string | null
153160
#siteID?: string
154161
#staticHandler?: StaticHandler
155162
#staticHandlerAdditionalDirectories: string[]
@@ -178,11 +185,23 @@ export class NetlifyDev {
178185
}
179186
this.#functionsServePath = path.join(projectRoot, '.netlify', 'functions-serve')
180187
this.#logger = options.logger ?? globalThis.console
181-
this.#server = options.serverAddress
188+
this.#serverAddress = options.serverAddress
182189
this.#projectRoot = projectRoot
183190
this.#staticHandlerAdditionalDirectories = options.staticFiles?.directories ?? []
184191
}
185192

193+
private getServerAddress(requestServerAddress?: string) {
194+
if (requestServerAddress) {
195+
return requestServerAddress
196+
}
197+
198+
if (typeof this.#serverAddress === 'string') {
199+
return this.#serverAddress
200+
}
201+
202+
throw new Error('Server address is not defined')
203+
}
204+
186205
/**
187206
* Runs a request through the Netlify request chain and returns a `Response`
188207
* if there's a match. We must not disturb the incoming request unless we
@@ -202,6 +221,8 @@ export class NetlifyDev {
202221
destPath: string,
203222
options: HandleOptions = {},
204223
): Promise<{ response: Response; type: ResponseType } | undefined> {
224+
const serverAddress = this.getServerAddress(options.serverAddress)
225+
205226
// Try to match the request against the different steps in our request chain.
206227
//
207228
// https://docs.netlify.com/platform/request-chain/
@@ -211,15 +232,15 @@ export class NetlifyDev {
211232
const edgeFunctionMatch = await this.#edgeFunctionsHandler?.match(readRequest)
212233
if (edgeFunctionMatch) {
213234
return {
214-
response: await edgeFunctionMatch.handle(getWriteRequest()),
235+
response: await edgeFunctionMatch.handle(getWriteRequest(), serverAddress),
215236
type: 'edge-function',
216237
}
217238
}
218239

219240
// 2. Check if the request matches an image.
220241
const imageMatch = this.#imageHandler?.match(readRequest)
221242
if (imageMatch) {
222-
const response = await imageMatch.handle()
243+
const response = await imageMatch.handle(serverAddress)
223244
return { response, type: 'image' }
224245
}
225246

@@ -251,7 +272,7 @@ export class NetlifyDev {
251272
// If the redirect rule matches Image CDN, we'll serve it.
252273
const imageMatch = this.#imageHandler?.match(redirectRequest)
253274
if (imageMatch) {
254-
const response = await imageMatch.handle()
275+
const response = await imageMatch.handle(serverAddress)
255276
return { response, type: 'image' }
256277
}
257278

@@ -403,9 +424,9 @@ export class NetlifyDev {
403424
// If a custom server has been provided, use it. If not, we must stand up
404425
// a new one, since it's required for communication with edge functions
405426
// and local images support for Image CDN.
406-
if (typeof this.#server === 'string') {
407-
serverAddress = this.#server
408-
} else if (this.#features.edgeFunctions || this.#features.images) {
427+
if (typeof this.#serverAddress === 'string') {
428+
serverAddress = this.#serverAddress
429+
} else if (this.#serverAddress !== null && (this.#features.edgeFunctions || this.#features.images)) {
409430
const passthroughServer = new HTTPServer(async (req) => {
410431
const res = await this.handle(req)
411432

@@ -415,6 +436,7 @@ export class NetlifyDev {
415436
this.#cleanupJobs.push(() => passthroughServer.stop())
416437

417438
serverAddress = await passthroughServer.start()
439+
this.#serverAddress = serverAddress
418440
}
419441

420442
let envVariables: Record<string, InjectedEnvironmentVariable> = {}
@@ -430,7 +452,7 @@ export class NetlifyDev {
430452
})
431453
}
432454

433-
if (this.#features.edgeFunctions && serverAddress !== undefined) {
455+
if (this.#features.edgeFunctions) {
434456
const env = Object.entries(envVariables).reduce<Record<string, string>>((acc, [key, variable]) => {
435457
if (
436458
variable.usedSource === 'account' ||
@@ -454,7 +476,6 @@ export class NetlifyDev {
454476
env,
455477
geolocation: mockLocation,
456478
logger: this.#logger,
457-
originServerAddress: serverAddress,
458479
siteID,
459480
siteName: config?.siteInfo.name,
460481
})
@@ -511,7 +532,6 @@ export class NetlifyDev {
511532
this.#imageHandler = new ImageHandler({
512533
imagesConfig: this.#config?.config.images,
513534
logger: this.#logger,
514-
originServerAddress: serverAddress,
515535
})
516536
}
517537

packages/edge-functions/dev/node/main.test.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ describe('`EdgeFunctionsHandler`', () => {
6464
},
6565
geolocation,
6666
logger: console,
67-
originServerAddress: serverAddress,
6867
siteID: '123',
6968
siteName: 'test',
7069
})
@@ -75,7 +74,7 @@ describe('`EdgeFunctionsHandler`', () => {
7574
const match = await handler.match(req)
7675
expect(match).toBeTruthy()
7776

78-
const res = await match?.handle(req)
77+
const res = await match?.handle(req, serverAddress)
7978

8079
expect(await res?.json()).toStrictEqual({
8180
env: { VAR_1: 'value1', VAR_2: 'value2' },
@@ -126,7 +125,6 @@ describe('`EdgeFunctionsHandler`', () => {
126125
},
127126
geolocation,
128127
logger: console,
129-
originServerAddress: serverAddress,
130128
siteID: '123',
131129
siteName: 'test',
132130
})
@@ -137,7 +135,7 @@ describe('`EdgeFunctionsHandler`', () => {
137135
const match = await handler.match(req)
138136
expect(match).toBeTruthy()
139137

140-
const res = await match?.handle(req)
138+
const res = await match?.handle(req, serverAddress)
141139

142140
expect(await res?.text()).toStrictEqual('FROM ORIGIN')
143141

@@ -179,7 +177,6 @@ describe('`EdgeFunctionsHandler`', () => {
179177
},
180178
geolocation,
181179
logger: console,
182-
originServerAddress: serverAddress,
183180
siteID: '123',
184181
siteName: 'test',
185182
})
@@ -190,7 +187,7 @@ describe('`EdgeFunctionsHandler`', () => {
190187
const match = await handler.match(req)
191188
expect(match).toBeTruthy()
192189

193-
const res = await match?.handle(req)
190+
const res = await match?.handle(req, serverAddress)
194191

195192
expect(await res?.json()).toStrictEqual({
196193
slug: 'hello-world',
@@ -223,7 +220,6 @@ describe('`EdgeFunctionsHandler`', () => {
223220
geolocation,
224221
logger: console,
225222
requestTimeout: 1_000,
226-
originServerAddress: serverAddress,
227223
siteID: '123',
228224
siteName: 'test',
229225
})
@@ -234,7 +230,7 @@ describe('`EdgeFunctionsHandler`', () => {
234230
const match = await handler.match(req)
235231
expect(match).toBeTruthy()
236232

237-
const res = await match?.handle(req)
233+
const res = await match?.handle(req, serverAddress)
238234

239235
expect(res?.status).toBe(500)
240236
expect(await res?.text()).toContain('Failed to parse edge function `unparseable`')
@@ -269,7 +265,6 @@ describe('`EdgeFunctionsHandler`', () => {
269265
geolocation,
270266
logger: console,
271267
requestTimeout: 1_000,
272-
originServerAddress: serverAddress,
273268
siteID: '123',
274269
siteName: 'test',
275270
})
@@ -280,7 +275,7 @@ describe('`EdgeFunctionsHandler`', () => {
280275
const match = await handler.match(req)
281276
expect(match).toBeTruthy()
282277

283-
const res = await match?.handle(req)
278+
const res = await match?.handle(req, serverAddress)
284279

285280
expect(res?.status).toBe(500)
286281
expect(await res?.text()).toContain('An edge function took too long to produce a response')

packages/edge-functions/dev/node/main.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ interface EdgeFunctionsHandlerOptions {
2323
env: Record<string, string>
2424
geolocation: Geolocation
2525
logger: Logger
26-
originServerAddress: string
2726
requestTimeout?: number
2827
siteID?: string
2928
siteName?: string
@@ -52,7 +51,6 @@ export class EdgeFunctionsHandler {
5251
private initialization: ReturnType<typeof this.initialize>
5352
private initialized: boolean
5453
private logger: Logger
55-
private originServerAddress: string
5654
private requestTimeout: number
5755
private siteID?: string
5856
private siteName?: string
@@ -67,7 +65,6 @@ export class EdgeFunctionsHandler {
6765
})
6866
this.initialized = false
6967
this.logger = options.logger
70-
this.originServerAddress = options.originServerAddress
7168
this.requestTimeout = options.requestTimeout ?? REQUEST_TIMEOUT
7269
this.siteID = options.siteID
7370
this.siteName = options.siteName
@@ -211,8 +208,8 @@ export class EdgeFunctionsHandler {
211208
}
212209

213210
return {
214-
handle: async (request: Request) => {
215-
const originURL = new URL(this.originServerAddress)
211+
handle: async (request: Request, originServerAddress: string) => {
212+
const originURL = new URL(originServerAddress)
216213

217214
const url = new URL(request.url)
218215
url.hostname = LOCAL_HOST
@@ -236,7 +233,7 @@ export class EdgeFunctionsHandler {
236233
const site = {
237234
id: this.siteID,
238235
name: this.siteName,
239-
url: this.originServerAddress,
236+
url: originServerAddress,
240237
}
241238

242239
request.headers.set(headers.Site, base64Encode(site))

0 commit comments

Comments
 (0)