越不懂的越愛裝
大家都同等:IT世界沒有難不難,只有是否了解過
挑戰(zhàn)目錄
什么是Vue-cli多模塊打包?
在一個項目中,通過配置達到可以共用公共文件,且打包只屬于當前功能的文件的項目包的場景。
Vue-cli多模塊打包的用途累颂?
- 比如我比較常用的:離線包模式本砰。單獨功能模塊打成單獨的離線包供安卓、IOS使用。
- 一個項目的不同版本的實現(xiàn)房待。多模塊打包可以做到抽出公共部分專注不同部分怔球。
- 等等
Webpack為什么可以實現(xiàn)多模塊打包嚼酝?
-
(打包?)由于:Vue-cli(使用webpack)會從入口js,通過導(dǎo)入語句自動尋找所依賴的模塊進行打包
所以:只要通過不同的入口,執(zhí)行打包命令就能打出不同的包竟坛。
-
(執(zhí)行?)由于:腳本文件.js文件中可以獲取如命令:node 腳本文件.js xxx xxx 類的命令的命令行參數(shù)
所以:可以實現(xiàn)通過在package.json文件配置node xxx.js的執(zhí)行命令并傳入?yún)?shù)自動實現(xiàn)配置化打包命令闽巩。
-
(配置?)由于: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] }, ... }
-
(執(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, }
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
上面簡單的提一下多模塊打包項目的的幾個方面,其他的以后在寫吧