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作为根组件的属性。
相关推荐
Nan_Shu_61410 小时前
学习: Threejs (2)
前端·javascript·学习
G_G#10 小时前
纯前端js插件实现同一浏览器控制只允许打开一个标签,处理session变更问题
前端·javascript·浏览器标签页通信·只允许一个标签页
@大迁世界10 小时前
TypeScript 的本质并非类型,而是信任
开发语言·前端·javascript·typescript·ecmascript
GIS之路11 小时前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug11 小时前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu1213811 小时前
React面向组件编程
开发语言·前端·javascript
持续升级打怪中11 小时前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路11 小时前
GDAL 实现矢量合并
前端
hxjhnct11 小时前
React useContext的缺陷
前端·react.js·前端框架
前端 贾公子12 小时前
从入门到实践:前端 Monorepo 工程化实战(4)
前端