在开发小程序的时候如何排查问题
在最近开发小程序的时候,经常出现本地在浏览器中调试没有问题,但是一发布到预发环境就出现各种个样的问题
-
手机兼用性问题
有时候会出现苹果🍎手机键盘弹出,导致ui界面高度出现异常
-
边界问题,导致js报错
小程序页面出现白屏,可能是js报错,但是我们没办法像在浏览器中一样去打开控制台查看日志报错信息 但是自己本地又复现不了
-
后端接口报错
有时候新增/修改调用后端接口的时候,后端接口可能会对字段进行校验,抛出错误信息,
说你某个字段传递的有问提,但是我们无法真正捕获到有用的信息,比如这个字段传递给后端的时候到底是怎样的,
有时候不得不麻烦后端同学去查看一下后端接口的日志信息,每次这样去找后端,也是会被讨厌的不是吗。
所以,作为前端的小伙伴我们应该怎样处解决小程序开发中所出现的问题呢?
我们这边以react开发小程序为例
- 面对js报错问题,我们可以开发一下 ErrorBoundary 组件,在组件内部捕获js报错,并在页面上展示错误信息
不管是在开发环境还是在生产环境,这个组件都能很好的帮助开发者排查前端问题。
ErrorBoundary 原理使用 react 类组件中的 componentDidCatch生命周期 进行错误的捕获,如果有错误信息则展示错误信息否则展示正常的页面
import React from "react";
import styles from "./index.less";
import { Toast } from "antd-mobile";
class ErrorBoundary extends React.Component<any,{ hasError: boolean; errorInfo: string }> {
constructor(props) {
super(props);
this.state = { hasError: false, errorInfo: null };
}
static getDerivedStateFromError(error) {
// 更新状态使得下一次渲染能够显示降级后的UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 你同样可以将错误日志上报给服务器
const url = location.href;
this.setState({ errorInfo: `${error.toString()}\n当前地址:${url}` });
}
render() {
/* 复制去反馈 */
const onCopy = () => {
navigator.clipboard.writeText(this.state.errorInfo);
Toast.show({
content: "复制成功",
});
};
if (this.state.hasError) {
// 你可以渲染任何自定义的降级UI
return (
<div className={styles.errorBoundary}>
<h2>哦呦,出错啦</h2>
<p>{this.state.errorInfo}</p>
<div onClick={onCopy} className={styles.errorBoundaryFooter}>
复制去反馈
</div>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
ps: 样式可以自行定义
- 我们有时候前端打印了很多日志,想去排产问题或者查看数据格式,但是我们无法在浏览器中打开控制台查看,我们怎么去排查呢?
思路:实现一个react组件,该组件可以配置在最外层,则他的子组件里的所有原生的console方法,都会被重写,重写的console方法会自动收集打印的日志内容,并将内容存储起来,然后在ui中呈现出来
实现结果
//index.jsx
import React, { createContext, useContext, useState, useEffect } from "react";
// 创建一个日志上下文
const LogContext = createContext(null);
// 创建一个高阶组件来提供日志收集功能
export const LogProvider = ({ children }: any) => {
const [logs, setLogs] = useState([]);
console.log(logs, "logs");
// 存储原生 console 方法
const consoleMethods = {} as any;
useEffect(() => {
// 重写 console 方法
Object.keys(console).forEach((method: any) => {
if (typeof console[method] === "function") {
consoleMethods[method] = console[method];
console[method] = (...args) => {
/* 阻止打印日志logs的时候添加到集合中 */
if (!args.toString().includes("logs") && logs?.length <= 100) {
setLogs((prevLogs) => [...prevLogs, { method, args }]);
}
consoleMethods[method](...args);
};
}
});
// 清理函数,恢复原生 console 方法
return () => {
Object.keys(console).forEach((method) => {
if (consoleMethods[method]) {
console[method] = consoleMethods[method];
}
});
};
}, []);
// 提供日志和日志收集状态
return (
<LogContext.Provider value={{ logs, setLogs }}>
{children}
</LogContext.Provider>
);
};
// 创建一个自定义 Hook 来访问日志上下文(可选)
export const useLogs = () => useContext(LogContext);
// LogViewer.jsx
import React from "react";
import { useLogs } from "./index"; // 请根据实际文件路径调整
import _ from "lodash";
import JsonView from "react18-json-view";
import "react18-json-view/src/style.css";
import RedBox from "redbox-react";
const LogViewer = () => {
const { logs } = useLogs();
return (
<div>
<h3>Log Viewer</h3>
<ul
style={{
maxHeight: "300px",
overflowY: "scroll",
background: "#f0f0f0",
padding: "1rem",
border: "1px solid #ddd",
}}
>
{logs.map((log: any, index: any) => (
<li key={index}>
<strong>{log.method}</strong>:{" "}
{log.args.map((arg: any) => {
if (_.isObject(arg)) {
return <JsonView src={arg} />;
} else {
return arg.toString();
}
})}
</li>
))}
</ul>
</div>
);
};
export default LogViewer;
使用方式
// 在最外层使用
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import { LogProvider } from "./components/LogTools/index.tsx";
import LogViewer from "./components/LogTools/LogViewer.tsx";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<LogProvider>
<LogViewer />
<App />
</LogProvider>
</React.StrictMode>
);
ps: 最好做一个悬浮的工具按钮,让其悬浮固定在页面某个位置,点击查看日志即可
- 如何收集查看日志/网络请求等关键信息,当然也可以重新二次封装我们的请求,但是这件事请已经有人帮我们做了有一个公共的npm库
Mdebug
安装:npm install --save-dev mdebug
测试环境/预发环境使用、别上生产环境
使用: 在我们的项目主文件中main.tsx
中直接引用即可
import mdebug from "mdebug";
mdebug.init();
效果图: