☰
DoKit For Web 前端日志组件(Console)原理与使用指南
2026/10/10 5:15:02 网站建设 项目流程
  • 开发工具
  • 移动开发
  • 测试
  • 性能测试

【免费下载链接】DoKit

一款面向泛前端产品研发全生命周期的效率平台。

项目地址:https://gitcode.com/gh_mirrors/do/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, });

其核心动作有三:

  1. 从@dokit/web-core引入Dokit类;
  2. 从 Web/packages/web/src/feature.js 引入注册了全部插件的Features配置;
  3. 以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 插件的行为
onLoadDokit 实例化时(new Dokit(...)即调用)调用overrideConsole开始接管日志
onUnload插件卸载调用restoreConsole恢复原始console方法
onProductReadysetProductId()之后未使用(默认 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枚举常量供代码中以语义化方式引用各类型
ConsoleLogMapconsole 方法名 → 枚举捕获回调中把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 面板拆为三部分:

  1. console-tap:顶部类型筛选 Tab(console-tap.vue,通过changeTap事件通知父组件切换类型);
  2. log-container:日志列表(log-container.vue,遍历curLogList逐条渲染log-item);
  3. 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>
  1. 引入dist/dokit.js;
  2. 调用Dokit.setProductId(...)触发onProductReady生命周期(核心实现见 Web/packages/core/src/index.js,setProductId会写入 Store 并触发onProductReady);
  3. 可选: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

一款面向泛前端产品研发全生命周期的效率平台。

项目地址:https://gitcode.com/gh_mirrors/do/DoKit
点击查看免费下载
上一篇:Google Spatial Media项目解析:VR180视频格式技术详解
下一篇:TestProf 测试性能分析工具入门指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询