咱们搞前端的基本都遇到过这种场景页面在电脑上跑得好好的一放进手机里的微信或者浏览器就各种诡异问题——白屏、样式错乱、接口报错、点击没反应。更难受的是手机上没有开发者工具看不到Console报错不知道网络请求到底发出去没有也没法看元素位置。那几分钟里你唯一的想法就是回到电脑前加alert然后让测试再点一遍。我这次想聊的就是移动端H5调试的几套实用工具vConsole、eruda、spy-debugger。这三样东西几乎覆盖了H5/WAP端调试的全部主流需求页面内调试面板、远程真机调试、HTTPS抓包和源码定位。下面内容都是我在各类项目里实际用过的经验包括怎么接、怎么配、什么时候用哪个以及一些文档里很难翻到的坑。1. 移动端H5调试的困境到底难在哪很多人一开始不理解移动端调试不就是把手机接到电脑上然后Chrome devtools远程调试吗这话对一半。Android端用Chrome确实可以做USB远程调试iPhone配合Safari也能做但实际项目中你会发现这条路没那么顺畅。1.1 手机上缺了一整套调试工具PC端的开发者工具集成了Console、Network、Sources、Elements、Performance等十几个能力面板但在手机上这些工具默认是不存在的。你没法点右键审查元素也没法在浏览器里拉开一个Console窗口。即使你连上USB做远程调试碰到微信内置浏览器、各种手机厂商自带浏览器、App内嵌WebView这些环境Chrome DevTools基本就废了——因为这些WebView和标准浏览器不一样调试协议对不上甚至压根不给你暴露调试端口。那大家普遍的做法是什么呢把调试工具直接注入到页面里让手机页面上自己长出一个控制台来。vConsole和eruda干的都是这件事。你打开页面能看到右下角有个小按钮点开之后Console、Network、Storage这些面板全部蹦出来直接在手机上完成大部分调试工作。这种方案不管在微信里、普通浏览器里还是App内嵌WebView里只要能跑JS就能用。1.2 常见的调试场景有哪些我按实际工作中遇到的频率把移动端调试场景大致分成了三类。第一类是页面内自调试。就是你在开发阶段用手机直接访问开发环境地址然后在页面上弹出控制台看日志、看网络请求、看Cookie和LocalStorage。这个场景vConsole和eruda最合适注入成本最低。第二类是远程真机联调。页面在某个同事或测试的手机上你人在电脑前需要远程看到TA手机上的页面情况甚至要操作TA手机上的页面。这个时候spy-debugger这类工具出场原理是让手机通过代理访问你的电脑你的电脑上就能捕获到手机发起的全部请求并可以配合调试工具远程查看状态。第三类是线上问题定位。用户那边报了一个线上问题你又没有TA的手机不能重现。这时页面里的调试工具就要能远程上报日志或者至少在用户可操作的情况下把现场信息记录下来。这条我在后面避坑部分细讲。1.3 先用一张表看懂三者的定位工具核心定位典型使用场景上手成本vConsole页面内轻量控制台微信内、浏览器内快速看Console和网络请求极低几行代码eruda页面内功能更全的调试面板需要看Elements、终端、源码等更多信息时低支持插件spy-debugger远程代理抓包与调试入口真机访问电脑代理远程看请求、cookie、缓存等中需要装证书理解到这一步剩下的全是操作层面的东西。接下来我一个个拆开说。2. vConsole轻量注入式调试面板实战vConsole是现在用得最多、也最被广泛知晓的页面内调试方案。它能把一个类控制台的面板直接渲染在页面上不依赖任何真机调试环境只要页面能打开就能调试。2.1 核心能力不只是日志面板很多人以为vConsole只是一个console.log展示器其实它还有几个很实用的能力我在项目里基本都会用到。Console面板是基础console.log、console.warn、console.error都会按级别展示也可以按级别过滤。Log面板默认还会记录页面的加载过程比如请求了哪些JS、CSS什么时候DOMReady这些信息在排查加载类问题时非常有用。Network面板算是vConsole的高频功能。它能看到每个请求的URL、方法、状态码、耗时、请求体和响应体基本够用了。很多H5项目里出现的“接口报错但页面不弹”这类问题我通常都是先在vConsole的Network里看一遍先确认是请求没发出去还是响应数据格式不对再决定往哪查。Storage面板则能看LocalStorage、SessionStorage和Cookie。这个便宜好用特别是排查登录状态异常、token失效这类问题直接在手机上看一眼存储的数据就明白了。2.2 项目里怎么快速接进来接入有两种方式。第一种是npm安装后import适用于工程化项目第二种是直接在HTML里用script标签引入CDN文件适合活动页、简单的静态页或者临时排查。npm install vconsole然后在代码里引入并初始化import VConsole from vconsole; // 只在开发或测试环境开启线上别乱开 if (import.meta.env.MODE development) { const vConsole new VConsole({ theme: dark, maxLogNumber: 1000 }); }如果是不走构建工具的页面直接这样写script srchttps://unpkg.com/vconsole/dist/vconsole.min.js/script script new VConsole(); /script这里有个很重要的细节vConsole默认实例化之后就直接显示出来。但线上环境我强烈建议别自动开。很多团队的做法是配置文件里留一个开关或者通过URL参数控制。比如这样默认不初始化但URL里带了debug标志才初始化const isDebug /[?]debugtrue/.test(location.href); if (isDebug) { new VConsole(); }这样线上用户不会受到影响而你想看某个线上页面时自己拼一个带debugtrue的链接就能调出面板。这个技巧我用了好几年非常稳。2.3 动态开关与自定义面板vConsole原生支持动态开启和关闭。实例化时可以传参数也可以在运行时调用相关方法。const vConsole new VConsole(); // 动态打开 vConsole.show(); // 动态隐藏 vConsole.hide(); // 手动输出一条log vConsole.log(some data, { a: 1 });还有个场景属于“进阶用法”。vConsole允许自定义面板有些团队会把业务日志单独放到一个自定义Tab里方便测试同学自己查看关键业务节点。比如某次活动页面判断用户是否领到券、是否触发弹窗这些业务状态如果丢在通用Console里会非常零散。我当时就是写了一个自定义面板把几个关键业务节点汇总成一个列表展示出来测试同学直接在手机上提供截图反馈定位效率提升非常明显。2.4 我在实战里怎么用vConsole捞问题说一个真实的例子。之前有个某商城的H5活动页用户投诉说在微信里点击“立即参与”没有反应。开发同学在PC端模拟器上反复点一切正常。后来我在一台老安卓机上打开页面挂上vConsole复现了点击无反应的操作然后去看Console面板发现脚本抛了一个ReferenceError是因为某个低版本安卓WebView不支持某个新语法导致的。但如果没vConsole这个报错根本看不到只能盲猜。那次之后我在团队里定了个规矩所有H5页面必须在测试阶段默认开启vConsole测试完再关掉这个操作直接减少了30%的“定位不到问题”的扯皮时间。3. eruda功能更重的移动端调试面板eruda和vConsole目标一致也是页面内注入式调试面板但它的能力范围更大更像是一个可以随时拖出来的移动版开发者工具。3.1 eruda的核心能力eruda默认提供Console、Network、Elements、Sources、Resources、Info、Snippets等面板。Elements面板可以查看DOM结构直接看到元素的标签属性还能显示当前页面有没有元素溢出、挡住了点击这类视觉问题是vConsole帮不了你的。Sources面板可以查看页面加载的脚本源码偶尔需要确认线上JS版本的时候很有用。Resources面板能看到LocalStorage、SessionStorage、IndexedDB等所有存储数据。Info面板则展示页面、系统、UA等基础信息。这套能力加在一起基本上把你PC端DevTools里高频用到的几块都搬到了手机上。3.2 插件体系与自定义eruda还有一个vConsole比不了的东西就是插件机制。它有一堆现成插件可以按需加载比如eruda-dom用于查看DOM结构eruda-orientation用于模拟横竖屏切换eruda-benchmark用于简单的性能测试。你甚至可以写自己的插件往面板里塞工具栏按钮。加载插件的方式也比较简单script srchttps://cdn.jsdelivr.net/npm/eruda/script script eruda.init(); /script如果你还需要一些插件可以按需引入// 引入DOM面板插件 eruda.add(erudaDom);说实话因为eruda默认功能已经很多我在实际项目中加载插件的情况反而比较少。如果你是一个需要反复调试WebView里页面视觉问题、存储问题的场景eruda会比vConsole顺手得多。3.3 eruda和vConsole怎么选经常有人问这两个到底选哪个。我的建议很直接极简调试、只需要看Console和网络请求的用vConsole需要看DOM结构、看存储、甚至需要在手机上看源码的用eruda。如果你做的是短平快的活动页、配置页能不开太重的东西就尽量别开重vConsole就够了。但如果你做的是较复杂的单页应用页面里涉及路由、状态管理、组件通信要排查的问题类型五花八门那eruda提供的Sources和Elements面板能在关键时刻帮上大忙。此外两者也可以同时存在虽然看起来冗余但调试复杂问题时反而是个组合拳。我试过vConsole看请求执行时序eruda看DOM结构和元素样式两边一起对照定位效率其实比单用任何一个都高。4. spy-debugger远程真机调试与抓包方案vConsole和eruda解决的是“手机上就地调试”的问题但有一个短板它们看不到手机和服务器之间真正发生的事情尤其无法解决跨设备、跨网络场景下的问题。比如某个用户是用4G网络访问的某个接口在弱网下超时了这个时候就需要另一个方案spy-debugger。4.1 这个工具到底解决什么spy-debugger是一个代理工具核心思路是让你的手机访问一台电脑上运行的本地服务所有HTTP/HTTPS请求都走电脑这个代理然后电脑端能看到完整的请求报文和响应报文。它不需要你去改页面的代码也不需要你在手机上装复杂的App只要让手机无线网络代理指向电脑IP即可。它的典型场景是我在电脑上开发测试同学在手机上报了一个问题我不知道TA手机上的请求发出去了没、返回了什么这时候让TA把手机WiFi代理指到我的电脑IP我这边就能实时抓到手机发起的每个请求。4.2 安装与真机联调步骤使用spy-debugger前需要先安装Node环境然后全局安装npm install -g spy-debugger启动spy-debugger启动后终端会打印出当前电脑的局域网IP和端口。一般是类似http://192.168.x.x:9888这样具体以工具显示为准。接着在手机设置里找到WiFi进入“配置代理”选择“手动”把电脑的IP和端口填进去。保存之后手机访问任意HTTP页面电脑端spy-debugger面板就能看到详细请求。需要注意的是手机上必须能访问到电脑IP。如果手机和电脑不在同一个局域网或者网络隔离、AP隔离会连不上。最稳妥的方式是手机和电脑连同一个WiFi。同时spy-debugger启动时还自带一个内嵌调试页面手机可以通过它打开要调试的页面地址页面上会注入vConsole这样你在远程抓包的同时还能在手机上看Console。这个组合真的比单用vConsole方便太多。4.3 HTTPS证书与拦截细节现在页面基本都是HTTPS了而HTTPS抓包必须安装并信任证书。spy-debugger这一步做得比较友好首次启动时它会生成一个本地根证书。手机在完成代理设置后访问任意HTTP地址会弹出一个页面引导你下载证书。苹果手机还要额外在“设置-通用-关于本机-证书信任设置”里手动信任。安卓手机则根据厂商不同有的在“安全-加密与凭据”里安装有的直接下载APK格式的证书包。常见问题是很多新手装完证书后发现HTTPS请求仍然抓不到多半是漏了最后一步信任操作。而且部分智能手机在安装用户证书后对Chrome生效对App内WebView却不生效。这种环境下面只能退回到HTTP测试或者尝试真机Root环境说到底还是要根据实际机型逐步排查。4.4 团队协作里的实际使用心得我还在团队里推广过一个用法。测试同学在真机上报问题的时候我让TA通过spy-debugger这个代理访问页面这样我能同步在电脑上看到所有请求同时让TA点击复现。遇到接口异常时我这边直接把报文抓出来分析完把结论丢到群里一边定位一边让测试继续往下跑。这套流程不需要等测试截图、不需要反复描述“什么现象”、不需要远程到TA电脑去看效率提高非常明显。另外spy-debugger也可以用来查看静态资源缓存情况。比如某个JS更新了但线上页面还是加载旧版本通过代理面板能看到响应头里的cache-control到底怎么设置的然后判断是不是缓存策略导致。这个信息在移动端排查问题尤其重要很多线上怪问题最终都归结于缓存。4.5 它替代不了什么要注意的是spy-debugger并不能替代vConsole/eruda的全部功能。它本身不做DOM元素检查不做JS断点调试更多是抓包和请求分析的角色。实际调试中最好把spy-debugger和vConsole、eruda结合使用代理负责看网络层、数据流注入面板负责看页面内部状态。另外spy-debugger对WebSocket的支持一般长连接类的问题它不太能帮上忙。如果碰到推送消息、实时数据这类问题还是得回到业务代码里去排查工具只能辅助。5. 真实场景里的异常排查与避坑记录工具都介绍完了但真正干活的时候总会碰到工具本身也出现问题的情况。我把自己踩过的一些坑整理出来每条都是实际验证过的不是从文档里抄的那种。5.1 vConsole在部分机型上调不出来vConsole按钮偶尔不显示这个现象主要发生在老版本安卓WebView上。原因多半是按钮的默认定位或者z-index被页面自身的样式覆盖了。解决方法很简单不要等出现问题再找原因在使用vConsole的时候明确给它设置一个极高的z-index比如直接在初始化后修改按钮样式基本能规避掉绝大多数被遮挡的情况。#__vconsole { z-index: 999999 !important; }如果按钮出来了但点击没反应优先怀疑页面上有其他元素覆盖也可能是某些全局事件拦截了touch。这时可以用最土的办法临时注释掉业务代码里对全局点击的拦截逻辑再试一次。5.2 微信内置浏览器里最常翻车的三个点微信里调试最容易出问题的三个点我挨个说。第一是缓存。微信内置浏览器的缓存策略非常激进我遇到过同事说“我改了代码你再看”但手机里打开的页面始终是旧的。这个时候最快的办法是给页面URL手动加一个时间戳参数强制刷新。比如?t1234567。如果你用vConsole看到加载的还是旧JS多半是缓存没刷新。第二是路由问题。用history模式的单页应用部署到微信里一旦刷新二级页面容易出现空白页。spy-debugger或者vConsole的Network里能看到静态资源加载了但页面就是白屏。这种情况跟调试工具没关系是服务器没配置好history回退需要服务端把所有路由回退到index.html。第三是UA判断。移动端项目经常要做UA判断但微信内置浏览器的UA里含有MicroMessenger字样判断逻辑写错就会导致功能异常。这类问题在vConsole的Console里不一定有报错反而是用eruda的Info面板看UA最直观。5.3 调试工具本身的副作用vConsole和eruda这类注入工具本身也会改变页面状态。比如它的初始化和渲染会额外执行一些JS有可能会和页面的重绘逻辑冲突或在极低端机型上造成不必要的性能损耗。有一次我在某个页面上碰到一个奇怪现象vConsole开启时页面正常vConsole关闭后页面滚动就卡顿。后来排查发现是某个监听scroll的组件在反复计算位置而vConsole恰好改变了页面的可用高度把问题掩盖了。这类“工具改变了问题现场”的情况在调试时一定要留意遇到疑似工具引入的异常第一时间把工具关闭再复现一次。线上场景我建议默认全部关闭调试面板开启前必须想清楚这工具到底是帮我排查问题还是掩盖问题。如果线上一定要用加上URL参数开关是底线。5.4 更保险的兜底方案日志上报与线上快照工具只能在你手中的手机上看到问题。用户线上出了问题时如果用户不会配合调试vConsole和spy-debugger都帮不上忙。我的经验是项目里必须有一套轻量的线上日志上报机制。简单做法是劫持console方法把日志统一通过接口发到后端日志系统。代码如下const originalError console.error; console.error function (...args) { // 本地先打印 originalError.apply(console, args); // 上报到日志收集接口 fetch(/api/log/error, { method: POST, body: JSON.stringify({ message: args.map(String).join( ), url: location.href, ua: navigator.userAgent }) }); };这个方案不用引入额外的大库几行代码就能让线上错误不再“失明”。配合vConsole手动在页面上重现问题时还能先收集到更完整的用户操作路径有助于快速还原现场。另一个思路是页面快照。排查一些无法稳定复现的问题时可以在异常发生时把页面关键DOM、URL参数、存储信息打包上报。这个数据量比较大通常建议只截取关键模块或者把整段数据做压缩后上报。5.5 调试工具的最终选择矩阵我把选择的场景和推荐工具做成一个简单矩阵方便直接抄作业。场景推荐方案理由开发阶段手机自测vConsole轻量、快速、不需要额外设备复杂单页应用问题定位eruda可看DOM、源码、存储信息测试报障远程分析spy-debugger抓包直观、不污染业务代码微信内白屏/缓存问题vConsole spy-debugger一个看页面内状态一个看资源加载线上问题应急URL参数开关开vConsole 日志上报不常驻按需开启减少副作用写在最后的经验如果你问我在这三套工具里最推荐谁我的答案还是vConsole因为它成本最低、最不容易出错。但如果你问我组合方案里最不能缺谁那一定是日志上报机制。工具解决的是“我能看到问题”日志解决的是“用户出问题时我能拿到现场”。把这两层都做好移动端调试工作就算基本及格了。再分享一个我坚持了很多年的小习惯每逢新项目启动我第一件事就是把调试环境配置好而不是等到出了问题再装。vConsole的URL参数开关、eruda的按需加载、spy-debugger的代理说明这些都是在项目启动第一天就写进工程模板里的。这样到了测试阶段任何一台手机出问题我都能用最短路径介入。调试工具的意义不在于它多强大而在于它能在关键时刻让你少猜一次。