未验证 提交 435bf657 编写于 作者: J James Mosier 提交者: GitHub

Warn/revert custom devtool in development mode (#14285)

Warn users and revert their `devtool` when they manually change the `devtool` in development mode. For this addition, I check to ensure the `devtool` is custom (i.e. different than what is set by Next) and has a value (`false` is fine as a custom `devtool`!).

As described in [this issue (13963)](https://github.com/vercel/next.js/issues/13963), changing the `devtool` in development mode can cause issues with performance.

Fixes #13963
上级 afa9bab1
# Improper webpack `devtool` used in development mode
#### Why This Error Occurred
Next.js chooses the most optimal `devtool` for use with webpack. Changing the `devtool` in development mode will cause severe performance regressions with your application.
#### Possible Ways to Fix It
Please remove the custom `devtool` override or only apply it to production builds in your `next.config.js`.
```js
module.exports = {
webpack: (config, options) => {
if (!options.dev) {
config.devtool = options.isServer ? false : 'your-custom-devtool'
}
return config
},
}
```
import { codeFrameColumns } from '@babel/code-frame'
import ReactRefreshWebpackPlugin from '@next/react-refresh-utils/ReactRefreshWebpackPlugin'
import crypto from 'crypto'
import { readFileSync } from 'fs'
......@@ -5,6 +6,7 @@ import chalk from 'next/dist/compiled/chalk'
import TerserPlugin from 'next/dist/compiled/terser-webpack-plugin'
import path from 'path'
import webpack from 'webpack'
import type { Configuration } from 'webpack'
import {
DOT_NEXT_ALIAS,
NEXT_PROJECT_ROOT,
......@@ -21,6 +23,7 @@ import {
SERVERLESS_DIRECTORY,
SERVER_DIRECTORY,
} from '../next-server/lib/constants'
import { execOnce } from '../next-server/lib/utils'
import { findPageFile } from '../server/lib/find-page-file'
import { WebpackEntrypoints } from './entries'
import {
......@@ -44,12 +47,11 @@ import { ReactLoadablePlugin } from './webpack/plugins/react-loadable-plugin'
import { ServerlessPlugin } from './webpack/plugins/serverless-plugin'
import WebpackConformancePlugin, {
DuplicatePolyfillsConformanceCheck,
GranularChunksConformanceCheck,
MinificationConformanceCheck,
ReactSyncScriptsConformanceCheck,
GranularChunksConformanceCheck,
} from './webpack/plugins/webpack-conformance-plugin'
import { WellKnownErrorsPlugin } from './webpack/plugins/wellknown-errors-plugin'
import { codeFrameColumns } from '@babel/code-frame'
type ExcludesFalse = <T>(x: T | false) => x is T
......@@ -61,6 +63,15 @@ const escapePathVariables = (value: any) => {
: value
}
const devtoolRevertWarning = execOnce((devtool: Configuration['devtool']) => {
console.warn(
chalk.yellow.bold('Warning: ') +
chalk.bold(`Reverting webpack devtool to '${devtool}'.\n`) +
'Changing the webpack devtool in development mode will cause severe performance regressions.\n' +
'Read more: https://err.sh/next.js/improper-devtool'
)
})
function parseJsonFile(filePath: string) {
const JSON5 = require('next/dist/compiled/json5')
const contents = readFileSync(filePath, 'utf8')
......@@ -1002,6 +1013,7 @@ export default async function getBaseWebpackConfig(
productionBrowserSourceMaps,
})
let originalDevtool = webpackConfig.devtool
if (typeof config.webpack === 'function') {
webpackConfig = config.webpack(webpackConfig, {
dir,
......@@ -1014,6 +1026,11 @@ export default async function getBaseWebpackConfig(
webpack,
})
if (dev && originalDevtool !== webpackConfig.devtool) {
webpackConfig.devtool = originalDevtool
devtoolRevertWarning(originalDevtool)
}
if (typeof (webpackConfig as any).then === 'function') {
console.warn(
'> Promise returned in next config. https://err.sh/vercel/next.js/promise-in-next-config'
......
module.exports = {
webpack: (config) => {
config.devtool = false
return config
},
}
import { useEffect } from 'react'
export default function Index(props) {
useEffect(() => {
throw new Error('this should render')
}, [])
return <div>Index Page</div>
}
/* eslint-env jest */
import {
check,
findPort,
getRedboxSource,
hasRedbox,
killApp,
launchApp,
} from 'next-test-utils'
import webdriver from 'next-webdriver'
import { join } from 'path'
jest.setTimeout(1000 * 30)
const appDir = join(__dirname, '../')
describe('devtool set in developmemt mode in next config', () => {
it('should warn and revert when a devtool is set in development mode', async () => {
let stderr = ''
const appPort = await findPort()
const app = await launchApp(appDir, appPort, {
env: { __NEXT_TEST_WITH_DEVTOOL: true },
onStderr(msg) {
stderr += msg || ''
},
})
const found = await check(
() => stderr,
/Reverting webpack devtool to /,
false
)
const browser = await webdriver(appPort, '/')
expect(await hasRedbox(browser)).toBe(true)
if (process.platform === 'win32') {
// TODO: add win32 snapshot
} else {
expect(await getRedboxSource(browser)).toMatchInlineSnapshot(`
"pages/index.js (5:10) @ eval
3 | export default function Index(props) {
4 | useEffect(() => {
> 5 | throw new Error('this should render')
| ^
6 | }, [])
7 | return <div>Index Page</div>
8 | }"
`)
}
await browser.close()
await killApp(app)
expect(found).toBeTruthy()
})
})
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册