结合loader实现Vuex动态注册Store模块

1,165 阅读3分钟

VuexVue全家桶的重要一员,日常使用中一般都是下面这种项目结构。

├── index.html
├── main.js
├── api
│   └── ... # 抽取出API请求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── actions.js        # 根级别的 action
    ├── mutations.js      # 根级别的 mutation
    └── modules
        ├── cart.js       # 购物车模块
        └── products.js   # 产品模块

问题

现在我的项目模块比较多,而且大部分模块用到了Vuex,第一次打开网页单单Store所在的Chunk就有几百K,而且Store太臃肿对运行效率必定也会有所影响,实在不符合我追求高效简洁的理念。VuexAPI也提供了registerModule unregisterModule来动态注册和卸载模块,具体怎么使用呢?

方案level1

在模块对应页面组件的生命周期函数beforeCreate beforeDestroy里边调用API来注册写在就好喽。代码就是下边这样子。

import module from '@/src/store/module'
export default {
	beforeCreate() {
    	if(!this.$store.hasModule('modulePath')) {
        	this.$store.registerModule('modulePath', module);
        }
    },
	beforeDestroy() {
    	if(this.$store.hasModule('modulePath')) {
        	this.$store.unregisterModule('modulePath');
        }
    }
}

这样写太不严谨了,modulePath应该用个变量,另外好多模块都动态加载的话一个一个写太费劲了吧。OK,再改进一下。

方案level2

// 这里写个mixin
export default function(path, module) {
  return {
    beforeCreate() {
      if (!this.$store.hasModule(path)) {
        this.$store.registerModule(path, module);
      }
    },
    beforeDestroy() {
      if (this.$store.hasModule(path)) {
        this.$store.unregisterModule(path);
      }
    }
  };
}

// 组件里边使用mixin
import mixin from './mixin'
import module from '@/src/store/module'

export default {
	mixins: [mixin("modulePath", module)]
}

其实可以用动态导入,传递模块的地址和namespace两个参数就好,但是webpack打包时仍然会将动态路径下所有文件打包在一起,也就没有代码分割了,所以还是要单独导入。

这样挺不错了,每个组件顶多也就多写三行代码。但是不太对啊,万一我两个组件用一个模块,关了一个组件,就卸载了,我另一个组件怎么用?这个问题好说,mixin里边写个map放上每个模块的引用组件,beforeCreate里边添加引用,同时注册模块,beforeDestroy里边删除引用,如果没有引用就卸载模块。

方案level3

// 不想写了

还有一个问题,我一个组件用多个模块怎么办?这个问题简单,多import几个就好了,

方案level4

import mixin from './mixin'
import module1 from '@/src/store/module1'
import module2 from '@/src/store/module2'
import module3 from '@/src/store/module3'

export default {
	mixins: [mixin("modulePath1", module1), mixin("modulePath2", module2), mixin("modulePath3", module3)]
}

这里不太科学,mixin应该可以支持数组的,我就不写了。

这就有点烦了,一个个import下来累坏我。后期还要手动维护更改。

方案level5(终极方案)

下面介绍一下我的lazy-store-loader,不要import,不要mixin,只要配一下webpack.config.js就行了!!!当然夸张了,还要手动维护一个映射对象。

{
	"modulePath": "@/src/module"
}

就是注册模块时模块的namespace和文件路径的映射。mixinimport会在编译时通过loader注入,同时也会维护每个模块和组件之间的引用,防止提前卸载模块,同时防止了卸载静态注册的模块时引发异常(搞自己项目时踩的坑)内部原理其实和上边的思路差不多,注入的过程是通过解析<script>中的mapActions mapMutations mapState获取使用到的模块,通过映射文件获取到路径,然后注入相关代码。

项目地址

github.com/YinDongFang… 各位大佬感兴趣记得点个star

如果再懒点其实可以直接源码搞到自己项目,映射文件也不用,直接统一用namespace做路径