Skip to content

Commit

Permalink
feat: use next-build-id as module within Next 6 generateBuildId funct…
Browse files Browse the repository at this point in the history
…ion (#6)

BREAKING CHANGE: The next-build-id CLI has not changed, but module usage will no longer manually overwrite a BUILD_ID file unless a `write: true` option is given, so that the module can be used within generateBuildId from next.config.js to just lookup the current git commit hash.
  • Loading branch information
nexdrew committed May 25, 2018
1 parent a127d9b commit 502bccc
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ test/fixture/nextoutput/
test/fixture/next.config.js
test/fixture2/.next/BUILD_ID
test/fixture-next5/build/
test/fixture-next6/.next/
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,29 @@

Simple CLI and module that lets you define your own build id when using Next.js.

This is necessary if you're running multiple instances of your Next.js app on different servers sitting behind a load balancer without session affinity. Otherwise, if your Next.js builds end up with different build ids, a client loading content from different servers can result in [this Next.js error](https://github.com/zeit/next.js/blob/52ccc14059673508803f96ef1c74eecdf27fe096/server/index.js#L444), which causes the app to blow up for that client.
## New in version 2!

When using Next.js 6+ (which introduced the [generateBuildId](https://github.com/zeit/next.js#configuring-the-build-id) config prop), you can use `next-build-id` as a module within your next.config.js logic to set the BUILD_ID to the most recent git commit hash. This approach means you don't need to use the `next-build-id` CLI - just use `next build` as normal and you'll get the build id you want!

```js
// next.config.js
const nextBuildId = require('next-build-id')
module.exports = {
generateBuildId: async () => {
const fromGit = await nextBuildId({ dir: __dirname })
return fromGit.id
}
}
```

## Intro

This tool is necessary if you're running multiple instances of your Next.js app on different servers sitting behind a load balancer without session affinity. Otherwise, if your Next.js builds end up with different build ids, a client loading content from different servers can result in [this Next.js error](https://github.com/zeit/next.js/blob/52ccc14059673508803f96ef1c74eecdf27fe096/server/index.js#L444), which causes the app to blow up for that client.

This module updates/overrides the following:

- uuid defined in `.next/BUILD_ID`
- hashes for all chunks defined in `.next/build-stats.json`
- hashes for all chunks defined in `.next/build-stats.json` (Next.js 4 or below)

By default, this CLI/module will overwrite those values with the hash of the latest git commit (`git rev-parse HEAD`), but it will also allow you to define your own id.

Expand Down Expand Up @@ -77,6 +94,7 @@ This module exports a single function that accepts an options object and returns
The options supported are:

- `dir` (string): the directory built by `next build`
- `write` (boolean): whether to overwrite the BUILD_ID in the dist dir (not needed when using `generateBuildId` in next.config.js)
- `id` (string): define a custom id instead of deferring to `git rev-parse HEAD`

The returned `Promise` resolves to a result object containing:
Expand All @@ -93,6 +111,7 @@ const nextBuildId = require('next-build-id')

const opts = {}
// opts.dir = '/path/to/input/dir'
// opts.write = true
// opts.id = 'my_custom_id'

nextBuildId(opts).then(result => {
Expand All @@ -108,6 +127,7 @@ nextBuildId(opts).then(result => {

## Reference

- [zeit/next.js#786](https://github.com/zeit/next.js/issues/786)
- [zeit/next.js#2978 (comment)](https://github.com/zeit/next.js/issues/2978#issuecomment-334849384)
- [zeit/next.js#3299 (comment)](https://github.com/zeit/next.js/issues/3299#issuecomment-344973091)
- ["Handle BUILD_ID Mismatch Error" on Next.js wiki](https://github.com/zeit/next.js/wiki/Handle-BUILD_ID-Mismatch-Error)
Expand Down
1 change: 1 addition & 0 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require('sywac')
.outputSettings({ maxWidth: 60 })
.parseAndExit()
.then(argv => {
argv.write = true
argv.dir = path.resolve(process.cwd(), argv.dir || '.')
const nextBuildId = require('./index')
return nextBuildId(argv)
Expand Down
12 changes: 6 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const defaultConfig = {
assetPrefix: '',
configOrigin: 'default',
useFileSystemPublicRoutes: true,
// generateBuildId: () => '9f2a37be-4545-445e-91bd-' + String(new Date().getTime()).slice(1, 13),
generateBuildId: () => '9f2a37be-4545-445e-91bd-' + String(new Date().getTime()).slice(1, 13),
generateEtags: true,
pageExtensions: ['jsx', 'js']
}
Expand All @@ -26,19 +26,19 @@ module.exports = function nextBuildId (opts) {
return resolveInputDir(opts.dir)
.then(inputDir => {
result.inputDir = inputDir
return resolveOutputDir(inputDir)
return opts.write && resolveOutputDir(inputDir)
})
.then(outputDir => {
result.outputDir = outputDir
return getFiles(outputDir)
result.outputDir = outputDir || null
return opts.write && getFiles(outputDir)
})
.then(files => {
result.files = files
result.files = files || null
return determineBuildId(opts.id, result.inputDir)
})
.then(id => {
result.id = id
return updateFiles(id, result.files)
return opts.write && updateFiles(id, result.files)
})
.then(() => result)
}
Expand Down
8 changes: 8 additions & 0 deletions test/fixture-next6/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const nextBuildId = require('../../index')

module.exports = (phase, nextConfig) => {
if (process.env.NBI_TEST_CALL_DEFAULT_GENERATEBUILDID) console.log(nextConfig.defaultConfig.generateBuildId())
return {
generateBuildId: () => nextBuildId({ dir: __dirname }).then(result => result.id)
}
}
17 changes: 17 additions & 0 deletions test/fixture-next6/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "fixture",
"version": "1.0.0",
"description": "Fixture to test against Next.js 6",
"private": true,
"main": "index.js",
"scripts": {
"build": "next build"
},
"author": "",
"license": "ISC",
"dependencies": {
"next": "^6.0.3",
"react": "^16.4.0",
"react-dom": "^16.4.0"
}
}
1 change: 1 addition & 0 deletions test/fixture-next6/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => <div>Welcome to next.js!</div>
58 changes: 58 additions & 0 deletions test/test-next6.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const path = require('path')

const tap = require('tap')
const rimraf = require('rimraf')

const utils = require('./utils')

const exec = utils.exec
const mockedGitEnv = utils.mockedGitEnv
const fixturePath = path.resolve(__dirname, 'fixture-next6')

let npmi = false
tap.beforeEach(() => {
if (npmi) return Promise.resolve()
npmi = true
return exec('npm', 'i', fixturePath)
})

tap.afterEach(() => {
return Promise.all(['.next'].map(dir => {
return new Promise((resolve, reject) => {
rimraf(path.resolve(fixturePath, dir), err => {
if (err) return reject(err)
resolve()
})
})
}))
})

tap.test('with next.config.js that uses a generateBuildId function', t => {
return exec('npm', 'run build', fixturePath, mockedGitEnv())
.then(io => {
t.notOk(io.err)
t.notOk(io.stderr)
return utils.readTextFile(path.resolve(fixturePath, '.next', 'BUILD_ID'))
})
.then(buildId => {
t.equal(buildId, '0123456789abcdef0123456789abcdef01234567')
})
})

tap.test('call stupid default generateBuildId for code coverage', t => {
return exec('npm', 'run build', fixturePath, mockedGitEnv())
.then(() => {
return exec(path.resolve(__dirname, '..', 'cli.js'), '', fixturePath, Object.assign(mockedGitEnv(), { NBI_TEST_CALL_DEFAULT_GENERATEBUILDID: true }))
})
.then(io => {
t.notOk(io.err)
t.notOk(io.stderr)
t.match(io.stdout, /9f2a37be-4545-445e-91bd/)
t.match(io.stdout, /Build ID: 0123456789abcdef0123456789abcdef01234567/)
t.match(io.stdout, /Updated:.*BUILD_ID/)
return utils.readTextFile(path.resolve(fixturePath, '.next', 'BUILD_ID'))
})
.then(buildId => {
t.equal(buildId, '0123456789abcdef0123456789abcdef01234567')
})
})
1 change: 1 addition & 0 deletions test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ function writeTextFile (file, data) {

module.exports = {
exec,
mockedGitEnv,
cli,
readTextFile,
readJsonFile,
Expand Down

0 comments on commit 502bccc

Please sign in to comment.