日更挑戰(zhàn)-Vue-cli之構(gòu)建多模塊項目


越不懂的越愛裝
大家都同等:IT世界沒有難不難,只有是否了解過

挑戰(zhàn)目錄

什么是Vue-cli多模塊打包?

在一個項目中,通過配置達到可以共用公共文件,且打包只屬于當前功能的文件的項目包的場景。


Vue-cli多模塊打包的用途累颂?

  1. 比如我比較常用的:離線包模式本砰。單獨功能模塊打成單獨的離線包供安卓、IOS使用。
  2. 一個項目的不同版本的實現(xiàn)房待。多模塊打包可以做到抽出公共部分專注不同部分怔球。
  3. 等等

Webpack為什么可以實現(xiàn)多模塊打包嚼酝?

  1. (打包?)由于:Vue-cli(使用webpack)會從入口js,通過導(dǎo)入語句自動尋找所依賴的模塊進行打包

    所以:只要通過不同的入口,執(zhí)行打包命令就能打出不同的包竟坛。

  2. (執(zhí)行?)由于:腳本文件.js文件中可以獲取如命令:node 腳本文件.js xxx xxx 類的命令的命令行參數(shù)

    所以:可以實現(xiàn)通過在package.json文件配置node xxx.js的執(zhí)行命令并傳入?yún)?shù)自動實現(xiàn)配置化打包命令闽巩。

  3. (配置?)由于:Vue-cli提供了配置參數(shù)pages用來配置多頁應(yīng)用。(當然webpack也有自己的一套,這里主要是使用Vue)

    所以:可以通過解析命令行參數(shù)拼出pages所需配置格式担汤,然后進行打包涎跨。

    pages多頁配置格式如下:

    {     //下面最少存在一個包名
         "包名1":{
             // page 的入口
          entry: `src/${包名1}/main.js`,
          // 模板來源
          template: "public/index.html",
          // 在 dist/`${包名1}.html` 的輸出
          filename: `${包名1}.html`,
          / 當使用 title 選項時,
          // template 中的 title 標簽需要是 <title><%= htmlWebpackPlugin.options.title %></title>
          title: 包名1,
          // 在這個頁面中包含的塊漫试,默認情況下會包含
          // 提取出來的通用 chunk 和 vendor chunk
          chunks: ["chunk-vendors", "chunk-common", 包名1]
        },
         "包名2":{
          entry: `src/${包名2}/main.js`,
          template: "public/index.html",
          filename: `${包名2}.html`,
          title: 包名2,
          chunks: ["chunk-vendors", "chunk-common", 包名2]
        },
        ...
    }
    
  4. (執(zhí)行?) 由于pages是配置在Vue-cli上的六敬。Vue-cli提供了將其搜索配置的包名啟動為服務(wù)和打包的功能。

    所以: 只需要在配置vue.config.js的module.exports = {pages}之前動態(tài)配置pages驾荣,就可以啟動一個或多個服務(wù)了外构。

    //通過fs.readdirSync(path.resolve(__dirname, "../src"));讀取指定目錄的文件夾。拼裝出上面所以的pages的配置
    const MultiModulesConfig = require("./config/modules.config.js");
    let pages = {};
    
    //process.env.NODE_ENV會預(yù)先根據(jù)命令行參數(shù)賦值
    //開發(fā)環(huán)境 啟動全部的模塊播掷,如果每個包名啟動一次审编。會導(dǎo)致本地出現(xiàn)多個端口服務(wù)。
    //如果是打包則只打所以的包指定模塊名歧匈,若模塊名為all則表示一次性打包所以
    if (process.env.NODE_ENV == "development"||pageName==="all" ) {  
      pages = MultiModulesConfig; 
    } else {
        pages[pageName] = MultiModulesConfig[pageName];
    }
    
    module.exports = {
      pages: pages,
    }
    
  5. pages配置多模塊時垒酬,配置的多個模塊的入口html會打包到同一個文件夾(module.exports = {outputDir: "dist/front/" + pageName,})下,所有啟動的服務(wù)需要帶具體哪個模塊名去訪問。當需要打多個文件夾的不同模塊包是件炉,需要分享設(shè)置pages和outputDir勘究。

由上可知:基于Vue-cli腳手架后,多模塊運行服務(wù)和多模塊打包,簡單到只要配置pages參數(shù)然后繼續(xù)正常的步驟就行了。至于是一個或多個模塊斟冕,就看pages里面配置的是多少模塊而已口糕。


多模塊打包如何解決路由問題?

  • 跨模塊路由守衛(wèi)攔截
