目錄
- 一、簡介
- 二、實作過程
-
- 1. 配置打包指令(指定打包模式)
- 2. 定義模式行為
- 3. 定義打包邏輯
- 三、打包模式的應用
- 總結
一、簡介
關于如何以及為什麼要建構多頁vue應用,我們在上一篇文章中已經介紹過,感興趣的請參考建構多頁vue應用。本文我們要介紹的是,對于一個多頁應用,如何單獨打包其中一個(或幾個)頁面。
一般來說,多頁應用不需要打包單個頁面,這多個頁面可以作為整個應用直接放在靜态資源伺服器上。不過我們也說過,多頁應用的每個頁面也可能會放在不同的伺服器上,這時候如果往每個伺服器上都放置完整的資源包,就會顯得過于臃腫。于是我們可能就需要将某個頁面單獨打包出來。
誠然,有一個很明顯的方法,就是在每次打包的時候直接删掉
vue.config.js
的pages字段裡不相關的頁面,如:
module.exports = {
pages: {
page1: {...},
// page2: {...},
// page3: {...}
}
}
顯然,這樣打包出來的結果就是隻有page1頁面了。
但是每次打包都删改配置檔案并不是一種很優雅的做法。我們需要的方案是有多個打包指令,執行對應的打包指令即可打包對應的頁面,這樣我們就可以不再改配置檔案了。下面我們來介紹這種方法:
二、實作過程
要實作通過不同的打包指令來打包單獨的頁面,需要先從打包指令本身說起。
1. 配置打包指令(指定打包模式)
我們執行的打包指令為
npm run build
,這個指令執行的是
package.json
的
scripts
字段下的
build
指令,它的原始值如下:
{
...
"scripts": {
...
"build": "vue-cli-service build"
}
...
}
也就是說,這個指令實際上是在調用
vue-cli-service
服務的
build
指令。
根據vue-cli的文檔介紹,build指令後面可以跟一個mode參數,定義打包模式,預設的打包模式包括
production
、
development
和
test
三個,它們的行為主要是把全局的
process.env.NODE_ENV
變量置為對應的值(即
production
、
development
和
test
)。在省略mode參數的情況下,預設值是
production
,即生産模式。
除了這三個預設模式外,我們還可以自定義打包模式。假如我們想定義一個專門打包page1的打包模式,就可以這樣一個指令:
"scripts": {
"build-page1": "vue-cli-service build --mode page1"
}
我們希望,當執行
npm run build-page1
指令時,webpack就會自動把page1打包出來。
但顯然隻修改這裡是不夠的,webpack并不知道page1是什麼模式,以及它應該有哪些行為。接下來我們需要為page1這個打包模式定義行為。
2. 定義模式行為
啟用一個打包模式的本質含義,其實是啟用一組特定的環境變量。
比如,
production
模式會把
process.env.NODE_ENV
的值置為
production
,而
process.env
是webpack所在的node環境提供的全局變量。這樣,在代碼中,隻需要根據
process.env.NODE_ENV
的值就可以判斷目前處于哪種打包模式了,代碼可以根據不同的打包模式産生不同的行為。
對于自定義的打包模式,我們也可以指定一組全局變量,以使代碼産生不同的行為。vue-cli文檔規定,每個自定義模式對應的變量應該定義在根目錄下的
.env.xxx
檔案内。比如我們的打包模式名為
page1
,那麼就需要在項目根目錄下建立一個
.env.page1
(注意,這裡是沒有字尾的)檔案:
當指定打包模式為
page1
時,webpack就會啟用這個檔案中所定義的變量。檔案内可以這樣定義變量:
.env.page1
NODE_ENV = 'production'
page = 'page1'
現在,當使用打包模式
page1
時,webpack就會讀取這個環境檔案,然後把這裡定義的變量逐個添加到全局對象
process.env
上。是以此時
process.env.page
的值就是字元串
'page1'
(NODE_ENV的值需要在這裡手動設定為
'production'
,否則會以開發模式打包)。
向全局變量注冊了變量page之後,我們就可以在程式中根據它定義打包行為了。
3. 定義打包邏輯
之前我們定義多頁應用的配置時,pages字段配置的是固定的值,也就是定義了三個打包入口。現在有了全局變量
process.env.page
,我們就不需要設為定值了,而是可以根據這個變量的值,動态定義打包入口。此時vue.config.js可以進行如下改造:
function resolvePages(page){
let page1 = {
entry: 'src/pages/page1/main.js',
template: 'public/index.html',
filename: 'page1.html',
};
let page2 = {
entry: 'src/pages/page2/main.js',
template: 'public/index.html',
filename: 'page2.html',
};
let page3 = {
entry: 'src/pages/page3/main.js',
template: 'public/index.html',
filename: 'page3.html',
};
return page === 'page1' ? { page1 } :
{ page1, page2, page3 };
}
module.exports = {
pages: resolvePages(process.env.page),
}
我們現在讀取
process.env.page
的值進行判斷,如果它的值是
page1
,那麼說明我們處于
page1
打包模式下,于是resolvePages函數傳回的對象僅包括
page1
這一個頁面的入口,否則就傳回三個打包入口,進行完整多頁應用的建構。
基于這個原理,我們同樣可以定義
page2
、
page3
的打包模式,甚至定義更加複雜的打包模式(如同時打包
page1
和
page2
),此時resolvePages函數的傳回值隻是稍微複雜一些:
return page === 'page1' ? { page1 } :
page === 'page2' ? { page2 } :
page === 'page1,page2' ? { page1, page2 } :
...
{ page1, page2, page3 };
現在一切準備就緒。
我們執行
npm run build-page1
指令時,vue-cli會先讀取指定的
page1
模式對應的
.env.page1
檔案,它會為
process.env
新增環境變量
page
。然後vue-cli會去讀取
vue.config.js
配置檔案中的pages字段,調用resolvePages函數,并傳入變量
process.env.page
,得到打包入口對象為:
{ page1 }
,由于隻有一個打包入口,是以vue-cli會調用webpack的打包服務,對該頁面進行單獨建構。
有人可能會問,難道隻有打包時才能指定mode嗎?其實不是的,
serve
指令也有mode參數。根據以上過程,你也可以單獨啟動某一個頁面,此時你隻需要定義下面這樣的腳本:
{
...
"scripts": {
"serve-page1": "vue-cli-service serve --mode page1"
}
}
與打包過程沒有什麼差别,這裡就不再贅述了。
需要注意的是,public檔案夾下的資源是靜态資源,無論使用任何打包模式,它們都會被直接拷貝到dist檔案夾下。
三、打包模式的應用
打包模式的應用不僅在于單頁打包,我們舉一個更常見的例子:假設我們的代碼打包後可能被派發到多個項目上,而這些項目之間卻存在一些細小的差别(比如某個表格的樣式不同)。如果我們為每個項目都單獨建立一份代碼,那麼代碼庫将變得極難維護。這時候,打包模式就可以派上用場了。
我們可以為這些項目分别建立單獨的打包指令,如:
{
"scripts": {
"build-project1": "vue-cli-service build --mode project1",
"build-project2": "vue-cli-service build --mode project2",
}
}
然後在根目錄下分别為每個打包模式定義一個環境檔案:
.env.project1
,
.env.project2
。我們在這裡分别定義一組全局變量:
.env.project1
.env.project2
這裡需要強調的是,如果需要在src路徑下的代碼中引用env中的某個變量,那麼這個變量必須以
VUE_APP_
開頭,否則結果都會是undefined(在src之外的代碼中沒有這個限制,如上面我們在vue.config.js中引用的變量就沒有遵循這個限制,當然你可以更規範地對所有自定義變量添加這個字首,以防止出錯)。
現在,當執行
npm run build-project1
時,
process.env.VUE_APP_PROJECT
的值就是
project1
,我們可以在代碼中根據這個值來區分不同的項目。比如在某個元件中,我們需要對項目1添加一些額外的邏輯:
methods: {
doSomething(){
if(process.env.VUE_APP_PROJECT === 'project1'){
// 對project1項目添加額外的邏輯
...
}
}
}
當你運作
npm run build-project1
打包指令時,if語句的内容就會生效,反之,在其他模式下,它不會生效。同樣的,你也可以配置項目1專屬的啟動指令:
你可以運作
npm run serve-project1
來啟用project1環境。
總結
通過學習在多頁應用中打包單個頁面,我們學會了如何自定義打包模式,這應該是本文最重要的知識點。将打包模式推廣,我們學會了如何在一份代碼中添加多個項目的邏輯,這使得我們維護多個項目分支的成本大大降低。打包模式的用途可能還遠不止這些,希望讀者了解它,并熟練運用。