Skip to content

Commit

Permalink
Display experimental features for next build (#57152)
Browse files Browse the repository at this point in the history
Display full information of experimental features in `next build`, so we'll have full insights for build logs


Close NEXT-1697

* `next build`
<img width="668" alt="image" src="https://github.com/vercel/next.js/assets/4800338/6ab75923-0336-4624-905f-347fedbff5a9">
  • Loading branch information
huozhi authored Oct 20, 2023
1 parent 4d31506 commit e6fbeab
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 82 deletions.
10 changes: 10 additions & 0 deletions packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ import { nodeFs } from '../server/lib/node-fs-methods'
import { collectBuildTraces } from './collect-build-traces'
import type { BuildTraceContext } from './webpack/plugins/next-trace-entrypoints-plugin'
import { formatManifest } from './manifests/formatter/format-manifest'
import { getStartServerInfo, logStartInfo } from '../server/lib/app-info-log'

interface ExperimentalBypassForInfo {
experimentalBypassFor?: RouteHas[]
Expand Down Expand Up @@ -502,6 +503,15 @@ export default async function build(
},
} as any

const { envInfo, expFeatureInfo } = await getStartServerInfo(dir)
logStartInfo({
networkUrl: null,
appUrl: null,
formatDurationText: null,
envInfo,
expFeatureInfo,
})

if (!isGenerate) {
buildSpinner = createSpinner('Creating an optimized production build')
}
Expand Down
28 changes: 3 additions & 25 deletions packages/next/src/cli/next-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import path from 'path'
import type { NextConfigComplete } from '../server/config-shared'
import { setGlobal, traceGlobals } from '../trace/shared'
import { Telemetry } from '../telemetry/storage'
import loadConfig, { getEnabledExperimentalFeatures } from '../server/config'
import loadConfig from '../server/config'
import { findPagesDir } from '../lib/find-pages-dir'
import { fileExists, FileType } from '../lib/file-exists'
import { getNpxCommand } from '../lib/helpers/get-npx-command'
import { createSelfSignedCertificate } from '../lib/mkcert'
import type { SelfSignedCertificate } from '../lib/mkcert'
import uploadTrace from '../trace/upload-trace'
import { initialEnv, loadEnvConfig } from '@next/env'
import { initialEnv } from '@next/env'
import { trace } from '../trace'
import { validateTurboNextConfig } from '../lib/turbopack-warning'
import { fork } from 'child_process'
Expand Down Expand Up @@ -184,27 +184,7 @@ const nextDev: CliCommand = async (args) => {
// some set-ups that rely on listening on other interfaces
const host = args['--hostname']

const { loadedEnvFiles } = loadEnvConfig(dir, true, console, false)

let expFeatureInfo: string[] = []
config = await loadConfig(PHASE_DEVELOPMENT_SERVER, dir, {
onLoadUserConfig(userConfig) {
const userNextConfigExperimental = getEnabledExperimentalFeatures(
userConfig.experimental
)
expFeatureInfo = userNextConfigExperimental.sort(
(a, b) => a.length - b.length
)
},
})

// we need to reset env if we are going to create
// the worker process with the esm loader so that the
// initial env state is correct
let envInfo: string[] = []
if (loadedEnvFiles.length > 0) {
envInfo = loadedEnvFiles.map((f) => f.path)
}
config = await loadConfig(PHASE_DEVELOPMENT_SERVER, dir)

const isExperimentalTestProxy = args['--experimental-test-proxy']

Expand All @@ -219,8 +199,6 @@ const nextDev: CliCommand = async (args) => {
isDev: true,
hostname: host,
isExperimentalTestProxy,
envInfo,
expFeatureInfo,
}

if (args['--turbo']) {
Expand Down
81 changes: 81 additions & 0 deletions packages/next/src/server/lib/app-info-log.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { loadEnvConfig } from '@next/env'
import * as Log from '../../build/output/log'
import { bold, purple } from '../../lib/picocolors'
import { PHASE_DEVELOPMENT_SERVER } from '../../shared/lib/constants'
import loadConfig, { getEnabledExperimentalFeatures } from '../config'

export function logStartInfo({
networkUrl,
appUrl,
envInfo,
expFeatureInfo,
formatDurationText,
maxExperimentalFeatures,
}: {
networkUrl: string | null
appUrl: string | null
formatDurationText: string | null
maxExperimentalFeatures?: number
envInfo?: string[]
expFeatureInfo?: string[]
}) {
Log.bootstrap(
bold(purple(`${Log.prefixes.ready} Next.js ${process.env.__NEXT_VERSION}`))
)
if (appUrl) {
Log.bootstrap(`- Local: ${appUrl}`)
}
if (networkUrl) {
Log.bootstrap(`- Network: ${networkUrl}`)
}
if (envInfo?.length) Log.bootstrap(`- Environments: ${envInfo.join(', ')}`)

if (expFeatureInfo?.length) {
Log.bootstrap(`- Experiments (use at your own risk):`)
// only show maximum 3 flags
for (const exp of expFeatureInfo.slice(0, maxExperimentalFeatures)) {
Log.bootstrap(` · ${exp}`)
}
/* ${expFeatureInfo.length - 3} more */
if (expFeatureInfo.length > 3 && maxExperimentalFeatures) {
Log.bootstrap(` · ...`)
}
}

// New line after the bootstrap info
Log.info('')
if (formatDurationText) {
Log.event(`Ready in ${formatDurationText}`)
}
}

export async function getStartServerInfo(dir: string): Promise<{
envInfo?: string[]
expFeatureInfo?: string[]
}> {
let expFeatureInfo: string[] = []
await loadConfig(PHASE_DEVELOPMENT_SERVER, dir, {
onLoadUserConfig(userConfig) {
const userNextConfigExperimental = getEnabledExperimentalFeatures(
userConfig.experimental
)
expFeatureInfo = userNextConfigExperimental.sort(
(a, b) => a.length - b.length
)
},
})

// we need to reset env if we are going to create
// the worker process with the esm loader so that the
// initial env state is correct
let envInfo: string[] = []
const { loadedEnvFiles } = loadEnvConfig(dir, true, console, false)
if (loadedEnvFiles.length > 0) {
envInfo = loadedEnvFiles.map((f) => f.path)
}

return {
envInfo,
expFeatureInfo,
}
}
61 changes: 12 additions & 49 deletions packages/next/src/server/lib/start-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { formatHostname } from './format-hostname'
import { initialize } from './router-server'
import { checkIsNodeDebugging } from './is-node-debugging'
import { CONFIG_FILES } from '../../shared/lib/constants'
import { bold, purple } from '../../lib/picocolors'
import { getStartServerInfo, logStartInfo } from './app-info-log'

const debug = setupDebug('next:start-server')

Expand All @@ -33,9 +33,6 @@ export interface StartServerOptions {
customServer?: boolean
minimalMode?: boolean
keepAliveTimeout?: number
// logging info
envInfo?: string[]
expFeatureInfo?: string[]
// this is dev-server only
selfSignedCertificate?: SelfSignedCertificate
isExperimentalTestProxy?: boolean
Expand Down Expand Up @@ -78,47 +75,6 @@ export async function getRequestHandlers({
})
}

function logStartInfo({
networkUrl,
appUrl,
hostname,
envInfo,
expFeatureInfo,
formatDurationText,
}: {
networkUrl: string
appUrl: string
hostname: string
envInfo: string[] | undefined
expFeatureInfo: string[] | undefined
formatDurationText: string
}) {
Log.bootstrap(
bold(purple(`${Log.prefixes.ready} Next.js ${process.env.__NEXT_VERSION}`))
)
Log.bootstrap(`- Local: ${appUrl}`)
if (hostname) {
Log.bootstrap(`- Network: ${networkUrl}`)
}
if (envInfo?.length) Log.bootstrap(`- Environments: ${envInfo.join(', ')}`)

if (expFeatureInfo?.length) {
Log.bootstrap(`- Experiments (use at your own risk):`)
// only show maximum 3 flags
for (const exp of expFeatureInfo.slice(0, 3)) {
Log.bootstrap(` · ${exp}`)
}
/* ${expFeatureInfo.length - 3} more */
if (expFeatureInfo.length > 3) {
Log.bootstrap(` · ...`)
}
}

// New line after the bootstrap info
Log.info('')
Log.event(`Ready in ${formatDurationText}`)
}

export async function startServer({
dir,
port,
Expand All @@ -129,8 +85,6 @@ export async function startServer({
keepAliveTimeout,
isExperimentalTestProxy,
selfSignedCertificate,
envInfo,
expFeatureInfo,
}: StartServerOptions): Promise<void> {
let handlersReady = () => {}
let handlersError = () => {}
Expand Down Expand Up @@ -248,7 +202,7 @@ export async function startServer({

port = typeof addr === 'object' ? addr?.port || port : port

const networkUrl = `http://${actualHostname}:${port}`
const networkUrl = hostname ? `http://${actualHostname}:${port}` : null
const appUrl = `${
selfSignedCertificate ? 'https' : 'http'
}://${formattedHostname}:${port}`
Expand Down Expand Up @@ -311,13 +265,22 @@ export async function startServer({
: `${Math.round(startServerProcessDuration)}ms`

handlersReady()

// Only load env and config in dev to for logging purposes
let envInfo: string[] | undefined
let expFeatureInfo: string[] | undefined
if (isDev) {
const startServerInfo = await getStartServerInfo(dir)
envInfo = startServerInfo.envInfo
expFeatureInfo = startServerInfo.expFeatureInfo
}
logStartInfo({
networkUrl,
appUrl,
hostname,
envInfo,
expFeatureInfo,
formatDurationText,
maxExperimentalFeatures: 3,
})
} catch (err) {
// fatal error if we can't setup
Expand Down
Loading

0 comments on commit e6fbeab

Please sign in to comment.