1. 定義路由攔截磕蛇。(即定義router.beforeEach(to, from, next) => {...}內(nèi)部的參數(shù))景描。
    const loginIntercept=(to, from, next) => {
        // ...
    }
2. 分別將上述定義的攔截注冊到模塊內(nèi)核模塊外路由攔截中。(多個遍歷執(zhí)行多次即可)
    router.beforeEach(loginIntercept); //模塊內(nèi)部攔截
    MyRoutreIntercept.beforeCrossModule(interceptor); // 跨模塊攔截
3. 通過Promise定義一個攔截器執(zhí)行隊列秀撇,用于串行執(zhí)行所有攔截器
     import { clone,isUndefined } from "lodash"
   syncInterceptorSeries = function(to, from, interceptors) {
    return new Promise((resolve, reject) => {
      const cloneArr = clone(interceptors);
      let exe = function(x) {
        if (!isUndefined(x)) {
          reject(x);
        }
        let fn = cloneArr.shift();
        if (!fn) {
          resolve();
          return;
        }
        fn(to, from, next);
      };
      exe();
    });
  };
4. 區(qū)分跨模塊跳轉(zhuǎn)和正常跳轉(zhuǎn)(這里也可以通過額外傳是否跨模塊參數(shù)確定)超棺。對跨模塊跳轉(zhuǎn)進行攔截處理。
   // 組裝跨模塊目標頁面的數(shù)據(jù)結(jié)構(gòu)
   const to = {
      fullPath: res.path || "",
      hash: "",
      matched: [{}],
      meta: res.meta || {},
      name: res.name || "",
      params: param.param || {},
      path: res.path,
      query: {
        ...param.query,
        crossModule: true,
        moduleName: param.moduleName
      },
      crossModule: true,
      moduleName: param.moduleName,
      fullUrl: this.getCrossModulePath(param)
      };
      const from = this.router.currentRoute;
            //調(diào)用上面的串行執(zhí)行攔截器方法
            return this.syncInterceptorSeries(
          to,
          from,
          this.crossModuleInterceptors
        ).then(
          () => {
            // 執(zhí)行完隊列未發(fā)生攔截行為
            return { granted: true };
          },
          reject => {
            // 發(fā)生攔截行為呵燕,此處reject為攔截器隊列函數(shù)中傳入next()函數(shù)的參數(shù)
            if (reject === false) {
              return { granted: false };
            }
            return { granted: false, redirect: true, params: reject };
          }
        );
  • 跨模塊路由跳轉(zhuǎn)

push:跳轉(zhuǎn)前調(diào)用上面的攔截棠绘,模塊內(nèi)和跨模塊區(qū)分處理。

import * as _ from "lodash";  
push(params) {
    /** 跨模塊跳轉(zhuǎn) */
    if (_(params).get("crossModule")) {
            //跳轉(zhuǎn)前調(diào)用上面的攔截
      this.beforeCrossModuleAction(params).then(res => {
        if (res.granted) {
          this.openFullPath(this.getCrossModulePath(params));
          return;
        }
        if (res.redirect) {
          // 重定向
          if (
            res.params.path === params.path ||
            res.params.name === params.name
          ) {
            // 重定向頁面為原始頁面
            this.openFullPath(this.getCrossModulePath(params));
            return;
          }
          this.push(res.params);
          return;
        }
      });
      return;
    }
    // 模塊內(nèi)
    this.router.push(params);
  }
    
    //跨模塊的跳轉(zhuǎn)方法,fullPath參數(shù)通過encodeURIComponent處理后的拼上參數(shù)的地址
  openFullPath(fullPath) {
    window.location.href = fullPath;
  }

replace: 和push同樣處理,不同在于openFullPath方法。

openFullPath(fullPath) {
  window.location.replace(fullPath);
}

openInNewWindow:打開新的頁面
由于項目由手機和網(wǎng)站項目之分弄唧。所以該部分打開過程有如下判斷

openInNewWindow(fullPath) {
   if (Native.isApp()) {
      Native.openNewWindow({
        url: fullPath
      });
   } else {
      // window.open(fullPath, "_blank");
      window.location.href = fullPath;
  }
}

back|go(n):

back(params){
      localStorage.setItem(RouteBackStorageKey,Json.stringify(params));
      window.history.back();
}

PS:

為了防止push到同一個地址報錯在main.js里面重寫push方法适肠。
Router.prototype.push = function push(location, onResolve, onReject) {
    if (onResolve || onReject){
          return originalPush.call(this, location, onResolve, onReject);
    }
    return originalPush.call(this, location).catch(err => err);
};
  • 跨模塊數(shù)據(jù)傳遞
