Fix VS Code debugging (#66254)

~Due to the entry preloading that was enabled by default in #65289, VS
Code is no longer able to map symbols correctly for production builds.
As a temporary solution, we can disable the preloading when a debugger
is started until a proper fix is found.~

By optionally building the Next.js source code with
`NEXT_SERVER_EVAL_SOURCE_MAPS=1` we can ensure, even with the bundled
next server in the node runtime, that the original names are shown in
the debug "Variables" section.

In addition, the `sourceMapPathOverrides` are improved to cover the
different variations of source mapping URLs. We can now also set
breakpoints in the `example/...` and `test/e2e/...` server components.

~Supersedes #66229~

#### Before

<img width="1276" alt="Screenshot 2024-05-27 at 21 36 52"
src="https://github.com/vercel/next.js/assets/761683/f2840c35-f683-445d-bc95-cac9f719d8e7">

#### After

<img width="1276" alt="Screenshot 2024-05-27 at 21 38 42"
src="https://github.com/vercel/next.js/assets/761683/c801c123-3163-46c3-b442-5b72c0a5d51d">
This commit is contained in:
Hendrik Liebau 2024-07-05 16:04:35 +02:00 committed by GitHub
parent a1098cec4d
commit bda92a1be5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 137 additions and 24 deletions

135
.vscode/launch.json vendored
View file

@ -3,7 +3,77 @@
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"inputs": [
{
"id": "appDirname",
"type": "promptString",
"description": "Enter an app dirname from examples or test/e2e",
"default": "examples/hello-world"
},
{
"id": "nextCommand",
"type": "pickString",
"description": "Select the next command",
"options": ["dev", "build", "start"],
"default": "dev"
},
{
"id": "nextTestMode",
"type": "pickString",
"description": "Select the next test mode",
"options": ["dev", "start"],
"default": "dev"
}
],
"configurations": [
{
"name": "Launch app",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "node",
"runtimeArgs": [
"packages/next/dist/bin/next",
"${input:nextCommand}",
"${input:appDirname}"
],
"skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": {
"webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/${input:appDirname}/$1/$2",
"webpack://_N_E/[.]/(.*)": "${workspaceFolder}/${input:appDirname}/.next/server/$1",
"webpack://_N_E/(?:../)*src/(.*)": "${workspaceFolder}/packages/next/src/$1",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*",
"webpack:///./app/(.*)": "${workspaceFolder}/${input:appDirname}/app/$1"
},
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1",
"NEXT_TELEMETRY_DISABLED": "1"
}
},
{
"name": "Launch current directory",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "node",
"runtimeArgs": [
"packages/next/dist/bin/next",
"${input:nextCommand}",
"${fileDirname}"
],
"skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": {
"webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/${fileDirname}/$1/$2",
"webpack://_N_E/[.]/(.*)": "${workspaceFolder}/${fileDirname}/.next/server/$1",
"webpack://_N_E/(?:../)*src/(.*)": "${workspaceFolder}/packages/next/src/$1",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*",
"webpack:///./app/(.*)": "${workspaceFolder}/${fileDirname}/app/$1"
},
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1",
"NEXT_TELEMETRY_DISABLED": "1"
}
},
{
"name": "Launch test/e2e/app-dir/app development",
"type": "node",
@ -17,8 +87,11 @@
],
"skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": {
"webpack://_N_E/../../../*": "${workspaceFolder}/packages/next/*",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*"
"webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/test/e2e/app-dir/app/$1/$2",
"webpack://_N_E/[.]/(.*)": "${workspaceFolder}/test/e2e/app-dir/app/.next/server/$1",
"webpack://_N_E/(?:../)*src/(.*)": "${workspaceFolder}/packages/next/src/$1",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*",
"webpack:///./app/(.*)": "${workspaceFolder}/test/e2e/app-dir/app/app/$1"
},
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1",
@ -38,8 +111,11 @@
],
"skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": {
"webpack://_N_E/../../../*": "${workspaceFolder}/packages/next/*",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*"
"webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/test/e2e/app-dir/app/$1/$2",
"webpack://_N_E/[.]/(.*)": "${workspaceFolder}/test/e2e/app-dir/app/.next/server/$1",
"webpack://_N_E/(?:../)*src/(.*)": "${workspaceFolder}/packages/next/src/$1",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*",
"webpack:///./app/(.*)": "${workspaceFolder}/test/e2e/app-dir/app/app/$1"
},
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1",
@ -59,8 +135,11 @@
],
"skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": {
"webpack://_N_E/../../../*": "${workspaceFolder}/packages/next/*",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*"
"webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/examples/hello-world/$1/$2",
"webpack://_N_E/[.]/(.*)": "${workspaceFolder}/examples/hello-world/.next/server/$1",
"webpack://_N_E/(?:../)*src/(.*)": "${workspaceFolder}/packages/next/src/$1",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*",
"webpack:///./app/(.*)": "${workspaceFolder}/examples/hello-world/app/$1"
},
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1",
@ -79,8 +158,11 @@
"examples/hello-world"
],
"sourceMapPathOverrides": {
"webpack://_N_E/../../../*": "${workspaceFolder}/packages/next/*",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*"
"webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/examples/hello-world/$1/$2",
"webpack://_N_E/[.]/(.*)": "${workspaceFolder}/examples/hello-world/.next/server/$1",
"webpack://_N_E/(?:../)*src/(.*)": "${workspaceFolder}/packages/next/src/$1",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*",
"webpack:///./app/(.*)": "${workspaceFolder}/examples/hello-world/app/$1"
},
"skipFiles": ["<node_internals>/**"],
"env": {
@ -100,8 +182,11 @@
],
"skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": {
"webpack://_N_E/../../../*": "${workspaceFolder}/packages/next/*",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*"
"webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/examples/hello-world/$1/$2",
"webpack://_N_E/[.]/(.*)": "${workspaceFolder}/examples/hello-world/.next/server/$1",
"webpack://_N_E/(?:../)*src/(.*)": "${workspaceFolder}/packages/next/src/$1",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*",
"webpack:///./app/(.*)": "${workspaceFolder}/examples/hello-world/app/$1"
},
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1",
@ -117,14 +202,40 @@
"runtimeArgs": ["packages/next/dist/bin/next", "dev", "${fileDirname}"],
"skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": {
"webpack://_N_E/../../../*": "${workspaceFolder}/packages/next/*",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*"
"webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/${fileDirname}/$1/$2",
"webpack://_N_E/[.]/(.*)": "${workspaceFolder}/${fileDirname}/.next/server/$1",
"webpack://_N_E/(?:../)*src/(.*)": "${workspaceFolder}/packages/next/src/$1",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*",
"webpack:///./app/(.*)": "${workspaceFolder}/${fileDirname}/app/$1"
},
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1",
"NEXT_TELEMETRY_DISABLED": "1"
}
},
{
"name": "Run e2e test",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/jest",
"runtimeArgs": ["--runInBand", "--verbose", "${file}"],
"console": "integratedTerminal",
"skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": {
"webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/${fileDirname}/$1/$2",
"webpack://_N_E/[.]/(.*)": "${workspaceFolder}/${fileDirname}/.next/server/$1",
"webpack://_N_E/(?:../)*src/(.*)": "${workspaceFolder}/packages/next/src/$1",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*",
"webpack:///./app/(.*)": "${workspaceFolder}/${fileDirname}/app/$1"
},
"env": {
"HEADLESS": "true",
"NEXT_E2E_TEST_TIMEOUT": "1000000",
"NEXT_SKIP_ISOLATE": "1",
"NEXT_TEST_MODE": "${input:nextTestMode}"
}
},
{
"name": "Launch app build trace jaeger",
"type": "node",

View file

@ -6,22 +6,22 @@ The Next.js monorepo provides configurations in the [`.vscode/launch.json`](../.
The common configurations are:
- Launch app development: Run `next dev` with an attached debugger
- Launch app build: Run `next build` with an attached debugger
- Launch app production: Run `next start` with an attached debugger
- **Launch app**: Run `next dev`, `next build`, or `next start` in a directory of your choice, with an attached debugger.
- **Launch current directory**: Run `next dev`, `next build`, or `next start` in the directory of the currently active file, with an attached debugger.
- **Run e2e test**: Run an e2e test using the currently active file, with an attached debugger.
### Run a specific app
Any Next.js app inside the monorepo can be debugged with these configurations. For example to run "Launch app development" against `examples/hello-world`:
Any Next.js app inside the monorepo can be debugged with these configurations.
1. Open the [`.vscode/launch.json`](../../.vscode/launch.json) file.
2. Find the configuration "Launch app development".
3. Edit the `runtimeArgs` array's last item to be `"examples/hello-world"`.
4. Save the file.
5. Now you can start the debugger and it will run against the `examples/hello-world` app!
1. Use the status bar, or the "Run and Debug" item in the Activity Bar, to select the "Launch app" launch configuration.
2. Enter the app dirname, e.g. `examples/hello-world` or `test/e2e/app-dir/app`.
3. Select the `next` command from the presented options (`dev`, `build`, or `start`).
To see the changes you make to the Next.js codebase during development, you can run `pnpm dev` in the root directory, which will watch for file changes in `packages/next` and recompile the Next.js source code on any file saves.
## Breakpoints
When developing/debugging Next.js, you can set breakpoints anywhere in the `packages/next` source code that will stop the debugger at certain locations so you can examine the behavior. Read more about [breakpoints in the VS Code documentation](https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_breakpoints).
To ensure that the original names are displayed in the "Variables" section, build the Next.js source code with `NEXT_SERVER_EVAL_SOURCE_MAPS=1`. This is automatically applied when using `pnpm dev`.

View file

@ -76,7 +76,7 @@
"next": "./dist/bin/next"
},
"scripts": {
"dev": "taskr",
"dev": "NEXT_SERVER_EVAL_SOURCE_MAPS=1 taskr",
"release": "taskr release",
"build": "pnpm release",
"prepublishOnly": "cd ../../ && turbo run build",

View file

@ -584,7 +584,7 @@ export async function ncc_react_refresh_utils(task, opts) {
await rmrf(destDir)
await fs.mkdir(destDir, { recursive: true })
const files = glob.sync('**/*.{js,json}', { cwd: srcDir })
const files = glob.sync('**/*.{js,json,map}', { cwd: srcDir })
for (const file of files) {
if (file === 'tsconfig.json') continue

View file

@ -152,7 +152,9 @@ module.exports = ({ dev, turbo, bundleType, experimental }) => {
}.runtime.${dev ? 'dev' : 'prod'}.js`,
libraryTarget: 'commonjs2',
},
devtool: 'source-map',
devtool: process.env.NEXT_SERVER_EVAL_SOURCE_MAPS
? 'eval-source-map'
: 'source-map',
optimization: {
moduleIds: 'named',
minimize: true,