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

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

需求的产生

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

大佬0:开个新的分支做吧,
大佬1:但是现在这个工程,已经做了大量的打包配置,并且有很多可复用的组件和封装好的类,如果有一天这些内容要做更改呢,我总不能没一个分支都去修改吧,
运维:我们可以传到公司的git上,公共内容改变时只要重新pull一下就行了,
大佬2:
大佬n-1:…
大佬n:…
小丫小王子:我们可以像分布式那样垂直拆分一下我们的项目吗?提取公共部分,然后分模块进行编译,\

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

webpack运行过程

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FOLSXnb3-1587029783451)(https://user-gold-cdn.xitu.io/2020/4/16/1718249a275901ca?w=356&h=463&f=png&s=18602)]
一个工程,默认就是一个打包入口,build文件夹内存放着webpack的打包配置,包括开发环境和生产环境。
当我们执行npm run dev/build时,webpack会读取build文件夹下对应的配置文件,
找到打包入口文件和模板文件,也就是main.jsindex.html
然后通过webpack配置的loader对不同类型文件进行解析或编译,生成不同浏览器都可识别的js和index.html。

文件结构变化

既然我们要用多入口打包,自然就要在不同的模块下创建入口文件和编译文件,然后我们让他对模块A打包,
他就去访问模块A的main.jsindex.html
让他对模块B打包,他就访问模块B的main.jsindex.html。这时候我们的文件结构就要变
成这样子,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZZmkauuh-1587029783455)(https://user-gold-cdn.xitu.io/2020/4/16/171824b5ce466564?w=363&h=564&f=png&s=22677)]
注意这里的数据仓库,尽管是不同的模块,但是他们仍然使用一套数据仓库,所以,
这里我们可以放在最外面,然后在每一个模块下,让他们按需引入就好了。

最后文件结构如下

实现

1.yargs:接收命令行参数

安装
npm install yargs --D

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

接收参数
const yargs = require('yargs')
const module_fileName = yargs.argv.env

执行一下发现读取到了

接收到参数后,我们可以把他提取到公共部分,
因为生产环境和开发环境对应的打包文件不同,直接调用方法取值就行了,

在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.js

在build/webpack.base.conf.js文件中修改entry
  entry: utils.entry(),
2.2.index.html

模板文件就相对复杂点了,同样生产环境和开发环境都需要他,而且我们的热更新也要用他

  • 首先修改开发环境

    在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、甚至是嵌套子模块——从上至下进行同样方式的分割
https://vuex.vuejs.org/zh/guide/modules.html

这部分可以使用官方推荐的modules,modules但是如果项目在搭建的时候没有采取该方案,则需要修改每一个使用vuex的组件,工程量比较大,如果很不幸,你的项目起初没有使用数据仓库的模块化方案,那可以考虑下面这种方案。

3.2 文件合并方案

这里呢,因为项目之前没有考虑这个情况,所以并没有模块化,考虑到修改起来很复杂,还有可能写错,所以使用另一种方式

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

根目录下的数据仓库


每个模块下的内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lXQvVVnx-1587029783465)(https://user-gold-cdn.xitu.io/2020/4/16/171824c863099506?w=247&h=227&f=png&s=7574)]

我们在模块中按需引入

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

这里引入的就是文件名,有了文件名的数组,我们可以动态的require进来,
然后使用Object.assign方法将对象合并,最后export出实例化的Vuex.Store对象
代码如下

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按需加载,本文的方案只是演示了一种解决方案,如果工作量不是很大的情况下,还是推荐使用官方的Module方案
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值