Skip to content

Commit fb49bea

Browse files
committed
introduce netlify adapter context for reusable helpers
1 parent ef37f11 commit fb49bea

File tree

8 files changed

+57
-60
lines changed

8 files changed

+57
-60
lines changed

src/adapter/adapter.ts

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ import {
1010
onBuildComplete as onBuildCompleteForImageCDN,
1111
} from './build/image-cdn.js'
1212
import { onBuildComplete as onBuildCompleteForMiddleware } from './build/middleware.js'
13+
import { createNetlifyAdapterContext } from './build/netlify-adapter-context.js'
1314
import { onBuildComplete as onBuildCompleteForPagesAndAppHandlers } from './build/pages-and-app-handlers.js'
1415
import { onBuildComplete as onBuildCompleteForStaticAssets } from './build/static-assets.js'
15-
import { NETLIFY_FRAMEWORKS_API_CONFIG_PATH } from './build/constants.js'
16-
import { FrameworksAPIConfig } from './build/types.js'
1716

1817
const adapter: NextAdapter = {
1918
name: 'Netlify',
@@ -34,30 +33,21 @@ const adapter: NextAdapter = {
3433

3534
console.log('onBuildComplete hook called')
3635

37-
let frameworksAPIConfig: FrameworksAPIConfig = null
36+
const netlifyAdapterContext = createNetlifyAdapterContext(nextAdapterContext)
3837

39-
frameworksAPIConfig = onBuildCompleteForImageCDN(nextAdapterContext, frameworksAPIConfig)
40-
frameworksAPIConfig = await onBuildCompleteForMiddleware(
41-
nextAdapterContext,
42-
frameworksAPIConfig,
43-
)
44-
frameworksAPIConfig = await onBuildCompleteForStaticAssets(
45-
nextAdapterContext,
46-
frameworksAPIConfig,
47-
)
38+
await onBuildCompleteForImageCDN(nextAdapterContext, netlifyAdapterContext)
39+
await onBuildCompleteForMiddleware(nextAdapterContext, netlifyAdapterContext)
40+
await onBuildCompleteForStaticAssets(nextAdapterContext, netlifyAdapterContext)
4841
// TODO: verifyNetlifyForms
49-
frameworksAPIConfig = onBuildCompleteForHeaders(nextAdapterContext, frameworksAPIConfig)
50-
frameworksAPIConfig = await onBuildCompleteForPagesAndAppHandlers(
51-
nextAdapterContext,
52-
frameworksAPIConfig,
53-
)
42+
await onBuildCompleteForHeaders(nextAdapterContext, netlifyAdapterContext)
43+
await onBuildCompleteForPagesAndAppHandlers(nextAdapterContext, netlifyAdapterContext)
5444

55-
if (frameworksAPIConfig) {
45+
if (netlifyAdapterContext.frameworksAPIConfig) {
5646
// write out config if there is any
5747
await mkdir(dirname(NETLIFY_FRAMEWORKS_API_CONFIG_PATH), { recursive: true })
5848
await writeFile(
5949
NETLIFY_FRAMEWORKS_API_CONFIG_PATH,
60-
JSON.stringify(frameworksAPIConfig, null, 2),
50+
JSON.stringify(netlifyAdapterContext.frameworksAPIConfig, null, 2),
6151
)
6252
}
6353
},

src/adapter/build/header.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import type { FrameworksAPIConfig, OnBuildCompleteContext } from './types.js'
1+
import type { NetlifyAdapterContext, OnBuildCompleteContext } from './types.js'
22

3-
export function onBuildComplete(
3+
export async function onBuildComplete(
44
nextAdapterContext: OnBuildCompleteContext,
5-
frameworksAPIConfigArg: FrameworksAPIConfig,
5+
netlifyAdapterContext: NetlifyAdapterContext,
66
) {
7-
const frameworksAPIConfig: FrameworksAPIConfig = frameworksAPIConfigArg ?? {}
7+
netlifyAdapterContext.frameworksAPIConfig ??= {}
8+
netlifyAdapterContext.frameworksAPIConfig.headers ??= []
89

9-
frameworksAPIConfig.headers ??= []
10-
11-
frameworksAPIConfig.headers.push({
10+
netlifyAdapterContext.frameworksAPIConfig.headers.push({
1211
for: `${nextAdapterContext.config.basePath}/_next/static/*`,
1312
values: {
1413
'Cache-Control': 'public, max-age=31536000, immutable',
@@ -23,6 +22,4 @@ export function onBuildComplete(
2322
// }
2423
// per https://docs.netlify.com/manage/routing/headers/#wildcards-and-placeholders-in-paths
2524
// this is example of something we can't currently do
26-
27-
return frameworksAPIConfig
2825
}

src/adapter/build/image-cdn.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { fileURLToPath } from 'node:url'
33
import type { RemotePattern } from 'next-with-adapters/dist/shared/lib/image-config.js'
44
import { makeRe } from 'picomatch'
55

6-
import type { FrameworksAPIConfig, NextConfigComplete, OnBuildCompleteContext } from './types.js'
6+
import type { NetlifyAdapterContext, NextConfigComplete, OnBuildCompleteContext } from './types.js'
77

88
const NETLIFY_IMAGE_LOADER_FILE = fileURLToPath(
99
import.meta.resolve(`./image-cdn-next-image-loader.cjs`),
@@ -22,15 +22,15 @@ function generateRegexFromPattern(pattern: string): string {
2222
return makeRe(pattern).source
2323
}
2424

25-
export function onBuildComplete(
25+
export async function onBuildComplete(
2626
nextAdapterContext: OnBuildCompleteContext,
27-
frameworksAPIConfigArg: FrameworksAPIConfig,
27+
netlifyAdapterContext: NetlifyAdapterContext,
2828
) {
29-
const frameworksAPIConfig: FrameworksAPIConfig = frameworksAPIConfigArg ?? {}
29+
netlifyAdapterContext.frameworksAPIConfig ??= {}
3030

3131
// when migrating from @netlify/plugin-nextjs@4 image redirect to ipx might be cached in the browser
32-
frameworksAPIConfig.redirects ??= []
33-
frameworksAPIConfig.redirects.push({
32+
netlifyAdapterContext.frameworksAPIConfig.redirects ??= []
33+
netlifyAdapterContext.frameworksAPIConfig.redirects.push({
3434
from: '/_ipx/*',
3535
// w and q are too short to be used as params with id-length rule
3636
// but we are forced to do so because of the next/image loader decides on their names
@@ -100,9 +100,8 @@ export function onBuildComplete(
100100

101101
if (remoteImageSources.length !== 0) {
102102
// https://docs.netlify.com/build/frameworks/frameworks-api/#images
103-
frameworksAPIConfig.images ??= { remote_images: [] }
104-
frameworksAPIConfig.images.remote_images = remoteImageSources
103+
netlifyAdapterContext.frameworksAPIConfig.images ??= { remote_images: [] }
104+
netlifyAdapterContext.frameworksAPIConfig.images.remote_images = remoteImageSources
105105
}
106106
}
107-
return frameworksAPIConfig
108107
}

src/adapter/build/middleware.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
NETLIFY_FRAMEWORKS_API_EDGE_FUNCTIONS,
1111
PLUGIN_DIR,
1212
} from './constants.js'
13-
import type { FrameworksAPIConfig, NextConfigComplete, OnBuildCompleteContext } from './types.js'
13+
import type { NetlifyAdapterContext, NextConfigComplete, OnBuildCompleteContext } from './types.js'
1414

1515
const MIDDLEWARE_FUNCTION_INTERNAL_NAME = 'next_middleware'
1616

@@ -21,25 +21,21 @@ const MIDDLEWARE_FUNCTION_DIR = join(
2121

2222
export async function onBuildComplete(
2323
nextAdapterContext: OnBuildCompleteContext,
24-
frameworksAPIConfigArg: FrameworksAPIConfig,
24+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
25+
_netlifyAdapterContext: NetlifyAdapterContext,
2526
) {
26-
const frameworksAPIConfig: FrameworksAPIConfig = frameworksAPIConfigArg ?? {}
27-
2827
const { middleware } = nextAdapterContext.outputs
2928
if (!middleware) {
30-
return frameworksAPIConfig
29+
return
3130
}
3231

3332
if (middleware.runtime === 'edge') {
3433
await copyHandlerDependenciesForEdgeMiddleware(middleware)
3534
} else if (middleware.runtime === 'nodejs') {
36-
// return frameworksAPIConfig
3735
await copyHandlerDependenciesForNodeMiddleware(middleware, nextAdapterContext.repoRoot)
3836
}
3937

4038
await writeHandlerFile(middleware, nextAdapterContext.config)
41-
42-
return frameworksAPIConfig
4339
}
4440

4541
const copyHandlerDependenciesForEdgeMiddleware = async (
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { readFile } from 'fs/promises'
2+
import { join } from 'path/posix'
3+
4+
import type { FrameworksAPIConfig, OnBuildCompleteContext } from './types.js'
5+
6+
export function createNetlifyAdapterContext(nextAdapterContext: OnBuildCompleteContext) {
7+
let buildId: string | undefined
8+
let frameworksAPIConfig: FrameworksAPIConfig | undefined
9+
10+
return {
11+
async getBuildId() {
12+
if (!buildId) {
13+
buildId = await readFile(join(nextAdapterContext.distDir, 'BUILD_ID'), 'utf-8')
14+
}
15+
return buildId
16+
},
17+
frameworksAPIConfig,
18+
}
19+
}

src/adapter/build/pages-and-app-handlers.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
NETLIFY_FRAMEWORKS_API_FUNCTIONS,
1010
PLUGIN_DIR,
1111
} from './constants.js'
12-
import type { FrameworksAPIConfig, OnBuildCompleteContext } from './types.js'
12+
import type { NetlifyAdapterContext, OnBuildCompleteContext } from './types.js'
1313

1414
const PAGES_AND_APP_FUNCTION_INTERNAL_NAME = 'next_pages_and_app'
1515

@@ -22,10 +22,9 @@ const PAGES_AND_APP_FUNCTION_DIR = join(
2222

2323
export async function onBuildComplete(
2424
nextAdapterContext: OnBuildCompleteContext,
25-
frameworksAPIConfigArg: FrameworksAPIConfig,
25+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
26+
_netlifyAdapterContext: NetlifyAdapterContext,
2627
) {
27-
const frameworksAPIConfig: FrameworksAPIConfig = frameworksAPIConfigArg ?? {}
28-
2928
const requiredFiles = new Set<string>()
3029
const pathnameToEntry: Record<string, string> = {}
3130

@@ -129,8 +128,6 @@ export async function onBuildComplete(
129128
2,
130129
),
131130
)
132-
133-
return frameworksAPIConfig
134131
}
135132

136133
const copyRuntime = async (handlerDirectory: string): Promise<void> => {

src/adapter/build/static-assets.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,25 @@
11
import { existsSync } from 'node:fs'
2-
import { cp, mkdir, readFile, writeFile } from 'node:fs/promises'
2+
import { cp, mkdir, writeFile } from 'node:fs/promises'
33
import { dirname, extname, join } from 'node:path/posix'
44

55
import { NEXT_RUNTIME_STATIC_ASSETS } from './constants.js'
6-
import type { FrameworksAPIConfig, OnBuildCompleteContext } from './types.js'
6+
import type { NetlifyAdapterContext, OnBuildCompleteContext } from './types.js'
77

88
export async function onBuildComplete(
99
nextAdapterContext: OnBuildCompleteContext,
10-
frameworksAPIConfigArg: FrameworksAPIConfig,
10+
netlifyAdapterContext: NetlifyAdapterContext,
1111
) {
12-
const frameworksAPIConfig: FrameworksAPIConfig = frameworksAPIConfigArg ?? {}
13-
1412
for (const staticFile of nextAdapterContext.outputs.staticFiles) {
1513
try {
1614
let distPathname = staticFile.pathname
1715
if (extname(distPathname) === '' && extname(staticFile.filePath) === '.html') {
1816
// if it's fully static page, we need to also create empty _next/data JSON file
1917
// on Vercel this is done in routing layer, but we can't express that routing right now on Netlify
20-
const buildID = await readFile(join(nextAdapterContext.distDir, 'BUILD_ID'), 'utf-8')
2118
const dataFilePath = join(
2219
NEXT_RUNTIME_STATIC_ASSETS,
2320
'_next',
2421
'data',
25-
buildID,
22+
await netlifyAdapterContext.getBuildId(),
2623
// eslint-disable-next-line unicorn/no-nested-ternary
2724
`${distPathname === '/' ? 'index' : distPathname.endsWith('/') ? distPathname.slice(0, -1) : distPathname}.json`,
2825
)
@@ -59,6 +56,4 @@ export async function onBuildComplete(
5956
recursive: true,
6057
})
6158
}
62-
63-
return frameworksAPIConfig
6459
}

src/adapter/build/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import type { NetlifyConfig } from '@netlify/build'
22
import type { NextAdapter } from 'next-with-adapters'
33

4+
import type { createNetlifyAdapterContext } from './netlify-adapter-context.js'
5+
46
export type OnBuildCompleteContext = Parameters<Required<NextAdapter>['onBuildComplete']>[0]
57
export type NextConfigComplete = OnBuildCompleteContext['config']
68

79
export type FrameworksAPIConfig = Partial<
810
Pick<NetlifyConfig, 'edge_functions' | 'functions' | 'headers' | 'redirects' | 'images'>
911
> | null
12+
13+
export type NetlifyAdapterContext = ReturnType<typeof createNetlifyAdapterContext>

0 commit comments

Comments
 (0)