Skip to content

Commit a38800f

Browse files
authored
Merge pull request #8 from netlify/rs/none-bundler
feat: use none bundler and node_modules created at build time
2 parents 373b8b4 + 2d9d9d6 commit a38800f

File tree

10 files changed

+73
-554
lines changed

10 files changed

+73
-554
lines changed

package-lock.json

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"@netlify/blobs": "^1.6.0",
3838
"@netlify/build": "^29.20.6",
3939
"@netlify/functions": "^2.0.1",
40+
"@vercel/node-bridge": "^3.1.14",
4041
"fs-extra": "^11.1.1",
4142
"next": "^13.4.16"
4243
},

src/helpers/config.ts

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
1+
import type { NetlifyConfig } from '@netlify/build'
12
import { copySync, moveSync } from 'fs-extra/esm'
23

3-
import { __dirname } from './constants.js'
4+
import { __dirname, NETLIFY_PUBLISH_DIR } from './constants.js'
45

5-
export const overrideNextJsConfig = () => {
6-
copySync('next.config.js', '.netlify/next.config.js', { overwrite: true })
6+
/**
7+
* Modify the user's next.config.js to use standalone mode
8+
*/
9+
export const modifyNextConfig = () => {
10+
moveSync('next.config.js', 'next.config.js.orig')
711
copySync(`${__dirname}/../templates/next.config.cjs`, 'next.config.js')
812
}
913

10-
export const revertNextJsConfig = () => {
11-
moveSync('.netlify/next.config.js', 'next.config.js', { overwrite: true })
14+
export const revertNextConfig = () => {
15+
moveSync('next.config.js.orig', 'next.config.js', { overwrite: true })
16+
}
17+
18+
/**
19+
* Modify the user's netlify.toml to use our new publish directory
20+
* @param config Netlify config
21+
*/
22+
export const modifyNetlifyConfig = (config: NetlifyConfig) => {
23+
config.build.publish = NETLIFY_PUBLISH_DIR
1224
}

src/helpers/constants.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ import { fileURLToPath } from 'node:url'
22

33
export const __dirname = fileURLToPath(new URL('.', import.meta.url))
44

5-
export const PUBLISH_STAGING_DIR = '.netlify/publish'
5+
export const NETLIFY_PUBLISH_DIR = '.netlify/publish'
6+
67
export const FUNCTIONS_INTERNAL_DIR = '.netlify/functions-internal'
78
export const FUNCTIONS_URL = '/.netlify/functions'
9+
10+
export const HANDLER_NAME = '___netlify-handler'
11+
export const HANDLER_DIR = `${FUNCTIONS_INTERNAL_DIR}/${HANDLER_NAME}`
12+
export const HANDLER_URL = `${FUNCTIONS_URL}/${HANDLER_NAME}`

src/helpers/files.ts

+11-19
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,19 @@
11
import { existsSync } from 'node:fs'
22

3-
import { copySync, moveSync } from 'fs-extra/esm'
3+
import { copySync } from 'fs-extra/esm'
44

5-
import { PUBLISH_STAGING_DIR } from './constants.js'
5+
import { NETLIFY_PUBLISH_DIR } from './constants.js'
66

7-
const stageStaticAssets = (publishDir: string) => {
8-
// TODO: consider caching here to avoid copying on every build
7+
/**
8+
* Ensure static assets get uploaded to the Netlify CDN
9+
* @param publishDir The publish directory
10+
*/
11+
export const publishStaticAssets = (publishDir: string) => {
12+
// copy user's public folder to the new publish directory
913
if (existsSync('public')) {
10-
copySync('public', PUBLISH_STAGING_DIR, { overwrite: true })
14+
copySync('public', NETLIFY_PUBLISH_DIR, { overwrite: true })
1115
}
12-
copySync(`${publishDir}/static/`, `${PUBLISH_STAGING_DIR}/_next/static`, { overwrite: true })
13-
}
14-
15-
const promoteStaticAssets = (publishDir: string) => {
16-
moveSync(publishDir, '.netlify/.next', { overwrite: true })
17-
moveSync(PUBLISH_STAGING_DIR, publishDir, { overwrite: true })
18-
}
19-
20-
export const publishStaticAssets = (publishDir: string) => {
21-
stageStaticAssets(publishDir)
22-
promoteStaticAssets(publishDir)
23-
}
2416

25-
export const revertStaticAssets = (publishDir: string) => {
26-
moveSync('.netlify/.next', publishDir, { overwrite: true })
17+
// copy the Next.js static assets to the new publish directory
18+
copySync(`${publishDir}/static/`, `${NETLIFY_PUBLISH_DIR}/_next/static`, { overwrite: true })
2719
}

src/helpers/functions.ts

+19-23
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,30 @@
1-
import type { NetlifyConfig } from '@netlify/build'
2-
import { copySync } from 'fs-extra/esm'
1+
import { NetlifyConfig } from '@netlify/build'
2+
import { copySync, emptyDirSync } from 'fs-extra/esm'
33

4-
import { FUNCTIONS_INTERNAL_DIR, FUNCTIONS_URL, __dirname } from './constants.js'
4+
import { HANDLER_DIR, HANDLER_NAME, HANDLER_URL, __dirname } from './constants.js'
55

6-
const HANDLER_NAME = '___netlify-handler'
7-
const HANDLER_DIR = `${FUNCTIONS_INTERNAL_DIR}/${HANDLER_NAME}`
8-
const HANDLER_URL = `${FUNCTIONS_URL}/${HANDLER_NAME}`
6+
/**
7+
* Create a Netlify function to run the Next.js server
8+
* @param publishDir The publish directory
9+
* @param config Netlify config
10+
*/
11+
export const createHandlerFunction = (publishDir: string, config: NetlifyConfig) => {
12+
emptyDirSync(HANDLER_DIR)
913

10-
const moveServerFiles = (publishDir: string) => {
11-
// TODO: consider caching here to avoid copying on every build
12-
// TODO: consider basepaths and monorepos, etc.
13-
// TODO: ensure functions internal dir is empty
14-
copySync(`${publishDir}/standalone/.next`, `${HANDLER_DIR}/.next`, { overwrite: true })
15-
copySync(`${__dirname}/../templates/handler.cjs`, `${HANDLER_DIR}/${HANDLER_NAME}.js`, { overwrite: true })
16-
copySync(`${__dirname}/../templates/bridge.cjs`, `${HANDLER_DIR}/bridge.js`, { overwrite: true })
17-
}
14+
copySync(`${__dirname}/../templates/handler.cjs`, `${HANDLER_DIR}/${HANDLER_NAME}.js`)
15+
copySync(`${__dirname}/../../node_modules/@vercel/node-bridge`, `${HANDLER_DIR}/node_modules/@vercel/node-bridge`)
16+
copySync(`${publishDir}/standalone/.next`, `${HANDLER_DIR}/.next`)
17+
copySync(`${publishDir}/standalone/node_modules`, `${HANDLER_DIR}/node_modules`)
18+
19+
// all the following will be replaced by the upcoming serverless functions API
1820

19-
const configureHandlerFunction = (config: NetlifyConfig) => {
2021
config.functions[HANDLER_NAME] ||= {}
22+
config.functions[HANDLER_NAME].node_bundler = 'none'
2123
config.functions[HANDLER_NAME].included_files ||= []
24+
config.functions[HANDLER_NAME].included_files.push(`${HANDLER_DIR}/${HANDLER_NAME}.js`)
2225
config.functions[HANDLER_NAME].included_files.push(`${HANDLER_DIR}/.next/**/*`)
23-
}
26+
config.functions[HANDLER_NAME].included_files.push(`${HANDLER_DIR}/node_modules/**/*`)
2427

25-
const addCatchAllRedirect = (config: NetlifyConfig) => {
2628
config.redirects ||= []
2729
config.redirects.push({ from: `/*`, to: HANDLER_URL, status: 200 })
2830
}
29-
30-
export const createHandlerFunction = (publishDir: string, config: NetlifyConfig) => {
31-
moveServerFiles(publishDir)
32-
configureHandlerFunction(config)
33-
addCatchAllRedirect(config)
34-
}

src/index.ts

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
import type { NetlifyPluginOptions } from '@netlify/build'
22

3-
import { overrideNextJsConfig, revertNextJsConfig } from './helpers/config.js'
3+
import { modifyNetlifyConfig, modifyNextConfig, revertNextConfig } from './helpers/config.js'
44
import { publishStaticAssets } from './helpers/files.js'
55
import { createHandlerFunction } from './helpers/functions.js'
66

77
type NetlifyPluginOptionsWithFlags = NetlifyPluginOptions & { featureFlags?: Record<string, unknown> }
88

99
export const onPreBuild = () => {
10-
overrideNextJsConfig()
10+
modifyNextConfig()
1111
}
1212

1313
export const onBuild = ({ constants, netlifyConfig }: NetlifyPluginOptionsWithFlags) => {
14-
createHandlerFunction(constants.PUBLISH_DIR, netlifyConfig)
1514
publishStaticAssets(constants.PUBLISH_DIR)
15+
createHandlerFunction(constants.PUBLISH_DIR, netlifyConfig)
16+
modifyNetlifyConfig(netlifyConfig)
1617
}
1718

1819
export const onEnd = () => {
19-
// TODO: call revertStaticAssets when we figure out
20-
// why onEnd is called before the deploy finishes
21-
revertNextJsConfig()
20+
revertNextConfig()
2221
}

0 commit comments

Comments
 (0)