- 开发工具
- 移动开发
- 测试
- 性能测试
【免费下载链接】DoKit
一款面向泛前端产品研发全生命周期的效率平台。
导读
本指南围绕 DoKit 开源仓库中 Web 端web-independent包的文档展开,聚焦于其中唯一被明确列出的基础插件——Console(基于 Web 的日志组件)。文章将以该文档为骨架,结合 Web/packages/web/src/plugins/console 下的完整源码实现,从日志捕获原理、类型体系、界面呈现、命令执行到构建接入,逐层拆解其工作机制,帮助你理解 DoKit For Web 如何在任意网页中以无侵入方式接管console、聚合前端日志并提供类 DevTools 的调试面板,从而在自己的业务页面中复用这套能力。
一、定位:Dokit For Web 与 web-independent 包
仓库中的 Web/packages/web-independent/README.md 是@dokit/web-independent包的说明文档,全文将 Web 端能力归纳为若干"基础插件",其中首要介绍的即为 Console 插件:
Console:基于 Web 的日志组件
从包配置 Web/packages/web-independent/package.json 可以看到,@dokit/web-independent是 Dokit Web 的主入口包(description: "Dokit Web Main Entry"),对外发布产物为dist/dokit.js(IIFE 格式,可直接通过<script>引入),依赖@dokit/web-core与@dokit/web-utils两个本地核心包。
包的入口 Web/packages/web-independent/src/index.js 只有寥寥数行,却完成了整个 SDK 的挂载:
import { Dokit } from '@dokit/web-core-independent' import { Features } from '../../web/src/feature' /** * 0.0.3 alpha 3 * TODO 全局注册 Dokit */ window.Dokit = new Dokit({ features: Features, });其核心动作有三:
- 从
@dokit/web-core引入Dokit类; - 从 Web/packages/web/src/feature.js 引入注册了全部插件的
Features配置; - 以
features选项实例化Dokit,并把实例挂到window.Dokit上,实现"全局注册"(源码注释中的 TODO 即指这一全局化动作,从代码结构看已完成)。
而 Console 插件正是 Web/packages/web/src/feature.js 中BasicFeatures(常用工具)列表的第一项,与 AppInfo、Resource、Network、Storage 等插件并列。因此可以说:Console 是 DoKit For Web 默认能力集中最基础、最先被加载的调试组件之一。
二、插件模型:RouterPlugin 与生命周期
在深入 Console 之前,需要先理解 DoKit For Web 的插件基座。核心包 Web/packages/core/src/common/js/feature.js 定义了插件抽象:
BasePlugin:基类,统一承载name、nameZh、icon、component四个描述字段,以及load()、unload()、productReady()三个生命周期方法;RouterPlugin:基于路由容器的插件(进入插件页时路由跳转);IndependPlugin:独立容器插件(不依赖路由,直接叠加到页面顶层)。
Console 插件在 Web/packages/web/src/plugins/console/index.js 中被定义为RouterPlugin:
import Console from './main.vue' import { overrideConsole, restoreConsole } from './js/console' import { getGlobalData, RouterPlugin } from '@dokit/web-core' export default new RouterPlugin({ name: 'console', nameZh: '日志', component: Console, icon: 'https://pt-starimg.didistatic.com/static/starimg/img/PbNXVyzTbq1618997544543.png', onLoad() { overrideConsole(({ name, type, value }) => { let state = getGlobalData(); state.logList = state.logList || []; state.logList.push({ type: type, name: name, value: value }); }); }, onUnload() { restoreConsole() } })生命周期由核心包 Web/packages/core/src/common/js/lifecycle.js 统一驱动:applyLifecyle会遍历所有 feature 分组,对每个插件的load/unload/productReady钩子依次调用。对应关系如下:
| 钩子 | 触发时机 | Console 插件的行为 |
|---|---|---|
onLoad | Dokit 实例化时(new Dokit(...)即调用) | 调用overrideConsole开始接管日志 |
onUnload | 插件卸载 | 调用restoreConsole恢复原始console方法 |
onProductReady | setProductId()之后 | 未使用(默认 noop) |
也就是说:Console 插件不是进入面板才生效,而是 Dokit 一启动就全局接管 console 并持续收集日志,日志被写入核心 Store 的logList数组中(见 Web/packages/core/src/store/index.js 中getGlobalData的实现),供插件页面实时读取渲染。
三、日志捕获原理:overrideConsole 与 restoreConsole
Console 组件"基于 Web 的日志组件"定位的底层实现,是 Web/packages/web/src/plugins/console/js/console.js 中的两个导出函数。
3.1 覆盖阶段(overrideConsole)
export const CONSOLE_METHODS = ["log", "info", "warn", "error"] export const overrideConsole = function (callback) { const winConsole = window.console CONSOLE_METHODS.forEach((name) => { let origin = (origConsole[name] = noop) if (winConsole[name]) { origin = origConsole[name] = winConsole[name].bind(winConsole) } winConsole[name] = (...args) => { callback({ name: name, type: ConsoleLogMap[name], value: args }) origin(...args) } }) }机制要点:
- 仅拦截
log、info、warn、error四个高频方法,不干扰console.debug、console.table等; - 先用
bind(winConsole)保存原始方法到origConsole缓存(避免丢失this上下文); - 替换后的新方法在调用回调上报日志后,仍会调用原始方法,因此页面原有的 console 输出不受影响——这就是"无侵入捕获";
- 回调收到的
value是完整的参数数组args,因此多参数调用(如console.log('a', obj))也能被完整保留。
3.2 恢复阶段(restoreConsole)
export const restoreConsole = function () { const winConsole = window.console CONSOLE_METHODS.forEach((name) => { winConsole[name] = origConsole[name] }) }将缓存的原始方法逐一还原,保证卸载后页面 console 行为与接入前完全一致,符合可插拔设计。
四、日志类型体系:LogMap / LogEnum / ConsoleLogMap
Web/packages/web/src/plugins/console/js/console.js 顶部定义了一套完整的日志类型映射,这是文档中 TODO"支持多种类型的日志"对应的数据基础:
export const LogMap = { 0: 'All', 1: 'Log', 2: 'Info', 3: 'Warn', 4: 'Error' } export const LogEnum = { ALL: 0, LOG: 1, INFO: 2, WARN: 3, ERROR: 4 } export const ConsoleLogMap = { 'log': LogEnum.LOG, 'info': LogEnum.INFO, 'warn': LogEnum.WARN, 'error': LogEnum.ERROR }三者分工明确:
| 常量 | 作用 | 说明 |
|---|---|---|
LogMap | 数字 → 名称 | 用于渲染 Tab 文案(All / Log / Info / Warn / Error) |
LogEnum | 枚举常量 | 供代码中以语义化方式引用各类型 |
ConsoleLogMap | console 方法名 → 枚举 | 捕获回调中把name转成type数字 |
LogTabs由LogMap派生:
export const LogTabs = Object.keys(LogMap).map(key => { return { type: parseInt(key), name: LogMap[key] } })插件页面 Web/packages/web/src/plugins/console/main.vue 直接消费这些定义:Tab 组件渲染LogTabs,默认选中LogEnum.ALL,curLogList计算属性在非 ALL 状态下按log.type过滤。四种日志类型与筛选能力在源码中均已落地,对应文档 TODO 中的第一项。
五、日志界面呈现与对象展开
5.1 界面结构
main.vue 的模板将 Console 面板拆为三部分:
console-tap:顶部类型筛选 Tab(console-tap.vue,通过changeTap事件通知父组件切换类型);log-container:日志列表(log-container.vue,遍历curLogList逐条渲染log-item);operation-command:底部命令执行区(op-command.vue)。
5.2 日志条目与对象展开
单条日志由 log-item.vue 渲染。它根据日志类型做差异化展示:
log/info:识别每个参数的数据类型(getDataType),除 Number、String、Boolean、Undefined、Null 外,均渲染类型标签 + 结构化文本(getDataStructureStr);error/warn:若参数带stack,直接以pre-wrap样式输出完整的错误堆栈;- 样式层面按
info(浅蓝)、warn(浅黄)、error(浅红底色 + 红色文字)做视觉区分。
对象类型展开正是文档 TODO"支持对象类型展开"对应的能力,在 log-detail.vue 中实现:点击日志预览可展开明细,明细项对 Object/Array 递归渲染(组件自引用自身Detail),支持逐层展开折叠,值展示为index: value形式,可折叠项带三角形指示符。从源码结构看,该 TODO 项已有完整实现。
六、简易 JavaScript 命令执行
Console 面板底部提供命令行输入框,对应 op-command.vue:输入命令后点击 "Excute" 按钮,执行结果通过console.log回灌到日志列表,实现"面板内即时求值"的类 DevTools 体验。
命令求值由 console.js 中的excuteScript完成:
export const excuteScript = function (command) { let ret try { ret = eval.call(window, `(${command})`) } catch (e) { ret = eval.call(window, command) } return ret }其策略为:先尝试将输入包裹成表达式(${command})求值(适用于对象字面量、JSON 等),失败则退化为直接求值(适用于语句、变量访问等),并统一以window为执行上下文。注意此能力面向调试场景,执行任意 JS 存在安全风险,仅在可信的开发/调试环境开启。
七、构建与接入方式
7.1 构建产物
Web/packages/web-independent/rollup.config.js 负责将../web/src/index.js打包为dist/dokit.js:
- 输出格式为IIFE,全局变量名为
dokit,因此页面可直接以<script>标签引入; - 插件链包含
rollup-plugin-vue(编译.vue单文件组件)、postcss(处理 less)、node-resolve+commonjs、@rollup/plugin-alias(把@common指向../web/src/common); - 生产构建(
NODE_ENV=production)追加terser压缩,同时通过replace注入process.env.NODE_ENV等环境常量。
执行构建(包内 scripts,见 package.json):
npm run build # 生产构建(含压缩) npm run dev # rollup -wc 监听模式开发构建7.2 页面接入示例
仓库中的 Web/playground/independent.html 即一个最小可用的接入示例,完整展示了接入三步曲:
<script src="../packages/web-independent/dist/dokit.js"></script> <script> Dokit.setProductId('749a0600b5e48dd77cf8ee680be7b1b7') // Dokit.startMultiControl('ws://192.168.0.102:8000/proxy/multicontrol/qwe', 'host') </script>- 引入
dist/dokit.js; - 调用
Dokit.setProductId(...)触发onProductReady生命周期(核心实现见 Web/packages/core/src/index.js,setProductId会写入 Store 并触发onProductReady); - 可选:
startMultiControl(url, role)开启多机同控(host/client角色),stopMultiControl()断开。
接入后,页面中任何console.log/info/warn/error都会自动被 Console 插件捕获并可在面板中按类型筛选查看。
八、小结
回到 Web/packages/web-independent/README.md 的原始骨架,可以将其一句话概括为"基于 Web 的日志组件"的 Console 插件,在仓库源码中拥有完整闭环:
- 捕获层:console.js 的
overrideConsole/restoreConsole以保存-替换-恢复模式无侵入接管console; - 类型层:
LogMap/LogEnum/ConsoleLogMap支撑多类型日志(Log/Info/Warn/Error)与 Tab 筛选,对应文档 TODO 第一项; - 展示层:log-item.vue 与 log-detail.vue 实现错误堆栈渲染与对象/数组递归展开,对应文档 TODO 第二项;
- 交互层:op-command.vue 提供命令执行入口;
- 生命周期层:插件基座 feature.js 与 lifecycle.js 保证加载与卸载的对称性。
若要在自己的业务页面中启用这一能力,只需按web-independent包的构建产物引入并实例化Dokit,即可获得一个随页面运行的、可筛选、可展开对象、可执行命令的前端调试日志面板。
- 开发工具
- 移动开发
- 测试
- 性能测试
【免费下载链接】DoKit
一款面向泛前端产品研发全生命周期的效率平台。
相关推荐
CuraEngine插件开发实战:如何为3D打印引擎扩展自定义功能
CuraEngine插件开发实战:如何为3D打印引擎扩展自定义功能 CuraEngine是Ultimaker开发的一款强大、快速且健壮的3D打印切片引擎,能够将
后端图形学Pinpoint Web 前端富日期时间选择器(Rich Datetime Picker)组件使用指南
Pinpoint Web 前端富日期时间选择器(Rich Datetime Picker)组件使用指南 导读 本文讲解 Pinpoint 项目 Web 前端(
后端可观测性APM链路追踪微服务Graylog 2 Web Interface 前端分页组件 Pagination 使用指南
Graylog 2 Web Interface 前端分页组件 Pagination 使用指南 导读 本指南以 Graylog2 Server 开源仓库中 Pag
日志分析运维观测
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考