2020-11-06 03:33:14 +01:00
import chalk from 'chalk'
2020-03-29 18:21:53 +02:00
import findUp from 'next/dist/compiled/find-up'
2019-12-13 20:30:22 +01:00
import {
2020-05-02 06:10:19 +02:00
promises ,
2019-12-13 20:30:22 +01:00
existsSync ,
2020-03-25 09:22:34 +01:00
exists as existsOrig ,
2019-12-13 20:30:22 +01:00
readFileSync ,
writeFileSync ,
} from 'fs'
2021-07-16 11:21:44 +02:00
import { Worker } from '../lib/worker'
2019-10-31 21:26:47 +01:00
import { dirname , join , resolve , sep } from 'path'
2019-10-04 17:26:44 +02:00
import { promisify } from 'util'
import { AmpPageStatus , formatAmpMessages } from '../build/output/index'
2020-08-04 09:58:23 +02:00
import * as Log from '../build/output/log'
2019-10-04 17:26:44 +02:00
import createSpinner from '../build/spinner'
2020-05-19 15:29:34 +02:00
import { API_ROUTE , SSG_FALLBACK_EXPORT_ERROR } from '../lib/constants'
2019-09-05 01:56:11 +02:00
import { recursiveCopy } from '../lib/recursive-copy'
import { recursiveDelete } from '../lib/recursive-delete'
2019-05-29 13:57:26 +02:00
import {
BUILD_ID_FILE ,
2019-10-04 17:26:44 +02:00
CLIENT_PUBLIC_FILES_PATH ,
CLIENT_STATIC_FILES_PATH ,
CONFIG_FILE ,
2019-12-13 20:30:22 +01:00
EXPORT_DETAIL ,
2020-11-11 16:46:48 +01:00
EXPORT_MARKER ,
2019-10-04 17:26:44 +02:00
PAGES_MANIFEST ,
PHASE_EXPORT ,
2019-09-24 10:50:04 +02:00
PRERENDER_MANIFEST ,
SERVERLESS_DIRECTORY ,
2019-12-13 20:30:22 +01:00
SERVER_DIRECTORY ,
2021-06-30 11:43:31 +02:00
} from '../shared/lib/constants'
2021-07-12 23:38:57 +02:00
import loadConfig , { isTargetLikeServerless } from '../server/config'
import { NextConfigComplete } from '../server/config-shared'
2020-02-14 21:42:44 +01:00
import { eventCliSession } from '../telemetry/events'
2020-10-05 17:26:11 +02:00
import { hasNextSupport } from '../telemetry/ci-info'
2019-10-10 19:18:07 +02:00
import { Telemetry } from '../telemetry/storage'
2020-06-04 19:32:45 +02:00
import {
normalizePagePath ,
denormalizePagePath ,
2021-06-30 13:44:40 +02:00
} from '../server/normalize-page-path'
2020-09-25 20:14:28 +02:00
import { loadEnvConfig } from '@next/env'
2020-05-19 15:29:34 +02:00
import { PrerenderManifest } from '../build'
2020-05-25 23:15:56 +02:00
import { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin'
2021-06-30 13:44:40 +02:00
import { getPagePath } from '../server/require'
2021-09-13 15:49:29 +02:00
import { Span } from '../trace'
2019-02-22 17:33:28 +01:00
2020-03-25 09:22:34 +01:00
const exists = promisify ( existsOrig )
2017-05-08 00:47:40 +02:00
2020-09-07 11:52:12 +02:00
function divideSegments ( number : number , segments : number ) : number [ ] {
const result = [ ]
while ( number > 0 && segments > 0 ) {
2020-11-20 17:57:34 +01:00
const dividedNumber =
number < segments ? number : Math . floor ( number / segments )
2020-09-07 11:52:12 +02:00
number -= dividedNumber
segments --
result . push ( dividedNumber )
}
return result
}
2020-09-21 18:09:14 +02:00
const createProgress = ( total : number , label : string ) = > {
2020-09-07 11:52:12 +02:00
const segments = divideSegments ( total , 4 )
2021-03-12 09:36:28 +01:00
if ( total === 0 ) {
throw new Error ( 'invariant: progress total can not be zero' )
}
2020-09-07 11:52:12 +02:00
let currentSegmentTotal = segments . shift ( )
let currentSegmentCount = 0
2021-07-16 11:21:44 +02:00
let lastProgressOutput = Date . now ( )
2019-09-16 17:37:00 +02:00
let curProgress = 0
let progressSpinner = createSpinner ( ` ${ label } ( ${ curProgress } / ${ total } ) ` , {
spinner : {
frames : [
'[ ]' ,
'[= ]' ,
'[== ]' ,
'[=== ]' ,
'[ ===]' ,
'[ ==]' ,
'[ =]' ,
'[ ]' ,
'[ =]' ,
'[ ==]' ,
'[ ===]' ,
'[====]' ,
'[=== ]' ,
'[== ]' ,
2019-10-04 17:26:44 +02:00
'[= ]' ,
2019-09-16 17:37:00 +02:00
] ,
2021-07-16 11:21:44 +02:00
interval : 500 ,
2019-10-04 17:26:44 +02:00
} ,
2019-09-16 17:37:00 +02:00
} )
return ( ) = > {
curProgress ++
2020-09-07 11:52:12 +02:00
2021-07-16 11:21:44 +02:00
// Make sure we only log once
// - per fully generated segment, or
// - per minute
// when not showing the spinner
if ( ! progressSpinner ) {
currentSegmentCount ++
if ( currentSegmentCount === currentSegmentTotal ) {
currentSegmentTotal = segments . shift ( )
currentSegmentCount = 0
} else if ( lastProgressOutput + 60000 > Date . now ( ) ) {
return
}
2020-09-07 11:52:12 +02:00
2021-07-16 11:21:44 +02:00
lastProgressOutput = Date . now ( )
}
2019-09-16 17:37:00 +02:00
const newText = ` ${ label } ( ${ curProgress } / ${ total } ) `
if ( progressSpinner ) {
progressSpinner . text = newText
} else {
console . log ( newText )
}
if ( curProgress === total && progressSpinner ) {
progressSpinner . stop ( )
console . log ( newText )
}
}
}
2019-10-04 17:26:44 +02:00
type ExportPathMap = {
[ page : string ] : { page : string ; query ? : { [ key : string ] : string } }
}
2020-05-25 23:15:56 +02:00
interface ExportOptions {
outdir : string
silent? : boolean
threads? : number
pages? : string [ ]
buildExport? : boolean
2020-08-04 09:58:23 +02:00
statusMessage? : string
2021-08-12 21:54:49 +02:00
exportPageWorker? : typeof import ( './worker' ) . default
endWorker ? : ( ) = > Promise < void >
2020-05-25 23:15:56 +02:00
}
export default async function exportApp (
2019-10-04 17:26:44 +02:00
dir : string ,
2020-05-25 23:15:56 +02:00
options : ExportOptions ,
2021-09-13 15:49:29 +02:00
span : Span ,
2021-07-12 23:38:57 +02:00
configuration? : NextConfigComplete
2019-10-04 17:26:44 +02:00
) : Promise < void > {
2021-09-13 15:49:29 +02:00
const nextExportSpan = span . traceChild ( 'next-export' )
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
return nextExportSpan . traceAsyncFn ( async ( ) = > {
2021-01-10 02:12:13 +01:00
dir = resolve ( dir )
2020-05-21 14:06:57 +02:00
2021-01-10 02:12:13 +01:00
// attempt to load global env values so they are available in next.config.js
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
nextExportSpan
. traceChild ( 'load-dotenv' )
. traceFn ( ( ) = > loadEnvConfig ( dir , false , Log ) )
2019-10-03 16:21:15 +02:00
2021-01-10 02:12:13 +01:00
const nextConfig =
configuration ||
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
( await nextExportSpan
. traceChild ( 'load-next-config' )
. traceAsyncFn ( ( ) = > loadConfig ( PHASE_EXPORT , dir ) ) )
2021-04-17 22:09:26 +02:00
const threads = options . threads || nextConfig . experimental . cpus
2021-01-10 02:12:13 +01:00
const distDir = join ( dir , nextConfig . distDir )
const telemetry = options . buildExport ? null : new Telemetry ( { distDir } )
if ( telemetry ) {
telemetry . record (
eventCliSession ( PHASE_EXPORT , distDir , {
2021-04-20 16:46:40 +02:00
webpackVersion : null ,
2021-01-10 02:12:13 +01:00
cliCommand : 'export' ,
isSrcDir : null ,
hasNowJson : ! ! ( await findUp ( 'now.json' , { cwd : dir } ) ) ,
isCustomServer : null ,
} )
)
2020-03-24 18:38:22 +01:00
}
2021-03-14 13:58:34 +01:00
const subFolders = nextConfig . trailingSlash && ! options . buildExport
2021-01-10 02:12:13 +01:00
const isLikeServerless = nextConfig . target !== 'server'
2018-08-27 12:28:54 +02:00
2021-01-10 02:12:13 +01:00
if ( ! options . silent && ! options . buildExport ) {
Log . info ( ` using build directory: ${ distDir } ` )
2019-11-22 02:20:19 +01:00
}
2021-01-10 02:12:13 +01:00
const buildIdFile = join ( distDir , BUILD_ID_FILE )
2019-10-06 13:44:03 +02:00
2021-01-10 02:12:13 +01:00
if ( ! existsSync ( buildIdFile ) ) {
throw new Error (
2021-03-29 10:25:00 +02:00
` Could not find a production build in the ' ${ distDir } ' directory. Try building your app with 'next build' before starting the static export. https://nextjs.org/docs/messages/next-export-no-build-id `
2021-01-10 02:12:13 +01:00
)
2020-08-04 09:58:23 +02:00
}
2017-05-14 02:11:13 +02:00
2021-01-10 02:12:13 +01:00
const customRoutesDetected = [ 'rewrites' , 'redirects' , 'headers' ] . filter (
( config ) = > typeof nextConfig [ config ] === 'function'
2018-02-07 11:54:07 +01:00
)
2021-01-10 02:12:13 +01:00
if (
! hasNextSupport &&
! options . buildExport &&
customRoutesDetected . length > 0
) {
Log . warn (
` rewrites, redirects, and headers are not applied when exporting your application, detected ( ${ customRoutesDetected . join (
', '
2021-03-29 10:25:00 +02:00
) } ) . See more info here : https : //nextjs.org/docs/messages/export-no-custom-routes`
2020-08-04 09:58:23 +02:00
)
}
2017-05-09 03:20:50 +02:00
2021-01-10 02:12:13 +01:00
const buildId = readFileSync ( buildIdFile , 'utf8' )
const pagesManifest =
! options . pages &&
( require ( join (
distDir ,
isLikeServerless ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY ,
PAGES_MANIFEST
) ) as PagesManifest )
let prerenderManifest : PrerenderManifest | undefined = undefined
try {
prerenderManifest = require ( join ( distDir , PRERENDER_MANIFEST ) )
} catch ( _ ) { }
const excludedPrerenderRoutes = new Set < string > ( )
const pages = options . pages || Object . keys ( pagesManifest )
const defaultPathMap : ExportPathMap = { }
let hasApiRoutes = false
for ( const page of pages ) {
// _document and _app are not real pages
// _error is exported as 404.html later on
// API Routes are Node.js functions
if ( page . match ( API_ROUTE ) ) {
hasApiRoutes = true
continue
}
2020-10-15 20:21:30 +02:00
2021-01-10 02:12:13 +01:00
if ( page === '/_document' || page === '/_app' || page === '/_error' ) {
continue
}
2020-11-11 16:46:48 +01:00
2021-01-10 02:12:13 +01:00
// iSSG pages that are dynamic should not export templated version by
// default. In most cases, this would never work. There is no server that
// could run `getStaticProps`. If users make their page work lazily, they
// can manually add it to the `exportPathMap`.
if ( prerenderManifest ? . dynamicRoutes [ page ] ) {
excludedPrerenderRoutes . add ( page )
continue
}
2018-02-26 12:03:27 +01:00
2021-01-10 02:12:13 +01:00
defaultPathMap [ page ] = { page }
}
2018-02-27 17:50:14 +01:00
2021-01-10 02:12:13 +01:00
// Initialize the output directory
const outDir = options . outdir
2017-05-08 08:10:26 +02:00
2021-01-10 02:12:13 +01:00
if ( outDir === join ( dir , 'public' ) ) {
throw new Error (
2021-03-29 10:25:00 +02:00
` The 'public' directory is reserved in Next.js and can not be used as the export out directory. https://nextjs.org/docs/messages/can-not-output-to-public `
2021-01-10 02:12:13 +01:00
)
}
2017-05-08 08:10:26 +02:00
2021-01-11 14:34:58 +01:00
if ( outDir === join ( dir , 'static' ) ) {
throw new Error (
2021-03-29 10:25:00 +02:00
` The 'static' directory is reserved in Next.js and can not be used as the export out directory. https://nextjs.org/docs/messages/can-not-output-to-static `
2021-01-11 14:34:58 +01:00
)
}
2021-01-10 02:12:13 +01:00
await recursiveDelete ( join ( outDir ) )
await promises . mkdir ( join ( outDir , '_next' , buildId ) , { recursive : true } )
writeFileSync (
join ( distDir , EXPORT_DETAIL ) ,
JSON . stringify ( {
version : 1 ,
outDirectory : outDir ,
success : false ,
} ) ,
'utf8'
)
2020-05-27 07:48:50 +02:00
2021-01-10 02:12:13 +01:00
// Copy static directory
if ( ! options . buildExport && existsSync ( join ( dir , 'static' ) ) ) {
if ( ! options . silent ) {
Log . info ( 'Copying "static" directory' )
}
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
await nextExportSpan
. traceChild ( 'copy-static-directory' )
. traceAsyncFn ( ( ) = >
recursiveCopy ( join ( dir , 'static' ) , join ( outDir , 'static' ) )
)
2019-09-04 16:00:54 +02:00
}
2020-05-27 07:48:50 +02:00
2021-01-10 02:12:13 +01:00
// Copy .next/static directory
if (
! options . buildExport &&
existsSync ( join ( distDir , CLIENT_STATIC_FILES_PATH ) )
) {
if ( ! options . silent ) {
Log . info ( 'Copying "static build" directory' )
}
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
await nextExportSpan
. traceChild ( 'copy-next-static-directory' )
. traceAsyncFn ( ( ) = >
recursiveCopy (
join ( distDir , CLIENT_STATIC_FILES_PATH ) ,
join ( outDir , '_next' , CLIENT_STATIC_FILES_PATH )
)
2021-01-10 02:12:13 +01:00
)
}
2020-05-19 15:29:34 +02:00
2021-01-10 02:12:13 +01:00
// Get the exportPathMap from the config file
if ( typeof nextConfig . exportPathMap !== 'function' ) {
if ( ! options . silent ) {
Log . info (
` No "exportPathMap" found in " ${ CONFIG_FILE } ". Generating map from "./pages" `
)
2020-05-19 15:29:34 +02:00
}
2021-01-10 02:12:13 +01:00
nextConfig . exportPathMap = async ( defaultMap : ExportPathMap ) = > {
return defaultMap
2020-05-19 15:29:34 +02:00
}
}
2021-01-10 02:12:13 +01:00
const {
i18n ,
images : { loader = 'default' } ,
} = nextConfig
if ( i18n && ! options . buildExport ) {
2020-05-19 15:29:34 +02:00
throw new Error (
2021-01-10 02:12:13 +01:00
` i18n support is not compatible with next export. See here for more info on deploying: https://nextjs.org/docs/deployment `
2020-05-19 15:29:34 +02:00
)
}
2021-01-10 02:12:13 +01:00
if ( ! options . buildExport ) {
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
const { isNextImageImported } = await nextExportSpan
. traceChild ( 'is-next-image-imported' )
. traceAsyncFn ( ( ) = >
2021-01-10 02:12:13 +01:00
promises
. readFile ( join ( distDir , EXPORT_MARKER ) , 'utf8' )
. then ( ( text ) = > JSON . parse ( text ) )
. catch ( ( ) = > ( { } ) )
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
)
2021-01-10 02:12:13 +01:00
if ( isNextImageImported && loader === 'default' && ! hasNextSupport ) {
throw new Error (
` Image Optimization using Next.js' default loader is not compatible with \` next export \` .
Possible solutions :
2021-03-15 19:01:12 +01:00
- Use \ ` next start \` to run a server, which includes the Image Optimization API.
- Use any provider which supports Image Optimization ( like Vercel ) .
2021-01-10 02:12:13 +01:00
- Configure a third - party loader in \ ` next.config.js \` .
2021-03-15 19:01:12 +01:00
- Use the \ ` loader \` prop for \` next/image \` .
2021-03-29 10:25:00 +02:00
Read more : https : //nextjs.org/docs/messages/export-image-api`
2021-01-10 02:12:13 +01:00
)
}
2020-08-04 09:58:23 +02:00
}
2018-05-11 14:52:39 +02:00
2021-01-10 02:12:13 +01:00
// Start the rendering process
const renderOpts = {
dir ,
buildId ,
nextExport : true ,
assetPrefix : nextConfig.assetPrefix.replace ( /\/$/ , '' ) ,
distDir ,
dev : false ,
hotReloader : null ,
basePath : nextConfig.basePath ,
canonicalBase : nextConfig.amp?.canonicalBase || '' ,
ampValidatorPath : nextConfig.experimental.amp?.validator || undefined ,
ampSkipValidation : nextConfig.experimental.amp?.skipValidation || false ,
ampOptimizerConfig : nextConfig.experimental.amp?.optimizer || undefined ,
locales : i18n?.locales ,
locale : i18n?.defaultLocale ,
defaultLocale : i18n?.defaultLocale ,
domainLocales : i18n?.domains ,
2021-03-14 13:58:34 +01:00
trailingSlash : nextConfig.trailingSlash ,
2021-05-13 12:39:36 +02:00
disableOptimizedLoading : nextConfig.experimental.disableOptimizedLoading ,
2021-09-06 12:23:07 +02:00
// Exported pages do not currently support dynamic HTML.
supportsDynamicHTML : false ,
2021-08-13 23:08:45 +02:00
concurrentFeatures : nextConfig.experimental.concurrentFeatures ,
2020-08-04 09:58:23 +02:00
}
2019-09-05 01:56:11 +02:00
2021-01-10 02:12:13 +01:00
const { serverRuntimeConfig , publicRuntimeConfig } = nextConfig
2019-09-05 01:56:11 +02:00
2021-01-10 02:12:13 +01:00
if ( Object . keys ( publicRuntimeConfig ) . length > 0 ) {
; ( renderOpts as any ) . runtimeConfig = publicRuntimeConfig
}
2019-09-05 01:56:11 +02:00
2021-01-10 02:12:13 +01:00
// We need this for server rendering the Link component.
; ( global as any ) . __NEXT_DATA__ = {
nextExport : true ,
}
2019-05-03 18:57:47 +02:00
2021-01-10 02:12:13 +01:00
if ( ! options . silent && ! options . buildExport ) {
Log . info ( ` Launching ${ threads } workers ` )
}
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
const exportPathMap = await nextExportSpan
. traceChild ( 'run-export-path-map' )
. traceAsyncFn ( ( ) = >
2021-01-10 02:12:13 +01:00
nextConfig . exportPathMap ( defaultPathMap , {
dev : false ,
dir ,
outDir ,
distDir ,
buildId ,
} )
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
)
2019-09-05 01:56:11 +02:00
2021-03-08 09:30:44 +01:00
if (
! options . buildExport &&
! exportPathMap [ '/404' ] &&
! exportPathMap [ '/404.html' ]
) {
2021-01-10 02:12:13 +01:00
exportPathMap [ '/404' ] = exportPathMap [ '/404.html' ] = {
page : '/_error' ,
2019-09-05 01:56:11 +02:00
}
2021-01-10 02:12:13 +01:00
}
// make sure to prevent duplicates
const exportPaths = [
. . . new Set (
Object . keys ( exportPathMap ) . map ( ( path ) = >
denormalizePagePath ( normalizePagePath ( path ) )
)
) ,
]
const filteredPaths = exportPaths . filter (
// Remove API routes
( route ) = > ! exportPathMap [ route ] . page . match ( API_ROUTE )
)
if ( filteredPaths . length !== exportPaths . length ) {
hasApiRoutes = true
}
2021-04-06 19:12:23 +02:00
if ( filteredPaths . length === 0 ) {
return
}
2021-01-10 02:12:13 +01:00
if ( prerenderManifest && ! options . buildExport ) {
const fallbackEnabledPages = new Set ( )
2019-09-24 10:50:04 +02:00
2021-01-10 02:12:13 +01:00
for ( const key of Object . keys ( prerenderManifest . dynamicRoutes ) ) {
// only error if page is included in path map
if ( ! exportPathMap [ key ] && ! excludedPrerenderRoutes . has ( key ) ) {
continue
2020-10-15 23:55:38 +02:00
}
2021-01-10 02:12:13 +01:00
if ( prerenderManifest . dynamicRoutes [ key ] . fallback !== false ) {
fallbackEnabledPages . add ( key )
2020-10-15 23:55:38 +02:00
}
2019-09-24 10:50:04 +02:00
}
2020-10-15 23:55:38 +02:00
2021-01-10 02:12:13 +01:00
if ( fallbackEnabledPages . size ) {
throw new Error (
` Found pages with \` fallback \` enabled: \ n ${ [
. . . fallbackEnabledPages ,
] . join ( '\n' ) } \ n $ { SSG_FALLBACK_EXPORT_ERROR } \ n `
2020-06-22 23:12:36 +02:00
)
2021-01-10 02:12:13 +01:00
}
}
2020-06-22 23:12:36 +02:00
2021-01-10 02:12:13 +01:00
// Warn if the user defines a path for an API page
if ( hasApiRoutes ) {
if ( ! options . silent ) {
Log . warn (
chalk . yellow (
` Statically exporting a Next.js application via \` next export \` disables API routes. `
) +
` \ n ` +
chalk . yellow (
` This command is meant for static-only hosts, and is ` +
' ' +
chalk . bold ( ` not necessary to make your application static. ` )
) +
` \ n ` +
chalk . yellow (
` Pages in your application without server-side data dependencies will be automatically statically exported by \` next build \` , including pages powered by \` getStaticProps \` . `
) +
` \ n ` +
chalk . yellow (
2021-03-29 10:25:00 +02:00
` Learn more: https://nextjs.org/docs/messages/api-routes-static-export `
2021-01-10 02:12:13 +01:00
)
2020-03-25 09:22:34 +01:00
)
2021-01-10 02:12:13 +01:00
}
}
2019-09-24 10:50:04 +02:00
2021-01-10 02:12:13 +01:00
const progress =
! options . silent &&
createProgress (
filteredPaths . length ,
` ${ Log . prefixes . info } ${ options . statusMessage || 'Exporting' } `
)
const pagesDataDir = options . buildExport
? outDir
: join ( outDir , '_next/data' , buildId )
const ampValidations : AmpPageStatus = { }
let hadValidationError = false
const publicDir = join ( dir , CLIENT_PUBLIC_FILES_PATH )
// Copy public directory
if ( ! options . buildExport && existsSync ( publicDir ) ) {
if ( ! options . silent ) {
Log . info ( 'Copying "public" directory' )
}
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
await nextExportSpan
. traceChild ( 'copy-public-directory' )
. traceAsyncFn ( ( ) = >
recursiveCopy ( publicDir , outDir , {
filter ( path ) {
// Exclude paths used by pages
return ! exportPathMap [ path ]
} ,
} )
)
2021-01-10 02:12:13 +01:00
}
2020-03-25 09:22:34 +01:00
2021-07-16 11:21:44 +02:00
const timeout = configuration ? . experimental . staticPageGenerationTimeout || 0
let infoPrinted = false
2021-08-12 21:54:49 +02:00
let exportPage : typeof import ( './worker' ) . default
let endWorker : ( ) = > Promise < void >
if ( options . exportPageWorker ) {
exportPage = options . exportPageWorker
endWorker = options . endWorker || ( ( ) = > Promise . resolve ( ) )
} else {
const worker = new Worker ( require . resolve ( './worker' ) , {
timeout : timeout * 1000 ,
onRestart : ( _method , [ { path } ] , attempts ) = > {
if ( attempts >= 3 ) {
throw new Error (
` Static page generation for ${ path } is still timing out after 3 attempts. See more info here https://nextjs.org/docs/messages/static-page-generation-timeout `
)
}
2021-07-16 11:21:44 +02:00
Log . warn (
2021-08-12 21:54:49 +02:00
` Restarted static page genertion for ${ path } because it took more than ${ timeout } seconds `
2021-07-16 11:21:44 +02:00
)
2021-08-12 21:54:49 +02:00
if ( ! infoPrinted ) {
Log . warn (
'See more info here https://nextjs.org/docs/messages/static-page-generation-timeout'
)
infoPrinted = true
}
} ,
maxRetries : 0 ,
numWorkers : threads ,
enableWorkerThreads : nextConfig.experimental.workerThreads ,
exposedMethods : [ 'default' ] ,
} ) as Worker & typeof import ( './worker' )
exportPage = worker . default . bind ( worker )
endWorker = async ( ) = > {
await worker . end ( )
}
}
2021-01-10 02:12:13 +01:00
let renderError = false
const errorPaths : string [ ] = [ ]
await Promise . all (
filteredPaths . map ( async ( path ) = > {
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
const pageExportSpan = nextExportSpan . traceChild ( 'export-page' )
pageExportSpan . setAttribute ( 'path' , path )
2021-01-10 02:12:13 +01:00
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
return pageExportSpan . traceAsyncFn ( async ( ) = > {
2021-07-16 11:21:44 +02:00
const pathMap = exportPathMap [ path ]
2021-08-12 21:54:49 +02:00
const result = await exportPage ( {
2021-01-10 02:12:13 +01:00
path ,
2021-07-16 11:21:44 +02:00
pathMap ,
2021-01-10 02:12:13 +01:00
distDir ,
outDir ,
pagesDataDir ,
renderOpts ,
serverRuntimeConfig ,
subFolders ,
buildExport : options.buildExport ,
serverless : isTargetLikeServerless ( nextConfig . target ) ,
2021-04-05 19:47:03 +02:00
optimizeFonts : nextConfig.optimizeFonts ,
2021-01-10 02:12:13 +01:00
optimizeImages : nextConfig.experimental.optimizeImages ,
optimizeCss : nextConfig.experimental.optimizeCss ,
2021-05-13 12:39:36 +02:00
disableOptimizedLoading :
nextConfig . experimental . disableOptimizedLoading ,
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
parentSpanId : pageExportSpan.id ,
2021-08-03 02:38:42 +02:00
httpAgentOptions : nextConfig.httpAgentOptions ,
2021-01-10 02:12:13 +01:00
} )
for ( const validation of result . ampValidations || [ ] ) {
const { page , result : ampValidationResult } = validation
ampValidations [ page ] = ampValidationResult
hadValidationError =
hadValidationError ||
( Array . isArray ( ampValidationResult ? . errors ) &&
ampValidationResult . errors . length > 0 )
}
renderError = renderError || ! ! result . error
if ( ! ! result . error ) errorPaths . push ( path )
if ( options . buildExport && configuration ) {
if ( typeof result . fromBuildExportRevalidate !== 'undefined' ) {
configuration . initialPageRevalidationMap [ path ] =
result . fromBuildExportRevalidate
}
if ( result . ssgNotFound === true ) {
configuration . ssgNotFoundPaths . push ( path )
}
2021-07-16 11:21:44 +02:00
const durations = ( configuration . pageDurationMap [ pathMap . page ] =
configuration . pageDurationMap [ pathMap . page ] || { } )
durations [ path ] = result . duration
2021-01-10 02:12:13 +01:00
}
if ( progress ) progress ( )
} )
2019-09-24 10:50:04 +02:00
} )
)
2021-08-12 21:54:49 +02:00
const endWorkerPromise = endWorker ( )
2021-01-10 02:12:13 +01:00
// copy prerendered routes to outDir
if ( ! options . buildExport && prerenderManifest ) {
await Promise . all (
Object . keys ( prerenderManifest . routes ) . map ( async ( route ) = > {
const { srcRoute } = prerenderManifest ! . routes [ route ]
const pageName = srcRoute || route
2021-09-18 17:20:45 +02:00
route = normalizePagePath ( route )
// returning notFound: true from getStaticProps will not
// output html/json files during the build
if ( prerenderManifest ! . notFoundRoutes . includes ( route ) ) {
return
}
2021-01-10 02:12:13 +01:00
const pagePath = getPagePath ( pageName , distDir , isLikeServerless )
const distPagesDir = join (
pagePath ,
// strip leading / and then recurse number of nested dirs
// to place from base folder
pageName
. substr ( 1 )
. split ( '/' )
. map ( ( ) = > '..' )
. join ( '/' )
)
const orig = join ( distPagesDir , route )
const htmlDest = join (
outDir ,
` ${ route } ${
subFolders && route !== '/index' ? ` ${ sep } index ` : ''
} . html `
)
const ampHtmlDest = join (
outDir ,
` ${ route } .amp ${ subFolders ? ` ${ sep } index ` : '' } .html `
)
const jsonDest = join ( pagesDataDir , ` ${ route } .json ` )
await promises . mkdir ( dirname ( htmlDest ) , { recursive : true } )
await promises . mkdir ( dirname ( jsonDest ) , { recursive : true } )
2021-09-18 17:20:45 +02:00
const htmlSrc = ` ${ orig } .html `
const jsonSrc = ` ${ orig } .json `
await promises . copyFile ( htmlSrc , htmlDest )
await promises . copyFile ( jsonSrc , jsonDest )
2021-01-10 02:12:13 +01:00
if ( await exists ( ` ${ orig } .amp.html ` ) ) {
await promises . mkdir ( dirname ( ampHtmlDest ) , { recursive : true } )
await promises . copyFile ( ` ${ orig } .amp.html ` , ampHtmlDest )
}
} )
)
}
if ( Object . keys ( ampValidations ) . length ) {
console . log ( formatAmpMessages ( ampValidations ) )
}
if ( hadValidationError ) {
throw new Error (
2021-03-29 10:25:00 +02:00
` AMP Validation caused the export to fail. https://nextjs.org/docs/messages/amp-export-validation `
2021-01-10 02:12:13 +01:00
)
}
if ( renderError ) {
throw new Error (
` Export encountered errors on following paths: \ n \ t ${ errorPaths
. sort ( )
. join ( '\n\t' ) } `
)
}
2019-03-26 22:21:27 +01:00
2021-01-10 02:12:13 +01:00
writeFileSync (
join ( distDir , EXPORT_DETAIL ) ,
JSON . stringify ( {
version : 1 ,
outDirectory : outDir ,
success : true ,
} ) ,
'utf8'
Add failing paths to export error summary (#10026)
Closes #9990 by collecting all paths with errors during `next export` and reporting them sorted in the error summary at the end.
It will produce an output similar to:
```
Error: Export encountered errors on following paths:
/nested/page
/page
/page-1
/page-10
/page-11
/page-12
/page-13
/page-2
/page-3
/page-4
/page-5
/page-6
/page-7
/page-8
/page-9
at _default (/app/next.js/packages/next/dist/export/index.js:19:788)
at process._tickCallback (internal/process/next_tick.js:68:7)
```
I tested the output with the `handle-export-errors` integration test suite, but I'm not sure how to gracefully test this added output.
I thought of collecting all page source files with [recursiveReaddirSync](https://github.com/zeit/next.js/blob/2ba352da39ee00b6595aecdc9ffb2f103e803a85/packages/next/next-server/server/lib/recursive-readdir-sync.ts) but it seems I can't import it in js test files:
```
SyntaxError: /app/next.js/packages/next/next-server/server/lib/recursive-readdir-sync.ts: Unexpected token, expected "," (11:5)
9 | */
10 | export function recursiveReadDirSync(
> 11 | dir: string,
| ^
12 | arr: string[] = [],
13 | rootDir = dir
14 | ): string[] {
```
The test itself could look like:
```js
it('Reports failing paths', async () => {
const { stderr } = await nextBuild(appDir, [], {
stdout: true,
stderr: true,
})
const pages = []
// collect pages to be ['/page', '/page-1', ... etc.]
pages.forEach(page => {
expect(stderr).toContain(page)
})
})
```
2020-05-26 21:50:25 +02:00
)
2019-12-03 17:18:58 +01:00
2021-01-10 02:12:13 +01:00
if ( telemetry ) {
await telemetry . flush ( )
}
2021-08-12 21:54:49 +02:00
await endWorkerPromise
2021-01-10 02:12:13 +01:00
} )
2017-05-08 00:47:40 +02:00
}