Typescript breakpoints with VSCode



我从generator- expression -no-stress-typescript模板中构建了这个约曼脚手架项目。我需要调试它,就像"通过打字脚本代码的步骤"一样。使用Visual Studio Code(不,console.log()对我来说还不够)。

根据文档,我只需要发出

npm run dev:debug

,然后附加VSCode。这里有一个问题:如果我这样做,VSCode不能绑定断点。如果我让调试器停止在第一行执行("stopOnEntry": true),它停止在生成的JavaScript代码,而不是源TypeScript代码,和/但标签标题中的文件名显示"index.ts"(不是.js)

以下是package.json中的dev:debug脚本目标:

"dev:debug": "nodemon --exec "node -r ts-node/register --inspect-brk" server/index.ts | pino-pretty",

,这里是"附件"我的launch.json中的配置:

{
"name": "Debug (Attach)",
"port": 9229,
"request": "attach",
"cwd": "${workspaceFolder}",
"sourceMaps": true,
"skipFiles": ["<node_internals>/**"],
"type": "node",
// "outFiles": ["${workspaceFolder}/dist/**/*.js"],
},

由于这不起作用,我尝试了其他一些教程,其中一个(我不记得是哪个)让我将以下配置添加到我的launch.json中:

{
"name": "Run and debug",
"program": "${workspaceFolder}/server/index.ts",
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"type": "node",
// "outFiles": ["${workspaceFolder}/dist/**/*.js"],
"runtimeArgs": ["-r", "ts-node/register", "--preserve-symlinks"],
"runtimeExecutable": "node",
"args": ["--inspect", "${workspaceFolder}/server/index.ts"],
"cwd": "${workspaceFolder}",           
}

这一开始似乎很有希望,但是,当我尝试它时,它通过JS代码而不是TS步进,就像"调试(附加)"上面的配置。

这是生成的JS代码,调试器使用它来跟踪执行。请注意,它在末尾的注释中包含了源地图。

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _a, _b;
Object.defineProperty(exports, "__esModule", { value: true });
require("./common/env");
const server_1 = __importDefault(require("./common/server"));
const routes_1 = __importDefault(require("./routes"));
const models_1 = __importDefault(require("./api/models"));
const port = parseInt((_a = process.env.PORT) !== null && _a !== void 0 ? _a : '3000');
const syncdb = ((_b = process.env.SYNC_DB_SCHEMA_ON_STARTUP) !== null && _b !== void 0 ? _b : 'false') === 'true';
if (syncdb) {
models_1.default.sequelize.sync({ force: true }).then(() => {
console.log("DB Aggiornato");
}).catch((err) => {
console.log("Errore", err);
});
}
exports.default = new server_1.default().router(routes_1.default).listen(port);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiL2hvbWUvbHVjaW8vbXlhcHAvc2VydmVyL2luZGV4LnRzIiwic291cmNlcyI6WyIvaG9tZS9sdWNpby9teWFwcC9zZXJ2ZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsd0JBQXNCO0FBQ3RCLDZEQUFxQztBQUNyQyxzREFBOEI7QUFDOUIsMERBQThCO0FBQzlCLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxNQUFBLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxtQ0FBSSxNQUFNLENBQUMsQ0FBQztBQUdsRCxNQUFNLE1BQU0sR0FBRyxDQUFDLE1BQUEsT0FBTyxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsbUNBQUksT0FBTyxDQUFDLEtBQUssTUFBTSxDQUFDO0FBRTdFLElBQUksTUFBTSxFQUFFO0lBQ1IsZ0JBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRTtRQUN6QyxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQ2pDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQVEsRUFBRSxFQUFFO1FBQ2xCLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxDQUFBO0lBQzlCLENBQUMsQ0FBQyxDQUFDO0NBQ047QUFHRCxrQkFBZSxJQUFJLGdCQUFNLEVBQUUsQ0FBQyxNQUFNLENBQUMsZ0JBQU0sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAnLi9jb21tb24vZW52JztcbmltcG9ydCBTZXJ2ZXIgZnJvbSAnLi9jb21tb24vc2VydmVyJztcbmltcG9ydCByb3V0ZXMgZnJvbSAnLi9yb3V0ZXMnO1xuaW1wb3J0IGRiIGZyb20gJy4vYXBpL21vZGVscyc7XG5jb25zdCBwb3J0ID0gcGFyc2VJbnQocHJvY2Vzcy5lbnYuUE9SVCA/PyAnMzAwMCcpO1xuXG5cbmNvbnN0IHN5bmNkYiA9IChwcm9jZXNzLmVudi5TWU5DX0RCX1NDSEVNQV9PTl9TVEFSVFVQID8/ICdmYWxzZScpID09PSAndHJ1ZSc7XG5cbmlmIChzeW5jZGIpIHtcbiAgICBkYi5zZXF1ZWxpemUuc3luYyh7IGZvcmNlOiB0cnVlIH0pLnRoZW4oKCkgPT4ge1xuICAgICAgICBjb25zb2xlLmxvZyhcIkRCIEFnZ2lvcm5hdG9cIik7XG4gICAgfSkuY2F0Y2goKGVycjogYW55KSA9PiB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiRXJyb3JlXCIsIGVycilcbiAgICB9KTtcbn1cblxuXG5leHBvcnQgZGVmYXVsdCBuZXcgU2VydmVyKCkucm91dGVyKHJvdXRlcykubGlzdGVuKHBvcnQpOyJdfQ==

