Vue devtools在production模式下的使用

5,348 阅读3分钟

Vue devtools在production模式下的使用以及控制台调试vue实例(源码分析)


在vue的调试中vue devtools插件很有用,打开与否是由Vue.config.devtools变量来控制。根据官网api显示,Vue.config对象可以在在启动应用之前修改属性的值来控制Vue的行为。大家可能都有过这样的经历,在用vue脚手架调试Vue时我们可以打开vue devtools,但是打包后发布到网上我们就打不开了。实际上Vue devtools常用三种状态。

  1. 没有发现页面使用Vue
  2. 发现Vue并且可以打开devtools,这个时候我们按F12就可以在浏览器的devtool中找到Vue

3. 发现了Vue但是不能打开Vue devtools,这个时候devtools的popup页面就会提醒当前处于production模式或者devtools被网站作者手动关闭

很多时候我们想看看别人写的Vue页面(在Vue production模式下用Vue devtools进行调试),这个时候就要看看Vue和Vue devtools的源码了。我们主要有2个问题,

  1. Vue devtools是如何检测到页面使用了Vue的
  2. Vue devtools的打开和关闭原理

对于第2个问题很好猜到,大致使用了如下代码

Vue.config.devtools = process.env.NODE_ENV !== 'production'

在Vue源码中我们在 Vue/src/core/config.js中找到了如下代码 源码链接

devtools: process.env.NODE_ENV !== 'production'

第2个问题解决了,对于第一个问题,我们去Vue devtools的代码仓库下寻找,在vue-devtools/packages/shell-chrome/src/detector.js下找到了如下代码源码链接

const all = document.querySelectorAll('*')
let el
for (let i = 0; i < all.length; i++) {
  if (all[i].__vue__) {
    el = all[i]
    break
  }
}
if (el) {
  let Vue = Object.getPrototypeOf(el.__vue__).constructor
  while (Vue.super) {
    Vue = Vue.super
  }
  win.postMessage(
    {
      devtoolsEnabled: Vue.config.devtools,
      vueDetected: true
    },
    '*'
  )
}

我们可以看到检测有没有使用Vue的算法是遍历dom中的所有节点,只要有一个元素中有__vue__属性循环退出即可以判断页面使用了Vue。接下来我们去Vue源码中寻找__vue__,在和生命周期有关的文件src/src/core/instance/lifecycle.js中我们找到了如下代码源码链接


Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
  const vm: Component = this
  const prevEl = vm.$el
  const prevVnode = vm._vnode
  const restoreActiveInstance = setActiveInstance(vm)
  vm._vnode = vnode
  // Vue.prototype.__patch__ is injected in entry points
  // based on the rendering backend used.
  if (!prevVnode) {
    // initial render
    vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)
  } else {
    // updates
    vm.$el = vm.__patch__(prevVnode, vnode)
  }
  restoreActiveInstance()
  // update __vue__ reference
  if (prevEl) {
    prevEl.__vue__ = null
  }
  if (vm.$el) {
    vm.$el.__vue__ = vm
  }
  // if parent is an HOC, update its $el as well
  if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
    vm.$parent.$el = vm.$el
  }
  // updated hook is called by the scheduler to ensure that children are
  // updated in a parent's updated hook.
}

通过分析源码得知vm是当前的Vue实例,vm.$el是实例挂载的dom元素,通过其中的vm.$el.vue = vm 将dom的__vue__属性指向Vue实例。现在原理弄懂了,我们来解决实际问题---在production模式下使用Vue devtools。

在启动应用之前修改Vue.config.devtools就可以打开Vue devtools,这里用断点调试的方法强行在页面渲染完成之前修改Vue.config.devtools的值

  1. 找到网页js中有关Vue的代码,
  2. 在合适的行打上断点
  3. 修改Vue.config.devtools的值
  4. 恢复断点重新打开浏览器调试工具就会看到Vue devtools已经被打开

以下举个例子 我打开了一个使用Vue但是使用production模式的网页

去网页的源码中寻找有关Vue的代码,这里一般去app.[hash].js中寻找

点击上图中的代码格式化工具好打断点,然后按ctrl+f搜索 el: (注意直接搜索vue可能不会搜出结果因为代码经过混淆,也可以都其他有关Vue的)

通过上图我们可以看到有两行很熟悉的代码,一行是e.component一行是e.derective,所以我们很肯定e是Vue构造函数,我们在附近打上断点
然后刷新页面,在console中设置e.config.devtools = true

染回恢复断点。重新按一下F12就会看到Vuedevtools已经出现,就可以使用devtools看想要的东西了


因为我这边chrome断点后刷新很容易卡死,所有最后几张图是在firfox下完成的,新人小白第一篇文章,不喜勿喷

联系方式

github github.com/2239559319

mail w2239559319@outlook.com