【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實現按需加載,本文的方案只是演示了一種解決方案,若是工做量不是很大的狀況下,仍是推薦使用官方的方案。
相關文章
相關標籤/搜索