👏 背景
正浏览着下班后去哪家店撸串,结果隔壁组同事囧着脸过来问我:大哥,赶紧过去帮忙看个问题!客户反馈很多次了,一直找不出问题出在哪里!!!
我:能不能有点周五的样子!你小子耽误我下班啊!!
过去简单的了解一下,据说是个历史遗留问题,极难复现!
- 后端同学:数据绝对没问题,都仔细校对过了!😳😳
- 前端同学:线上报错信息啥也看不出来,我本地是好的!要不你们再试试?🤔🤔
- 测试同学:复现纯靠缘分!😰😰
我:这么说看来是有鬼了,要不你们在座位上摆个香炉烧根香?
坐下后我一顿操作猛如虎,五分钟后就定位出了问题,老板在知晓这件事后:
😥 背后原因分析
思考这背后的原因,根本在于是大家不知道怎么调试线上问题,都是靠猜。猜对了皆大欢喜,猜错了换个方向继续猜,直到陷入怀疑自我的情绪中......
今天借此机会,我决定祭出独门绝技,教大家一招 bug 定位消失术!彻底摆脱线上问题恐惧症!
说回正题
线上问题大致可以分两类:一类是接口数据导致的
,另一类是数据正常,前端哪里疏忽了导致的
。
- 数据不同:本地更多的是用的测试环境的数据,而线上用的真实环境的数据。不同数据,页面的渲染以及交互可能不同;
- 代码疏忽:可能是某些场景的边界情况没有处理好,再或者是未做容错降级处理等;
💁 模拟线上环境
文中所涉及到的代码均放到个人 github 仓库中:github.com/noBaldAaa/o…
通过 create-react-app 初始化一个项目(你也可以用 vue-cli,都一样):
npx create-react-app my-app --template typescript
复制代码
接着在控制台运行 yarn eject
,把 Webpack 的配置暴露出来(用其他构建工具也一样,这里以 Webpack 为例),此时项目目录结构:
├── build # 打包后的文件夹
├── config # webpack配置信息
| └── webpack.config.js
├── node_modules
├── public
├── package-lock.json
├── package.json
└── src # 源码目录
└── index.tsx
复制代码
在 index.tsx 中写一段错误的代码模拟报错:
import React, { useEffect } from "react";
import ReactDOM from "react-dom/client";
function App() {
const obj: any = {
author: "不要秃头啊",
};
useEffect(() => {
//报错代码在这里!!!!!!!!!!!
obj.abc.map((item: any) => item === "1111");
});
return (
<div className="App">
<h1>hello world</h1>
</div>
);
}
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
复制代码
模拟生产环境打包,修改 config/webpack.config.js 中的配置:
mode: "production",
devtool: false,
复制代码
mode: "production"
表示采用生产模式打包,会启用代码压缩等插件devtool: false
表示不生成source-map
文件
接着在控制台运行 yarn build
命令,生成打包后的文件:/build。
为了模拟线上,这里用一个第三方库:http-server,根据官方介绍:它是是一个简单的、零配置的命令行静态 HTTP 服务器。下面是官方介绍图,确实挺形象......
该说不说,确实很简单,这点没吹牛比👍,一行代码就可以起一个静态的 HTTP 服务器:
npx http-server ./build
复制代码
点击静态服务器地址,打开页面发现确实报错了:
所有代码都被压缩成了一行,确实啥都看不出来。
💣 小型必杀技
上面我们提到,本地没问题,线上有问题,一部分原因就是因为后端数据有问题,这里先祭出一个小型必杀技:Ajax Interceptor。
它是一个谷歌插件,可以拦截页面上的 Ajax 请求,并把返回结果替换成任意文本。这对 mock 数据、排查线上问题 来说简直就是神器!!!
Charles 等抓包软在它面前就是个弟弟(我没有侮辱 Charles 的意思,大家各有长处)。当我知道了这个插件之后,才发现以前的操作都花里胡哨的!!!
示范一下,把我的掘金等级改成 8 级,掘力值和关注者加几个 999,这不过分吧!
此处 @掘金运营
@优弧
,叫你们开发来改 bug 啦,这小子数据已经爆表了。
使用方式:
(1)点击插件图标
(2)把你想要修改的接口 URL 地址复制到输入框中,然后把返回的内容放到下面的文本框
拍了个视频教程:
友情提示:不需要用的时候别忘记关掉!!!要不然有可能分析半天,最后发现忘关插件了......
🚀 终极必杀技
上面那个小工具可以解决大部分场景的问题,但万一不是后端数据的问题,是我们自己的问题呢?
这个时候再说:我本地是好的,你再试试?
此时老板要拿刀过来了......
回归本质,线上不能定位到问题的原因是什么?不就是因为生产环境没有生成和上传 source-map
文件吗!!
那我们直接给线上环境添加上 source-map
文件不就可以了吗?
部分心急的同学请你把刀放下,我并不是说在生产环境上传 source-map
文件。
我的意思是:生产环境 + 本地的 source-map 文件。
这里偷偷告诉大家一个小秘密(99%的人都不知道,勿外传):谷歌浏览器的 Sources 面板支持右键添加 source-map
:
有了方案后,现在只需把生产环境的代码按照如下配置在本地重新打包:
output:{ path: path.resolve(__dirname, "build2") } //原build文件夹在模拟线上环境,这里改成build2防止影响之前的服务
devtool:"source-map"
复制代码
然后用 http-server 起一个静态服务:
npx http-server ./build2
复制代码
拿到 source-map
的文件链接添加到浏览器中:
操作视频:
这是添加前的效果:
这是添加后的效果:
堆栈信息一目了然,一下就能看到是哪个文件下的哪行代码出了问题!
👋 总结
本文从一个团队小故事出发,详细讲述了当前端开发者遇到线上问题时的囧境。从以下两个场景剖析,给出了对应的解决方案:
- 数据不同导致出错:在本地环境下使用 Ajax Interceptor 来模拟线上数据;
- 代码疏忽导致出错:直接在线上环境添加
source-map
链接来定位问题;
什么?这两个方案还不够?这已经是我知道的最简单的方式啦!!我已经把我知道的全说了😭😭😭
什么?你们项目里集成了 sentry 等监控系统?那就当我没说!我闭嘴了!
什么?......