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. // Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "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": [ "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", "name": "Launch test/e2e/app-dir/app development",
"type": "node", "type": "node",
@ -17,8 +87,11 @@
], ],
"skipFiles": ["<node_internals>/**"], "skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": { "sourceMapPathOverrides": {
"webpack://_N_E/../../../*": "${workspaceFolder}/packages/next/*", "webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/test/e2e/app-dir/app/$1/$2",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*" "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": { "env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1", "NEXT_PRIVATE_LOCAL_WEBPACK": "1",
@ -38,8 +111,11 @@
], ],
"skipFiles": ["<node_internals>/**"], "skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": { "sourceMapPathOverrides": {
"webpack://_N_E/../../../*": "${workspaceFolder}/packages/next/*", "webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/test/e2e/app-dir/app/$1/$2",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*" "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": { "env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1", "NEXT_PRIVATE_LOCAL_WEBPACK": "1",
@ -59,8 +135,11 @@
], ],
"skipFiles": ["<node_internals>/**"], "skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": { "sourceMapPathOverrides": {
"webpack://_N_E/../../../*": "${workspaceFolder}/packages/next/*", "webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/examples/hello-world/$1/$2",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*" "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": { "env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1", "NEXT_PRIVATE_LOCAL_WEBPACK": "1",
@ -79,8 +158,11 @@
"examples/hello-world" "examples/hello-world"
], ],
"sourceMapPathOverrides": { "sourceMapPathOverrides": {
"webpack://_N_E/../../../*": "${workspaceFolder}/packages/next/*", "webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/examples/hello-world/$1/$2",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*" "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>/**"], "skipFiles": ["<node_internals>/**"],
"env": { "env": {
@ -100,8 +182,11 @@
], ],
"skipFiles": ["<node_internals>/**"], "skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": { "sourceMapPathOverrides": {
"webpack://_N_E/../../../*": "${workspaceFolder}/packages/next/*", "webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/examples/hello-world/$1/$2",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*" "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": { "env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1", "NEXT_PRIVATE_LOCAL_WEBPACK": "1",
@ -117,14 +202,40 @@
"runtimeArgs": ["packages/next/dist/bin/next", "dev", "${fileDirname}"], "runtimeArgs": ["packages/next/dist/bin/next", "dev", "${fileDirname}"],
"skipFiles": ["<node_internals>/**"], "skipFiles": ["<node_internals>/**"],
"sourceMapPathOverrides": { "sourceMapPathOverrides": {
"webpack://_N_E/../../../*": "${workspaceFolder}/packages/next/*", "webpack://_N_E/[.]/(app|pages)/(.*)": "${workspaceFolder}/${fileDirname}/$1/$2",
"webpack://next/./dist/src/*": "${workspaceFolder}/packages/next/src/*" "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": { "env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1", "NEXT_PRIVATE_LOCAL_WEBPACK": "1",
"NEXT_TELEMETRY_DISABLED": "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", "name": "Launch app build trace jaeger",
"type": "node", "type": "node",

View file

@ -6,22 +6,22 @@ The Next.js monorepo provides configurations in the [`.vscode/launch.json`](../.
The common configurations are: The common configurations are:
- Launch app development: Run `next dev` 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 app build: Run `next build` 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.
- Launch app production: Run `next start` with an attached debugger - **Run e2e test**: Run an e2e test using the currently active file, with an attached debugger.
### Run a specific app ### 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. 1. Use the status bar, or the "Run and Debug" item in the Activity Bar, to select the "Launch app" launch configuration.
2. Find the configuration "Launch app development". 2. Enter the app dirname, e.g. `examples/hello-world` or `test/e2e/app-dir/app`.
3. Edit the `runtimeArgs` array's last item to be `"examples/hello-world"`. 3. Select the `next` command from the presented options (`dev`, `build`, or `start`).
4. Save the file.
5. Now you can start the debugger and it will run against the `examples/hello-world` app!
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. 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 ## 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). 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" "next": "./dist/bin/next"
}, },
"scripts": { "scripts": {
"dev": "taskr", "dev": "NEXT_SERVER_EVAL_SOURCE_MAPS=1 taskr",
"release": "taskr release", "release": "taskr release",
"build": "pnpm release", "build": "pnpm release",
"prepublishOnly": "cd ../../ && turbo run build", "prepublishOnly": "cd ../../ && turbo run build",

View file

@ -584,7 +584,7 @@ export async function ncc_react_refresh_utils(task, opts) {
await rmrf(destDir) await rmrf(destDir)
await fs.mkdir(destDir, { recursive: true }) 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) { for (const file of files) {
if (file === 'tsconfig.json') continue if (file === 'tsconfig.json') continue

View file

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