Skip to content

Commit

Permalink
feat: use async fs methods
Browse files Browse the repository at this point in the history
  • Loading branch information
orinokai committed Oct 15, 2023
1 parent a7f1588 commit ecd9460
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 36 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
max_line_length = 120
max_line_length = 100
trim_trailing_whitespace = true
insert_final_newline = true
3 changes: 2 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ module.exports = {
sourceType: 'module',
},
rules: {
'arrow-body-style': 'off',
'no-param-reassign': ['error', { props: false }],
'no-underscore-dangle': 'off',
'no-magic-numbers': 'off',
'n/no-sync': 'off',
'n/prefer-global/process': 'off',
'no-magic-numbers': 'off',
'unicorn/numeric-separators-style': 'off',
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
'import/no-namespace': 'off',
Expand Down
4 changes: 4 additions & 0 deletions .prettierrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
...require('@netlify/eslint-config-node/.prettierrc.json'),
printWidth: 100,
}
1 change: 0 additions & 1 deletion .prettierrc.json

This file was deleted.

5 changes: 3 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"@netlify/build": "^29.20.6",
"@netlify/functions": "^2.0.1",
"@vercel/nft": "^0.24.3",
"fs-extra": "^11.1.1"
"fs-extra": "^11.1.1",
"globby": "^13.2.2"
},
"devDependencies": {
"@netlify/eslint-config-node": "^7.0.1",
Expand Down
40 changes: 30 additions & 10 deletions src/helpers/files.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,43 @@
import { existsSync } from 'node:fs'

import { NetlifyPluginConstants } from '@netlify/build'
import { copySync, moveSync } from 'fs-extra/esm'
import { copy, move, remove } from 'fs-extra/esm'
import { globby } from 'globby'

import { BUILD_DIR } from './constants.js'

/**
* Move the Next.js build output from the publish dir to a temp dir
*/
export const stashBuildOutput = ({ PUBLISH_DIR }: NetlifyPluginConstants) => {
moveSync(PUBLISH_DIR, BUILD_DIR, { overwrite: true })
export const stashBuildOutput = async ({ PUBLISH_DIR }: NetlifyPluginConstants) => {
await move(PUBLISH_DIR, BUILD_DIR, { overwrite: true })

// remove prerendered content from the standalone build (it's also in the main build dir)
await Promise.all(
getPrerenderedContent(`${BUILD_DIR}/standalone/`).map((filename: string) => remove(filename)),
)
}

/**
* Glob for prerendered content in the build output
*/
const getPrerenderedContent = (cwd: string): string[] => {
// TODO: test this
// return globby('**/*.+(html|json|rsc|body|meta)', { cwd, extglob: true })
return []
}

/**
* Upload prerendered content from the main build dir to the blob store
*/
export const storePrerenderedContent = () => {
// TODO: implement
}

/**
* Move static assets to the publish dir so they upload to the CDN
* Move static assets to the publish dir so they are uploaded to the CDN
*/
export const publishStaticAssets = ({ PUBLISH_DIR }: NetlifyPluginConstants) => {
if (existsSync('public')) {
copySync('public', PUBLISH_DIR)
}
copySync(`${BUILD_DIR}/static/`, `${PUBLISH_DIR}/_next/static`)
return Promise.all([
copy('public', PUBLISH_DIR),
copy(`${BUILD_DIR}/static/`, `${PUBLISH_DIR}/_next/static`),
])
}
37 changes: 22 additions & 15 deletions src/helpers/functions.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,58 @@
import { writeFileSync } from 'fs'
import { writeFile } from 'fs/promises'

import { nodeFileTrace } from '@vercel/nft'
import { copySync, emptyDirSync, readJsonSync, writeJSONSync } from 'fs-extra/esm'
import { copy, emptyDir, ensureDir, readJson, writeJSON } from 'fs-extra/esm'

import { BUILD_DIR, SERVER_HANDLER_DIR, SERVER_HANDLER_NAME, PLUGIN_DIR } from './constants.js'

const pkg = readJsonSync(`${PLUGIN_DIR}/package.json`)
const pkg = await readJson(`${PLUGIN_DIR}/package.json`)

/**
* Create a Netlify function to run the Next.js server
*/
export const createServerHandler = async () => {
// clear the handler directory
emptyDirSync(SERVER_HANDLER_DIR)
// reset the handler directory
await emptyDir(SERVER_HANDLER_DIR)
await ensureDir(`${SERVER_HANDLER_DIR}/node_modules`)

// trace the handler dependencies
const { fileList } = await nodeFileTrace(
[`${PLUGIN_DIR}/dist/handlers/server.js`, `${PLUGIN_DIR}/dist/handlers/cache.cjs`],
{ base: PLUGIN_DIR, ignore: ['package.json', 'node_modules/next/**'] },
)

// copy the handler dependencies
fileList.forEach((path) => {
copySync(`${PLUGIN_DIR}/${path}`, `${SERVER_HANDLER_DIR}/${path}`)
})
await Promise.all(
// copy the handler dependencies
[...fileList].map((path) => copy(`${PLUGIN_DIR}/${path}`, `${SERVER_HANDLER_DIR}/${path}`)),
)

// copy the next.js standalone build output to the handler directory
copySync(`${BUILD_DIR}/standalone/.next`, `${SERVER_HANDLER_DIR}/.next`)
copySync(`${BUILD_DIR}/standalone/node_modules`, `${SERVER_HANDLER_DIR}/node_modules`)
await copy(`${BUILD_DIR}/standalone/.next`, `${SERVER_HANDLER_DIR}/.next`)
await copy(`${BUILD_DIR}/standalone/node_modules`, `${SERVER_HANDLER_DIR}/node_modules`)

// create the handler metadata file
writeJSONSync(`${SERVER_HANDLER_DIR}/${SERVER_HANDLER_NAME}.json`, {
await writeJSON(`${SERVER_HANDLER_DIR}/${SERVER_HANDLER_NAME}.json`, {
config: {
name: 'Next.js Server Handler',
generator: `${pkg.name}@${pkg.version}`,
nodeBundler: 'none',
includedFiles: [`${SERVER_HANDLER_NAME}*`, 'package.json', 'dist/**', '.next/**', 'node_modules/**'],
includedFiles: [
`${SERVER_HANDLER_NAME}*`,
'package.json',
'dist/**',
'.next/**',
'node_modules/**',
],
includedFilesBasePath: SERVER_HANDLER_DIR,
},
version: 1,
})

// configure ESM
writeFileSync(`${SERVER_HANDLER_DIR}/package.json`, JSON.stringify({ type: 'module' }))
await writeFile(`${SERVER_HANDLER_DIR}/package.json`, JSON.stringify({ type: 'module' }))

// write the root handler file
writeFileSync(
await writeFile(
`${SERVER_HANDLER_DIR}/${SERVER_HANDLER_NAME}.js`,
`import handler from './dist/handlers/server.js';export default handler;export const config = {path:'/*'}`,
)
Expand Down
16 changes: 11 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import type { NetlifyPluginOptions } from '@netlify/build'

import { setBuildConfig } from './helpers/config.js'
import { publishStaticAssets, stashBuildOutput } from './helpers/files.js'
import { stashBuildOutput, publishStaticAssets, storePrerenderedContent } from './helpers/files.js'
import { createServerHandler } from './helpers/functions.js'

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

export const onPreBuild = () => {
setBuildConfig()
}

export const onBuild = async ({ constants }: NetlifyPluginOptionsWithFlags) => {
stashBuildOutput(constants)
publishStaticAssets(constants)
await createServerHandler()
await stashBuildOutput(constants)

return Promise.all([
publishStaticAssets(constants),
storePrerenderedContent(),
createServerHandler(),
])
}

0 comments on commit ecd9460

Please sign in to comment.