全部的debugger配置json地址
chrome 调试
过滤控制台信息
添加 ignore list(这样在 chrome 上断点就不会跳到源码了)
- ._\/node_modules\/._
- ._\/.umi\/._
- ^webpack://.\\\\\\\\\\\\*/react refresh\$
- /umi\.js\$
- /react_devtools_backend.js\.js\$
- ^chrome-extension://fmkadmapgofadopljbjfkapdkoienihi\b.\\\\\\\\\*/react_devtools_backend\.js\$
其他断点
- 条件断点一般用于 循环时,当满足某个条件时,才会触发断点
- 日志断点 一般用于 打印日志,当触发日志断点时,会打印出日志信息
- 不触发断点一般用于 网站防止操作无限循环 debugger 时,设置后,不会触发断点
- xhr 断点 可以用来调试 ajax 请求
- 事件断点 可以用来调试事件
代码段
快速定位代码
xhr 调试
Performance 性能分析
如页面卡顿找不到原因时 可以用过这个来快速找到源头
Layers
- 用来测试滚动条 等功能时 测试层级
animations
- 测试动画
- 在生产环境遇到异常动画导致的问题 可以定位到元素然后样式覆盖
dns
- chrome://net-internals/#dns
node-debugger
- chrome://inspect/#devices
vue2
- 使用 vue cli 创建的项目
- yarn serve
- ./vscode/launch.json
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "针对 localhost 启动 Chrome",
"url": "http://localhost:8080",
"runtimeArgs": [
"--auto-open-devtools-for-tabs" // 自动打开开发者工具
],
"webRoot": "${workspaceFolder}",
"sourceMapPathOverrides": {
"webpack://项目名字/src/*": "${workspaceFolder}/src/*"
}
}
]
}
- vue.config.js
const { defineConfig } = require('@vue/cli-service');
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack(config) {
config.devtool = 'source-map';
},
});
vue3
- pnpm create vue@latest
- yarn serve
- ./vscode/launch.json
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "针对 localhost 启动 Chrome",
"runtimeArgs": ["--auto-open-devtools-for-tabs"],
"url": "http://localhost:5173",
"webRoot": "${workspaceFolder}"
}
]
}
- 以 umi4 为例
- yarn serve
- ./vscode/launch.json
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:8000",
"webRoot": "${workspaceFolder}",
"skipFiles": [
"${workspaceFolder}/<node_internals>/**",
"${workspaceFolder}/node_modules/**",
"${workspaceFolder}/webpack/**",
"${workspaceFolder}/.umi/**",
"${workspaceFolder}/umi\\.js$",
"${workspaceFolder}/@@/devScripts.js$",
"${workspaceFolder}/^webpack://.*/react refresh$",
"${workspaceFolder}/react_devtools_backend.js\\.js$"
],
"smartStep": true,
"sourceMaps": true
}
]
}
FAQ
debugger 行数不对
chainWebpack: function(config) {
config.devtool('source-map');
}
ts-node
- ./vscode/launch.json
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "ts-node",
"type": "node",
"request": "launch",
"runtimeExecutable": "node",
"runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"],
"args": ["scripts/generateBizConfig.ts"],
"cwd": "${workspaceRoot}",
"internalConsoleOptions": "openOnSessionStart",
"skipFiles": ["<node_internals>/**", "node_modules/**"]
}
]
}
terminal 终端调试
puppeteer UI 自动化测试
utils.tsx
const fs = require('fs');
/**
* @param {*} path
*/
async function removeDir(path) {
if (fs.existsSync(path)) {
const dirs = [];
const files = fs.readFileSync(path);
files.forEach(async (file) => {
const childPath = `${path}/${file}`;
if (fs.statSync(childPath).isDirectory()) {
await removeDir(childPath);
dirs.push(childPath);
} else {
fs.unlinkSync(path);
}
});
dirs.forEach((fir) => fs.rmdirSync(fir));
} else {
console.log('no such file or directory, failed to remove');
}
}
async function goto(page, link) {
return page.evaluate((link) => {
location.href = link;
}, link);
}
async function click(page, selector, timeout = 30000) {
await page.waitForSelector(selector, { visible: true, timeout });
let error;
while (timeout > 0) {
try {
await page.click(selector);
return;
} catch (e) {
await page.waitFor(100);
timeout -= 100;
error = e;
}
}
throw err;
}
module.exports = {
removeDir,
goto,
click,
};
testConfig.js
module.exports = {
domain: 'http://localhost:8000',
username: 'admin',
password: 'admin',
};
index.js
const puppeteer = require('puppeteer');
const path = require('path');
const testConfig = require('./testConfig');
const CommentTable = require('./commonTable/class');
const utils = require('./utils');
(async () => {
const browser = await puppeteer.launch({
// 有浏览器界面启动
headless: false,
// 放慢浏览器执行速度 方便测试观察
slowMo: 100,
devtools: true,
args: ['--window-size=1480,960', '--unlimited-storage'],
debuggerPort: 9992,
});
const startTime = new Date().getTime();
const page = await browser.newPage();
await page.setViewport({
width: 1480,
height: 960,
});
await utils.goto(page, `${testConfig.domain}/login`);
await page.waitForNavigation();
const username = await page.$("input[type='text']");
await username.type(testConfig.username);
const password = await page.$("input[type='password']");
await password.type(testConfig.password);
const submit = await page.$("button[type='submit']");
await Promise.all([submit.click(), page.waitForNavigation()]);
const submitBtn = await page.waitForSelector('.ant-tour-close');
await submitBtn.click();
page.on('pageerror', (err) => {
console.error(err);
});
// await utils.removeDir(path.join(__dirname, '/screenshot'));
let testResList = [];
let isLastTest = false;
function handleLastTest(flag) {
isLastTest = flag;
return statisticsTestResult;
}
function statisticsTestResult(testResult) {
testResList.push(testResult);
if (isLastTest) {
let allCount = 0;
let passCount = 0;
testResList.forEach((item) => {
allCount += item.allCount;
passCount += item.passCount;
});
testResList.push({
moduleName: '总计',
allCount,
passCount,
});
console.log('测试结果完成, 统计结果如下:');
console.table(testResList);
if (allCount === passCount && passCount > 0) {
console.log('\x1B[32m%s\x1B[39m', '测试通过');
}
const spendTime = (new Date().getTime() - startTime) / 1000;
console.log('\x1B[32m%s\x1B[39m', `done in ${spendTime}s.`);
}
}
// 非最后的测试用例 handleLastTest(false) 最后的测试用例 handleLastTest(true)
await CommentTable.CommentTableAddTest(page, handleLastTest(true));
// await page.close();
// await browser.close();
})();
commonTable/class.js
const testConfig = require('../testConfig');
const utils = require('../utils');
const { domain } = testConfig;
async function CommentTableAddTest(page, callback) {
let allCount = 0;
let passCount = 0;
const moduleName = '公众组件class';
const imgId = Date.now();
try {
allCount++;
await utils.goto(page, `${testConfig.domain}/home/class`, {
timeout: 5 * 1000,
waitUntil: [
'domcontentloaded', // 等待 DOMContentLoaded 事件触发
],
});
// 等待列表接口请求完成
await page.waitForRequest(`${domain}/getActivityList?page=1&limit=30&aaaaaa=1&my=121213`);
const EditBtnElement = '.ant-table-tbody .ant-table-row td:last-child >div >button';
const SubmitBtn = '.ant-modal-content > div.ant-modal-footer > button.ant-btn.ant-btn-primary';
const SelectElements = '.ant-modal-content .ant-select';
await utils.click(page, EditBtnElement);
const otherFormItemInput = await page.waitForSelector('#otherFormItem', {
timeout: 2000,
});
const keywords = '测试';
await otherFormItemInput.type(keywords, { delay: 100 });
const typeSelect = await page.$$(SelectElements);
await typeSelect[0].click();
await handleDropdownSelect(page, 1);
await utils.click(page, SubmitBtn);
page.on('response', (response) => {
response
.json()
.then((data) => {
const resCode = Number(data.code);
const apiUrl = response.url();
const checkApiPass = apiUrl === `${domain}/updateActivityList`;
if (resCode !== 200) {
console.error({
msg: data.msg,
code: data.code,
title: '测试不通过',
module: moduleName,
});
page.screenshot({
path: `./test/screenshot/${moduleName}${imgId}.png`,
});
} else if (resCode === 200) {
if (checkApiPass) passCount++;
}
if (checkApiPass) {
callback({
allCount,
passCount,
moduleName,
});
}
})
.catch((err) => {
console.error('err', err);
callback({
allCount,
passCount,
moduleName,
});
page.screenshot({
path: `./test/screenshot/${moduleName}${imgId}.png`,
});
});
});
callback({
allCount,
passCount,
moduleName,
});
page.screenshot({
path: `./test/screenshot/${moduleName}${imgId}.png`,
});
} catch (error) {
console.error('error', error);
}
}
async function handleDropdownSelect(page, selectedIndex) {
const allDownList = await page.$$('.ant-select-dropdown');
const optionsList = await allDownList[allDownList.length - 1].$$('.ant-select-item');
const selectedItem = optionsList[selectedIndex];
await selectedItem.click();
}
module.exports.CommentTableAddTest = CommentTableAddTest;
package.json
{
"scripts": {
"autotest": "node test"
},
"dependencies": {
"puppeteer": "^19.7.3"
}
}
node
新建一个目录
mkdir debug
cd debug
npm init -y
- 添加 index.js
// index.js
const os = require('os');
const homedir = os.homedir();
console.log(homedir);
使用 chrome 调试
- node --inspect-brk index.js
- 在 chrome 浏览器打开 chrome://inspect/#devices
vscode
- ./vscode/launch.json
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "首行断点",
"type": "node",
"request": "launch",
// 首行断点
// "stopOnEntry": true,
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/index.js"
}
]
}
next
pnpm dev
/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --remote-debugging-port=9222
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "后端",
"type": "node-terminal",
"request": "launch",
"command": "npm run dev"
},
{
"name": "前端",
"type": "chrome",
"request": "attach",
"port": 9222,
"userDataDir": false,
"runtimeExecutable": "canary",
"sourceMaps": true,
"sourceMapPathOverrides": {
"meteor://💻app/*": "${workspaceFolder}/*",
"webpack:///./~/*": "${workspaceFolder}/node_modules/*",
"webpack://?:*/*": "${workspaceFolder}/*"
},
"runtimeArgs": [
// 无痕模式
// "--incognito",
// 自动打开开发者工具
"--auto-open-devtools-for-tabs",
"--user-data-dir=${workspaceFolder}/.vscode/chrome"
],
"skipFiles": ["${workspaceFolder}/node_modules/**/*.js", "<node_internals>/**/*.js"]
}
]
}
使用 chrome 调试
- pnpm start:debug
使用 vscode 调试
1.nest start --debug --watch
- npm run start:debug
- ./vscode/launch.json
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "nest start --debug",
"port": 9229,
"request": "attach",
"skipFiles": ["<node_internals>/**"],
"type": "node",
"console": "integratedTerminal"
}
]
}
2. npm script
- 不需要自己自动项目了
- ./vscode/launch.json
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "npm script",
"request": "launch",
"runtimeArgs": ["start", "dev"],
// 首行断点
// "stopOnEntry": true,
"runtimeExecutable": "npm",
"skipFiles": ["<node_internals>/**"],
"type": "node",
"console": "integratedTerminal"
}
]
}
3. debugger 前端静态资源
- pnpm start:dev
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "static",
"url": "http://localhost:3000",
"webRoot": "${workspaceRoot}/src/public"
}
]
}
4. 使用 canary 调试前端静态资源
- 可以保留浏览器的配置 拓展程序等等
- 电脑根目录执行
/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --remote-debugging-port=9222
- pnpm start:dev
- 在 canary 浏览器打开 http://localhost:9222
{
"name": "canary-前端",
"type": "chrome",
"request": "attach",
"port": 9222,
"userDataDir": false,
"runtimeExecutable": "canary",
"sourceMaps": true,
"sourceMapPathOverrides": {
"meteor://💻app/*": "${workspaceFolder}/*",
"webpack:///./~/*": "${workspaceFolder}/node_modules/*",
"webpack://?:*/*": "${workspaceFolder}/*"
},
"runtimeArgs": [
// 无痕模式
// "--incognito",
// 自动打开开发者工具
"--auto-open-devtools-for-tabs",
"--user-data-dir=${workspaceFolder}/.vscode/chrome"
],
"skipFiles": ["${workspaceFolder}/node_modules/**/*.js", "<node_internals>/**/*.js"],
"webRoot": "${workspaceRoot}/src/public"
}
jest
{
"version": "0.2.0",
"configurations": [
{
"name": "jest",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
"console": "integratedTerminal",
"args": [
// 不再用 worker 进程并行跑测试用例,而是在当前进程串行跑:
"-i"
]
}
]
}
- 只调试某个测试用例
{
"version": "0.2.0",
"configurations": [
{
"name": "jest",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
"console": "integratedTerminal",
"args": [
// 不再用 worker 进程并行跑测试用例,而是在当前进程串行跑:
"-i",
"packages/ims-view-pc/tests/index.test.tsx",
"-t",
"CommonDemo"
]
}
]
}
调试当前打开的文件
{
"version": "0.2.0",
"configurations": [
{
"name": "jest",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
"console": "integratedTerminal",
"args": [
// 不再用 worker 进程并行跑测试用例,而是在当前进程串行跑:
"-i",
"${file}"
]
}
]
}
- 手动输入名称调试
- (支持正则 例如输入
CommonDemo\d)
- (支持正则 例如输入
{
"version": "0.2.0",
"configurations": [
{
"name": "jest",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
"console": "integratedTerminal",
"args": [
// 不再用 worker 进程并行跑测试用例,而是在当前进程串行跑:
"-i",
"${file}",
"-t",
"${input:case}"
]
}
],
"inputs": [
{
"type": "promptString",
"id": "case",
"description": "CommonDemo",
"default": ""
}
]
}
FAQ
发生异常: Error: Cannot find module 'jest-environment-jest-environment-jsdom/package.json' from 'xxx'
- 关闭异常断点等
canary
- 前端调试使用 canary 浏览器 可以保留浏览器的配置 拓展程序等
- 以 umi 为例
/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --remote-debugging-port=9222
- pnpm run start 启动项目
- ./vscode/launch.json
{
"name": "针对 localhost 启动 Chrome",
"type": "chrome",
"request": "attach",
"port": 9222,
"userDataDir": false,
"runtimeExecutable": "canary",
"sourceMaps": true,
"sourceMapPathOverrides": {
"meteor://💻app/*": "${workspaceFolder}/*",
"webpack:///./~/*": "${workspaceFolder}/node_modules/*",
"webpack://?:*/*": "${workspaceFolder}/*"
},
"runtimeArgs": [
// 无痕模式
// "--incognito",
// 自动打开开发者工具
"--auto-open-devtools-for-tabs",
"--user-data-dir=${workspaceFolder}/.vscode/chrome"
],
"skipFiles": [
"${workspaceFolder}/node_modules/**/*.js",
"<node_internals>/**/*.js"
]
}
```
- 用 canary 打开 http://localhost:8000