【webpack多入口打包】单工程下的多项目结构

(注:本文以vue-cli 2.x为例)html

需求的产生

起初,咱们的项目还只是简单的一个脚手架建立的简单工程,直到有一天,公司决定在现有基础上再出一个 版本,现有内容不变,两个版本并存,后期有可能还会出现更多版本,做为前端,咱们怎么作最好呢,前端

大佬0:开个新的分支作吧,
大佬1:可是如今这个工程,已经作了大量的打包配置,而且有不少可复用的组件和封装好的类,若是有一天这些内容要作更改呢,我总不能没一个分支都去修改吧,
大佬2:咱们能够传到公司的git上,公共内容改变时只要从新pull一下就好了,
大佬n:...
小王子:咱们能够像分布式那样垂直拆分一下咱们的项目吗?提取公共部分,而后分模块进行编译,
众人:...vue

emmmmm,说的怪好,怎么实现呢,node

webpack运行过程

首先看一下默认的文件结构webpack

一个工程,默认有一个打包入口,build文件夹下存放着webpack的打包配置,包括开发环境和生产环境。 当咱们执行npm run dev(或build)时,webpack会读取build文件夹下对应的配置文件, 找到打包的入口文件( main.js)和模板文件( index.html),而后经过咱们配置的loader对不一样类型文件进行解析或编译,最后生成不一样浏览器均可识别的js和index.html。

文件结构变化

既然咱们要用多入口打包,固然就不能再用一个入口文件(main.js)和模板文件(index.html)了,咱们在不一样的模块下分别建立他们,而后咱们对模块A打包, 他就自动去访问模块A的main.jsindex.html; 对模块B打包,他就自动去访问模块B的main.jsindex.html。 这时候咱们的文件结构就要变成这样子,git

注意这里的 数据仓库,尽管咱们如今有了多个的模块,可是他们仍然使用一套vuex便可,因此,这里咱们能够把 store放在最外面,而后在每个模块下,让他们按需引入就行了。

实现

1.yargs:接收命令行参数

安装
npm install yargs --D

在命令后面添加参数
node build/build.js --env module1

接收参数
const yargs = require('yargs')
const module_fileName = yargs.argv.env
复制代码

执行一下发现读取到对应的参数了,咱们再进行下一步, 咱们能够把接收参数的方法提取到公共部分, 由于生产环境和开发环境对应的打包文件都要使用他,咱们直接在使用的地方调用方法取值便可了,web

在build/utils.js文件中添加如下代码

  + const yargs = require('yargs')
  + const fileName = yargs.argv.env
  
  + // 自定义入口main.js
  + exports.entry = function () {
  +   return {
  +     app: './src/modules/' + fileName + '/main.js'
  +   }
  + }
  
  + // 自定义入口html文件
  + exports.template = function () {
  +   return './src/modules/' + fileName + '/index.html'
  + }
复制代码

2.动态读取main.js和index.html

2.1.main.js

做为入口文件,生产环境和开发环境都要从这里进入,属于基础配置,因此咱们找到webpack.base.conf.jsvuex

在build/webpack.base.conf.js文件中修改entry
  entry: utils.entry(),
复制代码

2.2.index.html

模板文件的使用就相对复杂点了,一样生产环境和开发环境都须要他,并且咱们的热更新也要用他vue-cli

  • 首先修改开发环境npm

    在build/webpack.dev.conf.js修改devServer.historyApiFallback.rewrites
        devServer: {
            historyApiFallback: {
              rewrites: [
                {from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, utils.template())},
              ],
            }
            ...
        }
    
    在build/webpack.dev.conf.js修改plugins
        plugins: [
            new HtmlWebpackPlugin({
                filename: utils.template(),
                template: utils.template(),
                inject: true
            }),
            ...
        ]
    复制代码
  • 接着修改生产环境

    在build/webpack.dev.conf.js修改plugins
    plugins: [
        new HtmlWebpackPlugin({
            template: utils.template(),
        ...
        })
    ]
    复制代码
  • 最后测试一下,咱们分别执行两个命令

    npm run dev:module1
    
    npm run dev:module2
    
    等到编译经过后,发现webpack启动了两个服务器,
    分别是module1和module2的项目,
    这就表示咱们的修改生效了
    复制代码

3.模块化 数据仓库

3.1 官网提供的方案

关于数据仓库的模块化,vuex自己提供了方案

Vuex 容许咱们将 store 分割成模块(module)。每一个模块拥有本身的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行一样方式的分割 vuex.vuejs.org/zh/guide/mo…

官方推荐了modules,同时咱们配合registerModule,能够实现数据仓库的按需引入,是个很好的优化方案。

可是咱们的项目在搭建的时候没有考虑到如今这种状况。采起该方案,意味着咱们要修改每个使用了vuex的组件,工程量比较大,若是很不幸,你的状况像咱们同样,或许能够考虑下面这种方案。

3.2 文件合并方案(require + Object.assign)

文章开头咱们已经展现的文件的结构,数据仓库放在项目根目录, module1和module2只要按需引入数据仓库的模块便可 这里咱们这样作,

首先看下根目录下的数据仓库

这是每一个模块的内容

咱们在module1中按需引入

src/module1/store/config.js
  export [
    'common',
    'alarm',
    'params_3dCity',
    'params_sky',
    'queue_message',
    'user_city'
  ]
复制代码

这里字符串的内容就是文件名,有了他,咱们能够动态地将文件require进来,而后使用Object.assign方法将对象合并,最后export出一个实例化的Vuex.Store对象,main.js直接使用便可。

代码以下

src/module1/store/config.js
  
  import Vue from 'vue'
  import Vuex from 'vuex'
  Vue.use(Vuex)
  import config from './config'
  
  const state = {};
  const mutations = {};
  const actions = {};
  
  for(let fileName of config) {
    const module = require('@/store/' + fileName);
  
    Object.assign(state, state, module.default.state);
    Object.assign(actions, actions, module.default.actions);
    Object.assign(mutations, mutations, module.default.mutations);
  }
  
  export default new Vuex.Store({
    state,
    mutations,
    actions,
  })
复制代码

4.配置命令,按需编译

在package.json中添加以下命令
+  "dev:module1": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --env module1",
+  "dev:module2": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --env module2",
+  "build:module1": "node build/build.js --env module1",
+  "build:module2": "node build/build.js --env module2",
复制代码

总结

  • 多入口打包对生产环境与开发环境都有要求,因此入口(entry)的内容要根据参数改变
  • 尽量提取公共部分,包括分装的公用类,util函数,公共组件等等
  • 减小公共部分与每一个模块的耦合度,尽可能不要在公共部分写业务,若有须要,只需在模块中extends公共组件,而后在模块中编写独有的内容便可
  • 数据仓库根据需求决定,官方推荐的方案能够配合registerModule实现按需加载,本文的方案只是演示了一种解决方案,若是工做量不是很大的状况下,仍是推荐使用官方的方案。
相关文章
相关标签/搜索