push,replace可以通過上面舉例的是通過拼接URl的方式傳遞,
另外還可以自己維護Storage本地存儲(略)
back的傳參不太一致:(在被返回的頁面上添加onBack方法候引,當返回時會自動回調(diào)并傳遞參數(shù))
export const onBackGoMixinListener = function (Vue: any) {
  Vue.mixin({
    created() {
      if (this.$options.name === this.$route.name) { //當前頁面組件
        localStorage.removeItem(RouteBackStorageKey)
      }
    },
    beforeRouteEnter(to: any, from: any, next: any) {
      next(((vue: any) => {
          //當前頁面組件
          if (this.$options.name === this.$route.name) {
            const isReturn = localStorage.getItem(RouteBackStorageKey);
            //當前頁面組件返回事件
            if (isReturn) {
              if (vue.onBack) {
                //調(diào)用當前頁面組件返回事件
                vue.onBack(to, from, JSON.parse(isReturn || ""))
              }
            }
          }
        }
      ));
    }
  })
};


多模塊打包如何解決devServer問題侯养?

這個其實應(yīng)該不會有太大問題,最后就是參數(shù)的配置不同而已澄干。在執(zhí)行node 自定義.js 腳本的時候逛揩,根據(jù)命令行參數(shù)或默認的命令行參數(shù)將要用到的數(shù)據(jù)都賦值給process.env.xxxx。用于全局獲取使用麸俘。

其他的問題應(yīng)該就是代理的配置問題辩稽,不屬于該討論范圍內(nèi)


多模塊打包如何解決Vuex.Store問題?

這里使用vuex-persistedstate插件从媚,解決多模塊和刷新時VueX數(shù)據(jù)丟失的問題逞泄。

  • 安裝

    npm install --save vuex-persistedstate

  • 使用:store入口js文件引入并進行配置

    import createPersistedState from "vuex-persistedstate";
    const store = new Vuex.Store({
    plugins: [createPersistedState()]
    });

  • 修改默認配置

    默認使用localStorage存儲,存儲鍵名key是“vuex

    參數(shù) 描述
    key 存儲數(shù)據(jù)的鍵名拜效。(默認:vuex)
    paths 部分路徑可部分保留狀態(tài)的數(shù)組喷众。如果沒有給出路徑,則將保留完整狀態(tài)紧憾。如果給出一個空數(shù)組到千,則不會保留任何狀態(tài)。必須使用點符號指定路徑赴穗。如果使用模塊憔四,請包括模塊名稱(默認:[])
    reducer 將根據(jù)給定路徑調(diào)用以減少狀態(tài)持久化的函數(shù)
    storage 指定存儲數(shù)據(jù)的方式。默認為localStorage 般眉,也可以設(shè)置 sessionStorage
    getState 用來重新補充先前持久狀態(tài)的功能了赵,默認使用:storage定義獲取的方式
    setState 用以保持給定狀態(tài)的函數(shù)。默認使用:storage定義的設(shè)置值方式
    filter 一個將被調(diào)用以過濾setState最終將在存儲中篩選過濾的函數(shù)甸赃。默認為() => true柿汛。

    詳細配置請參考源碼 vuex-persistedstate


上面簡單的提一下多模塊打包項目的的幾個方面,其他的以后在寫吧
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辑奈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子已烤,更是在濱河造成了極大的恐慌鸠窗,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胯究,死亡現(xiàn)場離奇詭異稍计,居然都是意外死亡,警方通過查閱死者的電腦和手機裕循,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門臣嚣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來净刮,“玉大人,你說我怎么就攤上這事硅则⊙透福” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵怎虫,是天一觀的道長暑认。 經(jīng)常有香客問我,道長大审,這世上最難降的妖魔是什么蘸际? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮徒扶,結(jié)果婚禮上粮彤,老公的妹妹穿的比我還像新娘。我一直安慰自己姜骡,他們只是感情好导坟,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著溶浴,像睡著了一般乍迄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上士败,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天闯两,我揣著相機與錄音,去河邊找鬼谅将。 笑死漾狼,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的饥臂。 我是一名探鬼主播逊躁,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼隅熙!你這毒婦竟也來了稽煤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤囚戚,失蹤者是張志新(化名)和其女友劉穎酵熙,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驰坊,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡匾二,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片察藐。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡皮璧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出分飞,到底是詐尸還是另有隱情悴务,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布浸须,位于F島的核電站惨寿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏删窒。R本人自食惡果不足惜裂垦,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肌索。 院中可真熱鬧蕉拢,春花似錦、人聲如沸诚亚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽站宗。三九已至闸准,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間梢灭,已是汗流浹背夷家。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留敏释,地道東北人库快。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像钥顽,于是被迫代替她去往敵國和親义屏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354