fix(next): next build --debug
log output layout is broken (#63193)
### Why? The output layout breaks when running `next build --debug` #### Current ```sh ✓ Generating static pages (10/10) Finalizing page optimization . Collecting build traces .Redirects ┌ source: /:path+/ ├ destination: /:path+ └ permanent: true ✓ Collecting build traces ✓ Finalizing page optimization ``` #### Expected ```sh ✓ Generating static pages (4/4) Finalizing page optimization ... Collecting build traces ... Redirects ┌ source: /:path+/ ├ destination: /:path+ └ permanent: true ``` ### How? Moved the `debug` output right above the `routes` output. Also, ensured that the output layout has a consistent number of line breaks (example below marked as `>`): > Two line breaks for the next `option`, a single line break within the same content. ```sh Collecting build traces ... > > Redirects ┌ source: /:path+/ ├ destination: /:path+ └ permanent: true > ┌ source: /redirects ├ destination: / └ permanent: true > > Headers ┌ source: / └ headers: └ x-custom-headers: headers > > Rewrites ┌ source: /rewrites └ destination: / > > Route (app) Size First Load JS ┌ ○ / 141 B 86.2 kB └ ○ /_not-found 876 B 86.9 kB ``` Fixes #63192 ---------
This commit is contained in:
parent
17907b4316
commit
1511433212
9 changed files with 140 additions and 52 deletions
|
@ -3308,12 +3308,6 @@ export default async function build(
|
||||||
return Promise.reject(err)
|
return Promise.reject(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (debugOutput) {
|
|
||||||
nextBuildSpan
|
|
||||||
.traceChild('print-custom-routes')
|
|
||||||
.traceFn(() => printCustomRoutes({ redirects, rewrites, headers }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: remove in the next major version
|
// TODO: remove in the next major version
|
||||||
if (config.analyticsId) {
|
if (config.analyticsId) {
|
||||||
Log.warn(
|
Log.warn(
|
||||||
|
@ -3370,6 +3364,12 @@ export default async function build(
|
||||||
if (postBuildSpinner) postBuildSpinner.stopAndPersist()
|
if (postBuildSpinner) postBuildSpinner.stopAndPersist()
|
||||||
console.log()
|
console.log()
|
||||||
|
|
||||||
|
if (debugOutput) {
|
||||||
|
nextBuildSpan
|
||||||
|
.traceChild('print-custom-routes')
|
||||||
|
.traceFn(() => printCustomRoutes({ redirects, rewrites, headers }))
|
||||||
|
}
|
||||||
|
|
||||||
await nextBuildSpan.traceChild('print-tree-view').traceAsyncFn(() =>
|
await nextBuildSpan.traceChild('print-tree-view').traceAsyncFn(() =>
|
||||||
printTreeView(pageKeys, pageInfos, {
|
printTreeView(pageKeys, pageInfos, {
|
||||||
distPath: distDir,
|
distPath: distDir,
|
||||||
|
|
|
@ -773,7 +773,6 @@ export function printCustomRoutes({
|
||||||
const isRedirects = type === 'Redirects'
|
const isRedirects = type === 'Redirects'
|
||||||
const isHeaders = type === 'Headers'
|
const isHeaders = type === 'Headers'
|
||||||
print(underline(type))
|
print(underline(type))
|
||||||
print()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
┌ source
|
┌ source
|
||||||
|
@ -815,9 +814,10 @@ export function printCustomRoutes({
|
||||||
})
|
})
|
||||||
.join('\n')
|
.join('\n')
|
||||||
|
|
||||||
print(routesStr, '\n')
|
print(`${routesStr}\n`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print()
|
||||||
if (redirects.length) {
|
if (redirects.length) {
|
||||||
printRoutes(redirects, 'Redirects')
|
printRoutes(redirects, 'Redirects')
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
export default function Root({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
3
test/production/app-dir/build-output-debug/app/page.tsx
Normal file
3
test/production/app-dir/build-output-debug/app/page.tsx
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export default function Page() {
|
||||||
|
return <p>hello world</p>
|
||||||
|
}
|
44
test/production/app-dir/build-output-debug/index.test.ts
Normal file
44
test/production/app-dir/build-output-debug/index.test.ts
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import { nextTestSetup } from 'e2e-utils'
|
||||||
|
import stripAnsi from 'strip-ansi'
|
||||||
|
|
||||||
|
describe('next build --debug', () => {
|
||||||
|
const { next } = nextTestSetup({
|
||||||
|
files: __dirname,
|
||||||
|
buildCommand: 'pnpm next build --debug',
|
||||||
|
})
|
||||||
|
|
||||||
|
let output = ''
|
||||||
|
beforeAll(() => {
|
||||||
|
output = stripAnsi(next.cliOutput)
|
||||||
|
})
|
||||||
|
|
||||||
|
const str = `
|
||||||
|
|
||||||
|
|
||||||
|
Redirects
|
||||||
|
┌ source: /:path+/
|
||||||
|
├ destination: /:path+
|
||||||
|
└ permanent: true
|
||||||
|
|
||||||
|
┌ source: /redirects
|
||||||
|
├ destination: /
|
||||||
|
└ permanent: true
|
||||||
|
|
||||||
|
|
||||||
|
Headers
|
||||||
|
┌ source: /
|
||||||
|
└ headers:
|
||||||
|
└ x-custom-headers: headers
|
||||||
|
|
||||||
|
|
||||||
|
Rewrites
|
||||||
|
┌ source: /rewrites
|
||||||
|
└ destination: /
|
||||||
|
|
||||||
|
|
||||||
|
Route (app)`
|
||||||
|
|
||||||
|
it('should log Redirects above Route(app)', async () => {
|
||||||
|
expect(output).toContain(str)
|
||||||
|
})
|
||||||
|
})
|
33
test/production/app-dir/build-output-debug/next.config.js
Normal file
33
test/production/app-dir/build-output-debug/next.config.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/** @type {import('next').NextConfig} */
|
||||||
|
module.exports = {
|
||||||
|
async redirects() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/redirects',
|
||||||
|
destination: '/',
|
||||||
|
permanent: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
async rewrites() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/rewrites',
|
||||||
|
destination: '/',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
async headers() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/',
|
||||||
|
headers: [
|
||||||
|
{
|
||||||
|
key: 'x-custom-headers',
|
||||||
|
value: 'headers',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
7
test/production/app-dir/build-output/app/layout.tsx
Normal file
7
test/production/app-dir/build-output/app/layout.tsx
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export default function Root({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
3
test/production/app-dir/build-output/app/page.tsx
Normal file
3
test/production/app-dir/build-output/app/page.tsx
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export default function Page() {
|
||||||
|
return <p>hello world</p>
|
||||||
|
}
|
|
@ -1,50 +1,41 @@
|
||||||
import { createNextDescribe } from 'e2e-utils'
|
import { nextTestSetup } from 'e2e-utils'
|
||||||
import stripAnsi from 'strip-ansi'
|
import stripAnsi from 'strip-ansi'
|
||||||
|
|
||||||
createNextDescribe(
|
describe('production - app dir - build output', () => {
|
||||||
'production - app dir - build output',
|
const { next } = nextTestSetup({
|
||||||
{
|
files: __dirname,
|
||||||
files: {
|
})
|
||||||
'app/page.tsx': `export default function Page() { return null }`,
|
|
||||||
'app/layout.tsx': `export default function Layout({ children }) {
|
|
||||||
return (
|
|
||||||
<html><body>{children}</body></html>
|
|
||||||
)
|
|
||||||
}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
({ next }) => {
|
|
||||||
let output = ''
|
|
||||||
beforeAll(() => {
|
|
||||||
output = stripAnsi(next.cliOutput)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should only log app routes', async () => {
|
let output = ''
|
||||||
expect(output).toContain('Route (app)')
|
beforeAll(() => {
|
||||||
expect(output).not.toContain('Route (pages)')
|
output = stripAnsi(next.cliOutput)
|
||||||
expect(output).not.toContain('/favicon.ico')
|
})
|
||||||
})
|
|
||||||
|
|
||||||
it('should always log version first then the rest jobs', async () => {
|
it('should only log app routes', async () => {
|
||||||
const indexOfVersion = output.indexOf('▲ Next.js')
|
expect(output).toContain('Route (app)')
|
||||||
const indexOfStartCompiling = output.indexOf(
|
expect(output).not.toContain('Route (pages)')
|
||||||
'Creating an optimized production build'
|
expect(output).not.toContain('/favicon.ico')
|
||||||
)
|
})
|
||||||
const indexOfLinting = output.indexOf(
|
|
||||||
'Linting and checking validity of types'
|
|
||||||
)
|
|
||||||
expect(indexOfVersion).toBeLessThan(indexOfLinting)
|
|
||||||
expect(indexOfStartCompiling).toBeLessThan(indexOfLinting)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should match the expected output format', async () => {
|
it('should always log version first then the rest jobs', async () => {
|
||||||
expect(output).toContain('Size')
|
const indexOfVersion = output.indexOf('▲ Next.js')
|
||||||
expect(output).toContain('First Load JS')
|
const indexOfStartCompiling = output.indexOf(
|
||||||
expect(output).toContain('+ First Load JS shared by all')
|
'Creating an optimized production build'
|
||||||
expect(output).toContain('└ other shared chunks (total)')
|
)
|
||||||
|
const indexOfLinting = output.indexOf(
|
||||||
|
'Linting and checking validity of types'
|
||||||
|
)
|
||||||
|
expect(indexOfVersion).toBeLessThan(indexOfLinting)
|
||||||
|
expect(indexOfStartCompiling).toBeLessThan(indexOfLinting)
|
||||||
|
})
|
||||||
|
|
||||||
// output type
|
it('should match the expected output format', async () => {
|
||||||
expect(output).toContain('○ (Static) prerendered as static content')
|
expect(output).toContain('Size')
|
||||||
})
|
expect(output).toContain('First Load JS')
|
||||||
}
|
expect(output).toContain('+ First Load JS shared by all')
|
||||||
)
|
expect(output).toContain('└ other shared chunks (total)')
|
||||||
|
|
||||||
|
// output type
|
||||||
|
expect(output).toContain('○ (Static) prerendered as static content')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
Loading…
Reference in a new issue