Skip to content

Commit

Permalink
Merge branch 'canary' into feature/monorepo-managed
Browse files Browse the repository at this point in the history
  • Loading branch information
ijjk committed Oct 21, 2021
2 parents 090bb4d + dd81d2c commit 69dccb3
Show file tree
Hide file tree
Showing 13 changed files with 81 additions and 66 deletions.
27 changes: 16 additions & 11 deletions packages/next/build/compiler.ts
@@ -1,21 +1,25 @@
import { webpack } from 'next/dist/compiled/webpack/webpack'
import type webpack5 from 'webpack5'
import { Span } from '../trace'

export type CompilerResult = {
errors: string[]
warnings: string[]
errors: webpack5.StatsError[]
warnings: webpack5.StatsError[]
}

function generateStats(
result: CompilerResult,
stat: webpack.Stats
stat: webpack5.Stats
): CompilerResult {
const { errors, warnings } = stat.toJson('errors-warnings')
if (errors.length > 0) {
const { errors, warnings } = stat.toJson({
preset: 'errors-warnings',
moduleTrace: true,
})
if (errors && errors.length > 0) {
result.errors.push(...errors)
}

if (warnings.length > 0) {
if (warnings && warnings.length > 0) {
result.warnings.push(...warnings)
}

Expand All @@ -24,7 +28,7 @@ function generateStats(

// Webpack 5 requires the compiler to be closed (to save caches)
// Webpack 4 does not have this close method so in order to be backwards compatible we check if it exists
function closeCompiler(compiler: webpack.Compiler | webpack.MultiCompiler) {
function closeCompiler(compiler: webpack5.Compiler | webpack5.MultiCompiler) {
return new Promise<void>((resolve, reject) => {
// @ts-ignore Close only exists on the compiler in webpack 5
return compiler.close((err: any) => (err ? reject(err) : resolve()))
Expand All @@ -36,18 +40,19 @@ export function runCompiler(
{ runWebpackSpan }: { runWebpackSpan: Span }
): Promise<CompilerResult> {
return new Promise((resolve, reject) => {
const compiler = webpack(config)
compiler.run((err: Error, stats: webpack.Stats) => {
const compiler = webpack(config) as unknown as webpack5.Compiler
compiler.run((err, stats) => {
const webpackCloseSpan = runWebpackSpan.traceChild('webpack-close', {
name: config.name,
})
webpackCloseSpan
.traceAsyncFn(() => closeCompiler(compiler))
.then(() => {
if (!stats) throw new Error('No Stats from webpack')
if (err) {
const reason = err?.toString()
const reason = err?.stack ?? err?.toString()
if (reason) {
return resolve({ errors: [reason], warnings: [] })
return resolve({ errors: [{ message: reason }], warnings: [] })
}
return reject(err)
}
Expand Down
30 changes: 19 additions & 11 deletions packages/next/build/index.ts
Expand Up @@ -94,7 +94,7 @@ import { PagesManifest } from './webpack/plugins/pages-manifest-plugin'
import { writeBuildId } from './write-build-id'
import { normalizeLocalePath } from '../shared/lib/i18n/normalize-locale-path'
import { NextConfigComplete } from '../server/config-shared'
import isError from '../lib/is-error'
import isError, { NextError } from '../lib/is-error'
import { TelemetryPlugin } from './webpack/plugins/telemetry-plugin'
import { MiddlewareManifest } from './webpack/plugins/middleware-plugin'

Expand Down Expand Up @@ -614,13 +614,13 @@ export default async function build(

result = nextBuildSpan
.traceChild('format-webpack-messages')
.traceFn(() => formatWebpackMessages(result))
.traceFn(() => formatWebpackMessages(result, true))

if (result.errors.length > 0) {
// Only keep the first error. Others are often indicative
// Only keep the first few errors. Others are often indicative
// of the same problem, but confuse the reader with noise.
if (result.errors.length > 1) {
result.errors.length = 1
if (result.errors.length > 5) {
result.errors.length = 5
}
const error = result.errors.join('\n\n')

Expand All @@ -645,11 +645,17 @@ export default async function build(
error.indexOf('private-next-pages') > -1 ||
error.indexOf('__next_polyfill__') > -1
) {
throw new Error(
'> webpack config.resolve.alias was incorrectly overridden. https://nextjs.org/docs/messages/invalid-resolve-alias'
)
const err = new Error(
'webpack config.resolve.alias was incorrectly overridden. https://nextjs.org/docs/messages/invalid-resolve-alias'
) as NextError
err.code = 'INVALID_RESOLVE_ALIAS'
throw err
}
throw new Error('> Build failed because of webpack errors')
const err = new Error(
'Build failed because of webpack errors'
) as NextError
err.code = 'WEBPACK_ERRORS'
throw err
} else {
telemetry.record(
eventBuildCompleted(pagePaths, {
Expand Down Expand Up @@ -1125,15 +1131,17 @@ export default async function build(
!customAppGetInitialProps && (!hasNonStaticErrorPage || hasPages404)

if (invalidPages.size > 0) {
throw new Error(
const err = new Error(
`Build optimization failed: found page${
invalidPages.size === 1 ? '' : 's'
} without a React Component as default export in \n${[...invalidPages]
.map((pg) => `pages${pg}`)
.join(
'\n'
)}\n\nSee https://nextjs.org/docs/messages/page-without-valid-component for more info.\n`
)
) as NextError
err.code = 'BUILD_OPTIMIZATION_FAILED'
throw err
}

await writeBuildId(distDir, buildId)
Expand Down
5 changes: 4 additions & 1 deletion packages/next/build/output/index.ts
Expand Up @@ -235,7 +235,10 @@ export function watchCompilers(
buildStore.setState({ amp: {} })

const { errors, warnings } = formatWebpackMessages(
stats.toJson({ all: false, warnings: true, errors: true })
stats.toJson({
preset: 'error-warnings',
moduleTrace: true,
})
)

const hasErrors = !!errors?.length
Expand Down
5 changes: 0 additions & 5 deletions packages/next/build/webpack/config/blocks/base.ts
Expand Up @@ -11,11 +11,6 @@ export const base = curry(function base(
// @ts-ignore TODO webpack 5 typings
config.target = ctx.isServer ? 'node12.22' : ['web', 'es5']

// Stop compilation early in a production build when an error is encountered.
// This behavior isn't desirable in development due to how the HMR system
// works, but is a good default for production.
config.bail = ctx.isProduction

// https://webpack.js.org/configuration/devtool/#development
if (ctx.isDevelopment) {
if (process.env.__NEXT_TEST_MODE && !process.env.__NEXT_TEST_WITH_DEVTOOL) {
Expand Down
13 changes: 11 additions & 2 deletions packages/next/cli/next-build.ts
Expand Up @@ -69,8 +69,17 @@ const nextBuild: cliCommand = (argv) => {
!args['--no-lint']
).catch((err) => {
console.error('')
console.error('> Build error occurred')
printAndExit(err)
if (
isError(err) &&
(err.code === 'INVALID_RESOLVE_ALIAS' ||
err.code === 'WEBPACK_ERRORS' ||
err.code === 'BUILD_OPTIMIZATION_FAILED')
) {
printAndExit(`> ${err.message}`)
} else {
console.error('> Build error occurred')
printAndExit(err)
}
})
}

Expand Down
@@ -1 +1 @@
export default function formatWebpackMessages(json: any): any
export default function formatWebpackMessages(json: any, verbose?: boolean): any
29 changes: 20 additions & 9 deletions packages/next/client/dev/error-overlay/format-webpack-messages.js
Expand Up @@ -32,13 +32,25 @@ function isLikelyASyntaxError(message) {
}

// Cleans up webpack error messages.
function formatMessage(message) {
function formatMessage(message, verbose) {
// TODO: Replace this once webpack 5 is stable
if (typeof message === 'object' && message.message) {
message =
(message.moduleName ? stripAnsi(message.moduleName) + '\n' : '') +
(message.file ? stripAnsi(message.file) + '\n' : '') +
message.message
message.message +
(message.details && verbose ? '\n' + message.details : '') +
(message.moduleTrace && verbose
? '\n\nImport trace for requested module:' +
message.moduleTrace
.filter(
(trace) =>
!trace.originName.includes('next-client-pages-loader.js')
)
.map((trace) => `\n${trace.originName}`)
.join('')
: '') +
(message.stack && verbose ? '\n' + message.stack : '')
}
let lines = message.split('\n')

Expand Down Expand Up @@ -84,8 +96,6 @@ function formatMessage(message) {
if (lines.length > 2 && lines[1].trim() === '') {
lines.splice(1, 1)
}
// Clean up file name
lines[0] = lines[0].replace(/^(.*) \d+:\d+(?:-\d+)?$/, '$1')

// Cleans up verbose "module not found" messages for files and packages.
if (lines[1] && lines[1].indexOf('Module not found: ') === 0) {
Expand All @@ -94,7 +104,7 @@ function formatMessage(message) {
lines[1]
.replace('Error: ', '')
.replace('Module not found: Cannot find file:', 'Cannot find file:'),
...lines.slice(2).filter((line) => line.indexOf(' @ ') !== 0),
...lines.slice(2),
]
}

Expand Down Expand Up @@ -132,17 +142,18 @@ function formatMessage(message) {
return message.trim()
}

function formatWebpackMessages(json) {
function formatWebpackMessages(json, verbose) {
const formattedErrors = json.errors.map(function (message) {
return formatMessage(message, true)
return formatMessage(message, verbose)
})
const formattedWarnings = json.warnings.map(function (message) {
return formatMessage(message, false)
return formatMessage(message, verbose)
})
const result = { errors: formattedErrors, warnings: formattedWarnings }
if (result.errors.some(isLikelyASyntaxError)) {
if (!verbose && result.errors.some(isLikelyASyntaxError)) {
// If there are any syntax errors, show just them.
result.errors = result.errors.filter(isLikelyASyntaxError)
result.warnings = []
}
return result
}
Expand Down
2 changes: 1 addition & 1 deletion packages/next/lib/is-error.ts
@@ -1,5 +1,5 @@
// We allow some additional attached properties for Errors
interface NextError extends Error {
export interface NextError extends Error {
type?: string
page?: string
code?: string | number
Expand Down
4 changes: 1 addition & 3 deletions packages/next/types/index.d.ts
Expand Up @@ -25,9 +25,7 @@ import {
import next from '../dist/server/next'

// @ts-ignore This path is generated at build time and conflicts otherwise
import { NextConfig as NextConfigType } from '../dist/server/config'

export type NextConfig = NextConfigType
export { NextConfig } from '../dist/server/config'

// Extend the React types with missing properties
declare module 'react' {
Expand Down
11 changes: 1 addition & 10 deletions test/integration/config-mjs/next.config.mjs
Expand Up @@ -14,16 +14,7 @@ export default {
env: {
customVar: 'hello',
},
webpack(config, { dev, buildId, webpack }) {
if (dev) {
if (config.bail !== false) {
throw new Error('Wrong bail value for development!')
}
} else {
if (config.bail !== true) {
throw new Error('Wrong bail value for production!')
}
}
webpack(config, { buildId, webpack }) {
config.plugins.push(
new webpack.DefinePlugin({
'process.env.CONFIG_BUILD_ID': JSON.stringify(buildId),
Expand Down
11 changes: 1 addition & 10 deletions test/integration/config/next.config.js
Expand Up @@ -14,16 +14,7 @@ module.exports = {
env: {
customVar: 'hello',
},
webpack(config, { dev, buildId, webpack }) {
if (dev) {
if (config.bail !== false) {
throw new Error('Wrong bail value for development!')
}
} else {
if (config.bail !== true) {
throw new Error('Wrong bail value for production!')
}
}
webpack(config, { buildId, webpack }) {
config.plugins.push(
new webpack.DefinePlugin({
'process.env.CONFIG_BUILD_ID': JSON.stringify(buildId),
Expand Down
Expand Up @@ -99,8 +99,10 @@ describe('Build Error Tests for basePath', () => {
await indexPage.restore()

expect(stderr).toContain(
"Error: Can't resolve '../public/foo/test-rect-broken.jpg"
"Module not found: Can't resolve '../public/foo/test-rect-broken.jpg"
)
// should contain the importing module
expect(stderr).toContain('./pages/static-img.js')
})
})
describe('Static Image Component Tests for basePath', () => {
Expand Down
4 changes: 3 additions & 1 deletion test/integration/image-component/default/test/static.test.js
Expand Up @@ -87,8 +87,10 @@ describe('Build Error Tests', () => {
await indexPage.restore()

expect(stderr).toContain(
"Error: Can't resolve '../public/foo/test-rect-broken.jpg"
"Module not found: Can't resolve '../public/foo/test-rect-broken.jpg"
)
// should contain the importing module
expect(stderr).toContain('./pages/static-img.js')
})
})
describe('Static Image Component Tests', () => {
Expand Down

0 comments on commit 69dccb3

Please sign in to comment.