我解码了base64源映射,它似乎包含到我的源的正确路径,甚至源代码的副本:

{"version":3,"file":"/home/lucio/myapp/server/index.ts","sources":["/home/lucio/myapp/server/index.ts"],"names":[],"mappings":";;;;;;AAAA,wBAAsB;AACtB,6DAAqC;AACrC,sDAA8B;AAC9B,0DAA8B;AAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,IAAI,mCAAI,MAAM,CAAC,CAAC;AAGlD,MAAM,MAAM,GAAG,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,yBAAyB,mCAAI,OAAO,CAAC,KAAK,MAAM,CAAC;AAE7E,IAAI,MAAM,EAAE;IACR,gBAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;QACzC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAQ,EAAE,EAAE;QAClB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IAC9B,CAAC,CAAC,CAAC;CACN;AAGD,kBAAe,IAAI,gBAAM,EAAE,CAAC,MAAM,CAAC,gBAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC","sourcesContent":["import './common/env';nimport Server from './common/server';nimport routes from './routes';nimport db from './api/models';nconst port = parseInt(process.env.PORT ?? '3000');nnnconst syncdb = (process.env.SYNC_DB_SCHEMA_ON_STARTUP ?? 'false') === 'true';nnif (syncdb) {n    db.sequelize.sync({ force: true }).then(() => {n        console.log("DB Aggiornato");n    }).catch((err: any) => {n        console.log("Errore", err)n  

这是我的tsconfig.json,以防万一:

{
"compileOnSave": false,
"compilerOptions": {
"inlineSourceMap": true, // added after answer below, still doesn't work
"target": "ES2019",
"lib": ["ES2020"],
"strict": true,
"module": "commonjs",
"esModuleInterop": true,
"skipLibCheck": true,
"sourceMap": true,
"declaration": true,
"moduleResolution": "node",
"useUnknownInCatchVariables": false,
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"noUnusedParameters": true,
"noUnusedLocals": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": false,
"strictPropertyInitialization":false,
"alwaysStrict": true,
"outDir": "dist",
"typeRoots": ["node_modules/@types"],
"resolveJsonModule": true,
"baseUrl": "."
},
"include": ["server/**/*.ts", "server/api/models/index.ts"],
"exclude": ["node_modules", "./test/", "./dist"]
}

下面是npx ts-node --showConfig(后)的输出Beautifulcoder对他的回答的评论)

{
"ts-node": {
"cwd": "/home/lucio/myapp",
"projectSearchDir": "/home/lucio/myapp",
"project": "/home/lucio/myapp/tsconfig.json"
},
"compilerOptions": {
"target": "es2019",
"lib": [
"es2020"
],
"strict": true,
"module": "commonjs",
"esModuleInterop": true,
"skipLibCheck": true,
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"useUnknownInCatchVariables": false,
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"noUnusedParameters": true,
"noUnusedLocals": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": false,
"strictPropertyInitialization": false,
"alwaysStrict": true,
"outDir": "./.ts-node",
"typeRoots": [
"/home/lucio/myapp/node_modules/@types"
],
"resolveJsonModule": true,
"baseUrl": "./",
"inlineSourceMap": false, // PLEASE NOTE: this is false even after I added `"inlineSourceMap": true` in tsconfig.json above
"inlineSources": true,
"noEmit": false
}
}
我已经搭建了一个新的最小示例generator- expression -no-stress-typescript项目,再次遵循文档化的过程。例如
$ npm install -g yo generator-express-no-stress
$ yo express-no-stress ts-debug-test

选择"OpenAPI 3"超过"昂首阔步";当我第一次搭建真正的项目时,我就是这么做的。如果你需要一个最小的例子来显示问题,你也可以这样做,或者你可以在GitHub上找到我的,如果你喜欢的话。我只添加了我的启动器。你只需要在第一行有意义的代码中设置一个断点。

所以现在我不知道下一步要做什么,以调试我的代码…有线索吗?

我认为您的Debug (Attach)配置中的outFiles属性可能是问题所在。ts-node实际上并没有将生成的文件和源映射写入磁盘,所以如果VS Code在那里寻找它们,那么它将找不到它们。你应该能够删除这个属性。

我有一些使用ts-nodenodemon的代码库,基本上就是你在这里使用它们的方式,源代码映射工作得很好。我能看到的唯一区别是我的调试配置没有设置outFiles


编辑由于outFiles的事情没有工作,我能想到的唯一一件事就是它在tsconfig.json的东西。这是我的一个有用的方法。我猜可能是"inlineSourceMap": true

{
"compilerOptions": {
"target": "ES2018",
"module": "commonjs",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"inlineSourceMap": true,
"noImplicitAny": false,
"types": [
"webpack-env"
],
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx",
"../interface/**/*.ts"
],
"exclude": [
"node_modules"
]
}

这个问题是由我存储项目的路径中的符号链接引起的(真正的bug被触发了),例如

/home/lucio/myapp -> /home/lucio/workspace/vscode/myapp

真正的bug在VSCode中,在这里。

直接的解决方法是避免项目文件夹路径中的符号链接。

我目前的理论是你有调试脚本运行在nodemon后面。这是一个用于生产的节点进程监视器,而不是用于本地的调试目的。

试题:

{"dev:debug": "node -r ts-node/register --inspect-brk server/index.ts"}

正如我刚刚发现的-这可能是由于VSCode控制台没有使用适当的节点版本。

如果你使用nvm(或类似的东西)-这很容易发生。

安装程序无论如何都不能工作,这里列举的任何选项或任何其他类似的线程(意味着它确实启动了,但没有命中断点)。

但是一旦我添加了适当的版本到我的launch.json(在我的情况下"runtimeVersion": "12.22.12") -一切都开始工作与最简单的默认值…

参考:

我"default"node版本为8.x.x

launch.json

{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"runtimeVersion": "12.22.12",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/src/server.ts",
"preLaunchTask": "tsc: build - tsconfig.json",
"sourceMaps": true,
"smartStep": true,
"internalConsoleOptions": "openOnSessionStart",
"runtimeExecutable": "node",
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
]
}
]
}

tsconfig.json

{
"extends": "@tsconfig/node12/tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"sourceMap": true
},
"include": ["src"],
"exclude": ["node_modules"]
}

最新更新