Skip to content

Commit

Permalink
Clear up production build missing message for next start and `next …
Browse files Browse the repository at this point in the history
…export` (vercel#19777)

Adds an err.sh link to the production build missing message. Also clears up `valid` as `production`.

Also fixes an edge case where an unhelpful error would be thrown because we checked for `.next` instead of `.next/BUILD_ID`

Added the out directory location as the list line during export to make sure people know where the files are output. 

Fixes vercel#19778
Fixes vercel#19788
  • Loading branch information
timneutkens authored Dec 8, 2020
1 parent cf46655 commit c792317
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 5 deletions.
10 changes: 10 additions & 0 deletions errors/next-export-no-build-id.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Could not find a production build

#### Why This Error Occurred

When running `next export` a production build is needed.

#### Possible Ways to Fix It

- Run `next build` to create a production build before running `next export`.
- If your intention was to run the development server run `next dev` instead.
10 changes: 10 additions & 0 deletions errors/production-start-no-build-id.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Could not find a production build

#### Why This Error Occurred

When running `next start` or a custom server in production mode a production build is needed.

#### Possible Ways to Fix It

- Run `next build` to create a production build before booting up the production server.
- If your intention was to run the development server run `next dev` instead.
2 changes: 1 addition & 1 deletion packages/next/cli/next-export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const nextExport: cliCommand = (argv) => {

exportApp(dir, options)
.then(() => {
printAndExit('Export successful', 0)
printAndExit(`Export successful. Files written to ${options.outdir}`, 0)
})
.catch((err) => {
printAndExit(err)
Expand Down
8 changes: 5 additions & 3 deletions packages/next/export/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,11 @@ export default async function exportApp(
Log.info(`using build directory: ${distDir}`)
}

if (!existsSync(distDir)) {
const buildIdFile = join(distDir, BUILD_ID_FILE)

if (!existsSync(buildIdFile)) {
throw new Error(
`Build directory ${distDir} does not exist. Make sure you run "next build" before running "next start" or "next export".`
`Could not find a production build in the '${distDir}' directory. Try building your app with 'next build' before starting the static export. https://err.sh/vercel/next.js/next-export-no-build-id`
)
}

Expand All @@ -186,7 +188,7 @@ export default async function exportApp(
)
}

const buildId = readFileSync(join(distDir, BUILD_ID_FILE), 'utf8')
const buildId = readFileSync(buildIdFile, 'utf8')
const pagesManifest =
!options.pages &&
(require(join(
Expand Down
2 changes: 1 addition & 1 deletion packages/next/next-server/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1899,7 +1899,7 @@ export default class Server {
} catch (err) {
if (!fs.existsSync(buildIdFile)) {
throw new Error(
`Could not find a valid build in the '${this.distDir}' directory! Try building your app with 'next build' before starting the server.`
`Could not find a production build in the '${this.distDir}' directory. Try building your app with 'next build' before starting the production server. https://err.sh/vercel/next.js/production-start-no-build-id`
)
}

Expand Down
39 changes: 39 additions & 0 deletions test/integration/export-no-build/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module.exports = {
onDemandEntries: {
// Make sure entries are not getting disposed.
maxInactiveAge: 1000 * 60 * 60,
},
rewrites() {
// add a rewrite so the code isn't dead-code eliminated
return [
{
source: '/some-rewrite',
destination: '/',
},
]
},
redirects() {
return [
{
source: '/redirect/me/to-about/:lang',
destination: '/:lang/about',
permanent: false,
},
{
source: '/nonexistent',
destination: '/about',
permanent: false,
},
{
source: '/shadowed-page',
destination: '/about',
permanent: false,
},
{
source: '/redirect-query-test/:path',
destination: '/about?foo=:path',
permanent: false,
},
]
},
}
13 changes: 13 additions & 0 deletions test/integration/export-no-build/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* eslint-env jest */
import { nextExport } from 'next-test-utils'
import { join } from 'path'
const appDir = join(__dirname, '../')
jest.setTimeout(1000 * 60 * 5)

describe('next export without build', () => {
it('should show error when there is no production build', async () => {
const result = await nextExport(appDir, {}, { stderr: true, stdout: true })
console.log(result.stdout, result.stderr)
expect(result.stderr).toMatch(/Could not find a production build in the/)
})
})
39 changes: 39 additions & 0 deletions test/integration/production-start-no-build/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module.exports = {
onDemandEntries: {
// Make sure entries are not getting disposed.
maxInactiveAge: 1000 * 60 * 60,
},
rewrites() {
// add a rewrite so the code isn't dead-code eliminated
return [
{
source: '/some-rewrite',
destination: '/',
},
]
},
redirects() {
return [
{
source: '/redirect/me/to-about/:lang',
destination: '/:lang/about',
permanent: false,
},
{
source: '/nonexistent',
destination: '/about',
permanent: false,
},
{
source: '/shadowed-page',
destination: '/about',
permanent: false,
},
{
source: '/redirect-query-test/:path',
destination: '/about?foo=:path',
permanent: false,
},
]
},
}
17 changes: 17 additions & 0 deletions test/integration/production-start-no-build/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* eslint-env jest */
import { nextServer } from 'next-test-utils'
import { join } from 'path'
const appDir = join(__dirname, '../')
jest.setTimeout(1000 * 60 * 5)

describe('Production Usage without production build', () => {
it('should show error when there is no production build', async () => {
expect(() => {
nextServer({
dir: appDir,
dev: false,
quiet: true,
})
}).toThrow(/Could not find a production build in the/)
})
})

0 comments on commit c792317

Please sign in to comment.