Vuex的install方法干了啥

在看服务端渲染的时候,看到在store.js中也要使用Vue.use(vuex),就想看看这一行代码到底做了啥,翻看了源码:github.com/vuejs/vuex/...

(没事干的记录,大佬轻喷,叠甲保命)

扯淡的打包

rollup.config.js

javascript 复制代码
const configs = [
  {
    input: 'src/index.js',
    file: 'dist/vuex.esm-browser.js',
    format: 'es',
    browser: true,
    env: 'development'
  },
  {
    input: 'src/index.js',
    file: 'dist/vuex.esm-browser.prod.js',
    format: 'es',
    browser: true,
    env: 'production'
  },
// ...
  {
    input: 'src/index.cjs.js',
    file: 'dist/vuex.global.prod.js',
    format: 'iife',
    minify: true,
    env: 'production'
  },
]

入口只有index.cjs.jsindex.js,但是这俩的导出:

javascript 复制代码
export {
  Store,
  storeKey,
  createStore,
  useStore,
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers,
  createLogger
}

压根没有install方法,最后全局搜索才发现在src/index.mjs中的导出

javascript 复制代码
export {
  Vuex as default,
  version,
  Store,
  storeKey,
  createStore,
  install,
  useStore,
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers,
  createLogger
}

才有导出的install方法,但是index.mjs并未出现在rollup.config.js中,直到在script/build

javascript 复制代码
async function run() {
  await Promise.all([build(), copy()])
  checkAllSizes()
}

async function copy() {
   await fs.copy('src/index.mjs', 'dist/vuex.mjs')
 }

说白了就是overwrite if exist一个dist/vuex.mjs文件,内容和src/index.mjs一样。

但是仍然存在一个问题,vuex并没有挂载install方法,install方法是实现在Store类中的。并且实际项目运行了后发现,

Vuex确实没有install方法。那为啥会使用Vue.use(Vuex)

答案就是:

Vue.use(Vuex)是Vue 2 接入 Vuex 3.x的用法,而Vue 3 接入 的是Vuex 4,没有挂载install方法的是Vuex 4(但是代码里却依旧留着install的导出。。。不知道为了啥)

Vuex 3.x的install方法

回顾Vuex 3.x的使用方式

javascript 复制代码
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
const store = new Vuex.Store({/* ... */})
new Vue({
  el: '#app',
  store
})
javascript 复制代码
export function install (_Vue) {
  if (Vue && _Vue === Vue) {
    if (__DEV__) {
      console.error(
        '[vuex] already installed. Vue.use(Vuex) should be called only once.'
      )
    }
    return
  }
  Vue = _Vue
  applyMixin(Vue)
}
// mixin.js
export default function (Vue) {
  const version = Number(Vue.version.split('.')[0])

  if (version >= 2) {
    Vue.mixin({ beforeCreate: vuexInit })
  } else {
    // override init and inject vuex init procedure
    // for 1.x backwards compatibility.
    const _init = Vue.prototype._init
    Vue.prototype._init = function (options = {}) {
      options.init = options.init
        ? [vuexInit].concat(options.init)
        : vuexInit
      _init.call(this, options)
    }
  }

  /**
   * Vuex init hook, injected into each instances init hooks list.
   */

  function vuexInit () {
    const options = this.$options
    // store injection
    if (options.store) {
      this.$store = typeof options.store === 'function'
        ? options.store()
        : options.store
    } else if (options.parent && options.parent.$store) {
      this.$store = options.parent.$store
    }
  }
}
  1. vue.use(Vuex) 时是将vuexInit作为beforeCreate回调

  2. 如果每个非根app组件的Option都没有设置store属性,那么就会子组件使用父组件的store,然后由于根app组件传递了store属性,那么就会走if上半判断,将store挂载到根app组件的实例上,然后app的子组件将使用app的store,然后一层一层地这样传下去(好家伙,手动provide inject是吧)

  3. 至于为啥vue 2明明有provideinject,还要使用这种手动的方式进行,是因为这俩api是vue 2.2+ 版本以后才有的,一切为了兼容性咯

Vuex 4.x的install方法

在理解Vue 4的install 方法之前,需要先回顾Vue 4的使用方式

javascript 复制代码
import { createApp } from 'vue'
import { createStore } from 'vuex'// Create a new store instance.
const store = createStore({ /* ... */})
const app = createApp({ /* your root component */ })// Install the store instance as a plugin
app.use(store)

// in some component
const store = useStore()
kotlin 复制代码
 class Store {
     // ....
     install (app, injectKey) {
        app.provide(injectKey || storeKey, this)
        app.config.globalProperties.$store = this
    
        const useDevtools = this._devtools !== undefined
          ? this._devtools
          : __DEV__ || __VUE_PROD_DEVTOOLS__
    
        if (useDevtools) {
          addDevtools(app, this)
        }
      }
 }
 // injectKey.js
import { inject } from 'vue'

export const storeKey = 'store'

export function useStore (key = null) {
  return inject(key !== null ? key : storeKey)
}

可以看出来,

  1. 组件内部获取Store实例的方式是通过provideinject实现的。app.provide(injectKey || storeKey, this)是为了配合useStore
  2. 同时将store实例挂载到全局的Vue上(感觉这个是为了兼容vuex 3的使用习惯)
  3. 由于使用了vue的provideinject,就不用再一层一层地传递store了,因此也就不用使用vue.use(Vuex),以及将store作为根组件的属性。
相关推荐
前端大卫5 分钟前
🔥 如何“为所欲为”地渲染页面:优雅拦截 Fetch 和 XMLHttpRequest!
前端·javascript
苏州第一深情6 分钟前
【vue+leaflet】自定义控件(五)
前端·javascript·vue.js
逾明6 分钟前
在项目中使用Volta控制node版本
前端·node.js
日升8 分钟前
Electron 开发:获取当前客户端真实 IP
前端·javascript·electron
你不会困9 分钟前
用纯JS监控本地文件,让网页拥有千里眼!
前端
枫无痕10 分钟前
promise源码解析
前端·vue.js
曙光就在眼前10 分钟前
奋发图强学 React 系列 (二):React 高阶组件(HOC)
前端·react.js
江城开朗的豌豆10 分钟前
CSS篇:CSS动画实战:如何让一个盒子平滑移动到另一个盒子?
前端·css·面试
北京_宏哥10 分钟前
🔥PC端自动化测试实战教程-2-pywinauto 启动PC端应用程序 - 上篇(详细教程)
前端·windows·python
小钰能吃三碗饭14 分钟前
第五篇:【React 性能优化秘籍】让你的应用丝滑流畅,告别卡顿!
前端·javascript·react.js