webpack 大法好
Webpack 是大家熟知的前端開發利器,它可以搭建包含熱更新的開發環境,也可以生成壓縮後的生產環境程式碼,還擁有靈活的擴充套件性和豐富的生態環境。但它的缺點也非常明顯,那就是配置項又多又複雜,隨便拿出某一個配置項(例如 rules
, plugins
, devtool
等等)都夠寫上一篇文章來說明它的 N 種用法,對新手造成極大的困擾。Vue.js(以下簡稱 Vue)絕大部分情況使用 webpack 進行構建,間接地把這個問題丟給了 Vue 的新手們。不過不論是 Vue 還是 webpack,其實他們都知道配置問題的癥結所在,因此他們也想了各自的辦法來解決這個問題,我們先看看他們的努力。
Vue cli 2.x - 提供開箱即用的配置
在之前一長段時間中,我們要初始化一個 Vue 專案,一般是使用 vue-cli 提供的 vue init
命令(這也是 Vue cli 的 v2 版本,之後簡稱 Vue cli 2.x)。而且通常一些比較有規模的專案都會使用 vue init webpack my-project
來使用 webpack 模板,那麼上面提到的配置問題就來了。
為了解決這個問題, Vue 的做法是提供開箱即用的配置,即通過 vue init
出來的專案,預設生成的巨多的配置檔案,截圖如下:
開箱即用是保證了,但一旦要修改,就相當於是進入了一個黑盒,開發者對於一堆檔案,一堆 JSON 望洋興嘆。
webpack 4 - 極大地簡化配置
webpack 4 推出也有一年左右了,它的核心改動之一是極大地簡化配置。它新增了 mode
,把一些顯而易見的配置做成內建的。因此例如 NoEmitOnErrorsPlugin()
, UglifyJSPlugin()
等等都不必寫了;分包用的 CommonsChunkPlugin()
也濃縮成了一個配置項 optimization.splitChunks
,並且已有能適應絕大部分情況的預設值。
據說 webpack 4 構建出來的程式碼的體積還更小了,因此這次升級顯然是必要的。
Vue cli 3.x - 升級 webpack,還搞出了外掛
大約小半年前,Vue cli 推出了 v3 版本,也是一個顛覆性的升級。它把核心精簡為 @vue/cli
,把 webpack 搞成了 @vue/cli-service
, 把其他東西抽象為“外掛”。這些外掛包括 babel, eslint, Vuex, Unit Testing 等等,還允許自定義編寫和釋出。我不在這裡介紹 Vue cli 3.x 的用法和生態,但從結果看,現在通過 vue create
建立的的 Vue 專案清爽了不少。
所以現在的問題是什麼?
如果我們單純開發一個前端 Vue 專案,webpack-dev-server 能幫助我們啟動一個 nodejs 伺服器並支援熱載入,非常好用。可如果我們要開發的是一個 nodejs + Vue 的全棧專案呢?兩者是不可能啟動在同一個埠的。那我們能做的只是讓 nodejs 啟動在埠 A,讓 Vue (webpack-dev-server) 啟動在埠 B。而如果 Vue 需要傳送請求訪問 nodejs 提供的 API 時,還會遇上跨域問題,雖然可以通過配置 proxy 解決,但依然非常繁瑣。而實質上,這是一整個專案的前後端而已,我們應該使用一條命令,一個埠來啟動它們。
拋開 Vue,此類需求 webpack 本身其實是支援的。因為它除了提供 webpack-dev-server 之外,還提供了 webpack-dev-middleware。它以 express middleware 的方式,同樣整合了熱載入的功能。因此如果我們的 nodejs 使用的是 express 作為服務框架的話,我們可以以 app.use
的方式引入這個中介軟體,就可以達成兩者的融合了。
再說回 Vue cli 3。它通過 vue-cli-service
命令,把 webpack 和 webpack-dev-server 包裹起來,這樣使用者就看不到配置檔案了,達成了簡潔的目的。不過實質上,配置檔案依然存在,只是移動到了 node_modules/@vue/cli-service/webpack.config.js
而已。當然為了個性化需求,它也支援使用者通過配置物件 (configureWebpack
) 或者鏈式呼叫 (chainWebpack
) 兩種間接的方式,但不再提供直接修改配置檔案的方式了。
然而致命的是,即便它提供了足夠的方式修改配置,但它不能把 webpack-dev-server 變成 webpack-dev-middleware。這表示使用 Vue cli 3 建立的 Vue 部分和 nodejs(express) 部分是不能融合的。
怎麼解決?
說了這麼多,其實這就是我最近實際碰到的問題以及分析問題的思路。鑑於 Vue cli 3 黑盒的特性,我們無法繼續使用它了(可能以後有升級能解決這個問題,至少目前不行)。而使用 Vue cli 2 又因為它內建的是 webpack 3 且配置檔案一大堆,也讓人無所適從。這麼看,唯一剩下的路就只能自行使用並配置 webpack 4了,這也是本文的內容所在。
技術棧
nodejs 部分
目前比較主流的構建 nodejs 部分的 Web 框架是 express,且不說它的語法有多優雅,使用有多廣泛等等,最主要的原因是剛才提過的 webpack-dev-middleware 就是一個 express 的中介軟體,因此兩者可以無縫銜接。
可惜的是,在我實際的專案中,我使用了 koa 作為了我的 nodejs 框架。其實要說它比 express 好在哪裡我也說不上來,也不是本文的重點。可能出於嚐鮮的目的,或者團隊技術棧統一的目的,或者其他鬼使神差的巧合,反正我用了它,而且開始時還沒意識到有這個融合的問題,直到後來發現 webpack-dev-middleware 和 koa 是不相容的,我內心有過一絲後悔……當然這是後話了。
本文以 koa 為基準。如果您使用的是 express,其實大同小異,而且更加簡單。
Vue 部分
Vue 沒什麼好多說的,就一個版本,不存在 express / koa / 其他的選擇。只是這裡我沒有使用 SSR,而是普通的 SPA 專案(單頁應用,前端渲染)。
目錄結構
既然是兩個專案合體,總有一個目錄結構的安排問題。這裡我不談每個專案內部需要如何組織,那是 Vue / koa 本身的問題,也是個人喜好的問題。我想談的是這兩者之間的組織方式,不外乎以下 3 種:(實際上也是個人喜好問題,見仁見智,這裡只是統一一下表述,避免後續的混淆)
以下截圖中的前後端專案均為獨立專案,即融合之前的,可以單獨執行的那種,所以能看到兩份 package.json 和 package-lock.json
後端專案為基礎,前端專案為子目錄
除了紅框中的 vue 目錄外,其他都是 nodejs 的程式碼。而且因為我只是做個示意,所以 nodejs 程式碼其實也僅僅包含兩個 index.js,public 目錄和兩個 package.json。實際的 nodejs 專案應該會有更多的程式碼,例如 actions(把每個路由處理單獨到一個目錄),middlewares(過所有路由的中介軟體)等等。
這個安排的思路是認為前端是整個專案的一部分(頁面展示部分),所以 Vue 單獨放在一個目錄裡面。我採用的就是這種結構。
前端專案為基礎,後端專案為子目錄
這就和前面一種相反,紅框中的是後端程式碼。這麼安排的理由可能是因為我們是前端開發者,所以把前端程式碼位於基礎位置,後端提供的 API 輔助 Vue 的程式碼執行。
中立,不偏向任何人
看了前面兩種,自然能想到這第三種辦法。不過我認為這種辦法純粹沒事兒找事兒,因為根據 npm 的要求,package.json 是必須放在根目錄的,所以實際上想把兩者完全分離並公平對待是弊大於利的(例如各類呼叫路徑都會多幾層),適合強迫症患者。
改造 Vue 部分
Vue 部分的改造點主要是:
-
package.json 融合到根目錄(nodejs) 的 package.json 裡面去。這裡主要包括依賴 (
dependency
和devDependency
)以及執行命令(scripts
)兩部分。其餘的如browserslist
,engine
等 babel 可能用到的欄位,因為 nodejs 程式碼不需要 babel,所以可以直接複製過去,不存在融合。 -
編寫
webpack.config.js
。(因為 Vue cli 3 是自動生成且隱藏的,這個就需要自己寫)
下面詳細來看。
融合 package.json
剛才有提到過,像 browserslist
, engine
這類 babel 等使用的欄位,因為 nodejs 端是不需要的,所以簡單的複製過去即可。需要動腦的是依賴和命令。
依賴方面,其實前後端共用的依賴也基本不存在,所以實際上也是一個簡單的複製。需要注意的是類似 vue
, vue-router
, webpack
, webpack-cli
等等都是 devDependency
,而不是 dependency
。真正需要放到 dependency
的,其實只有 @babel/runtime
這一個(因為使用了 plugin-transform-runtime
)。
命令方面,本身 Vue 必備的是“啟動開發環境”和“構建”兩條命令(可選的還有測試,這個我這裡先不討論)。因為開發環境需要和 nodejs 融合,所以這條我們放到 nodejs 部分說。剩下的是構建命令,常規操作是通過設定 NODE_ENV
為 production
來讓 webpack 走入線上構建的情況。另外值得注意的是,因為現在 package.json 和 webpack.config.js 不在同級目錄了,所以需要額外指定目錄,命令如下:(cross-env
是一個相當好用的跨平臺設定環境變數的工具)
{
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config vue/webpack.config.js"
}
}
複製程式碼
編寫 webpack.config.js
本文的重點不是 webpack 的配置方式,因此這裡比較簡略,不詳細講述每個配置項的含義
webpack.config.js 本質上是一個返回 JSON 的配置檔案,我們會用到其中的幾個 key。如果要了解 webpack 全部的配置項,可以檢視 webpack 的中文網站介紹。另外如果不想分段檢視,你可以在這裡找到完整的 webpack.config.js。
mode
webpack 4 新增配置項,常規可選值 'production'
和 'development'
。這裡我們根據 process.env.NODE_ENV
來確定值。
let isProd = process.env.NODE_ENV === 'production'
module.exports = {
mode: isProd ? 'production' : 'development'
}
複製程式碼
entry
定義 webpack 的入口。我們需要把入口設定為建立 Vue 例項的那個 JS,例如 vue/src/main.js
。
{
entry: {
"app": [path.resolve(__dirname, './src/main.js')]
}
}
複製程式碼
output
定義 webpack 的輸出配置。在開發狀態下,webpack-dev-middleware(以下簡稱 wdm)並不會真的去生成這個 dist
目錄,它是通過一個記憶體檔案系統,把檔案輸出到記憶體。所以這個目錄僅僅是一個標識而已。
{
output: {
filename: '[name].[hash:8].js',
path: isProd ? resolvePath('../vue-dist') : resolvePath('dist'),
publicPath: '/'
}
}
複製程式碼
resolve
主要定義兩個東西:webpack 處理 import
時自動新增的字尾順序和供快速訪問的別名。
{
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolvePath('src'),
}
}
}
複製程式碼
module(重點)
module
在 webpack 中主要確定如何處理專案中不同型別的模組。我們這裡採用最常用的配法,即告訴 webpack,什麼樣的字尾檔案用什麼樣的 loader 來處理。
{
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js?$/,
loader: 'babel-loader',
exclude: file => (
/node_modules/.test(file) && !/\.vue\.js/.test(file)
)
},
{
test: /\.less$/,
use: [
isProd ? MiniCssExtractPlugin.loader : 'vue-style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.css$/,
use: [
isProd ? MiniCssExtractPlugin.loader : 'vue-style-loader',
'css-loader'
]
}
]
}
}
複製程式碼
上述配置了 4 種檔案的處理方式,它們分別是:
-
/\.vue$/
處理 Vue 檔案,使用 Vue 專門提供的
vue-loader
。這個處理器做的事情就是把 Vue 裡面的<script>
和<style
> 的部分獨立出來,讓它們可以繼續由下面的 rules 分別處理。否則一個.vue
檔案是不可能進入.js
或者.css
的處理流程的。另外如果<style>
有lang
屬性,還可以進入例如.less
,.styl
等其他處理流程。它還需要專門的外掛
VueLoaderPlugin()
,之後可以看到,不要漏掉。 -
/\.js?$/
表面上是處理字尾為
.js
的檔案,但實質上在這裡也用來處理 Vue 裡面<script>
的內容。在這裡我們要做的是使用babel-loader
對程式碼中的高階寫法轉譯為相容低版本瀏覽器的寫法。具體轉譯規則使用.babelrc
檔案配置。另外這裡還忽略了node_modules
(因為其他包在釋出時都已經轉碼過了,不用再處理徒增時間)。不過得確保node_modules
裡的單體 Vue 檔案依然參與轉譯,這也是 Vue 官方文件 的推薦寫法。 -
/\.less$/
我的專案中使用 less 作為樣式前處理器,因此在每個 Vue 檔案都使用了
<style lang="less">
。這樣通過vue-loader
,就能讓這條規則中配置的幾個 loader 來處理 Vue 檔案中的樣式了。這幾個 loader 分別做的事情是:-
vue-style-loader
把樣式以
<style>
標籤的形式插入在頁面頭部,只在開發狀態下使用。它和
style-loader
的差異並不大,但既然 Vue 官方文件建議使用這個,那我們就用這個吧。 -
mini-css-extract-plugin
的 loader把樣式抽成一個單獨的 css 檔案並在
<head>
標籤中以<link rel="stylesheet">
的方式引用,取代原來 webpack 3.x 的extract-text-webpack-plugin
,只在生產狀態下使用。它同樣需要在外掛中增加
MiniCssExtractPlugin()
以配合使用。 -
css-loader
支援通過隱式的方式載入資源。例如如果在 JS 檔案中編寫
import 'style.css'
,或者在樣式檔案中編寫url('image.png')
,經過css-loader
可以把style.css
和image.png
都引入到 webpack 的處理流程中。這樣針對 css 的所有 loader 就可以處理style.css
,而針對所有圖片的 loader(例如尺寸很小就自動轉為 base64 的url-loader
)都可以處理image.png
了。 -
less-loader
使用 less 前處理器必須載入的 loader,用以把 less 語法轉化為普通的 css 語法。
基本上每個前處理器都有對應的 loader,例如
stylus-loader
,sass-loader
等等,可以按需使用。
-
-
/\.css$/
和
.js
規則相似,這條規則可以同時應用於.css
的字尾檔案以及 Vue 中的<style>
(且沒有寫lang
的)部分。
plugins(重點)
外掛和規則類似,也是對載入進入 webpack 的資源進行處理。不過和規則不同,它並不以正則(多數為字尾名)決定是否進入,而是全部進入後通過外掛自身的 JS 寫法來確定處理哪些,因此更加靈活。
前面提過,有些功能需要 loader 和 plugins 配合使用,因此也需要宣告在這裡,比如 VueLoaderPlugin()
和 MiniCssExtractPlugin()
。
在我們的專案中,外掛分為兩類。一類是不論環境(開發還是生產)都要使用的,這一類有 2 個:
{
"plugins": [
// 和 vue-loader 配合使用
new VueLoader(),
// 輸出 index.html 到 output
new HtmlwebpackPlugin({
template: resolvePath('index.html')
})
]
}
複製程式碼
另外一類是生產環境才需要使用的,也有 2 個:
if (isProd) {
webpackConfig.plugins.push(
// 每次 build 清空 output 目錄
new CleanWebpackPlugin(resolvePath('../vue-dist'))
)
webpackConfig.plugins.push(
// 分離單獨的 CSS 檔案到 output,和 MiniCssExtractPlugin.loader 配合使用
new MiniCssExtractPlugin({
filename: 'style.css',
})
)
}
複製程式碼
optimization
optimization 是一個 webpack 4 新增的配置項,主要處理生產環境下的各類優化(例如壓縮,提取公共程式碼等等),所以大部分的優化都在 mode === 'production'
時會使用。這裡我們只使用它的一個功能,即分包,以前的寫法是 new webpack.optimize.CommonChunkPlugin()
,現在只要配置就可以了,配置方法也很簡單:
{
optimization: {
splitChunks: {
chunks: 'all'
}
}
}
複製程式碼
這樣,從 node_modules
來的程式碼會打包到一起,命名為 vendors~app.[hash].js
,這裡面可能包含了 Vue, Vuex, Vue Router 等等第三方的程式碼。這些程式碼不會經常修改,所以獨立出來並新增長時間的強制快取能顯著提升站點訪問速度。
看看編譯完成的產物
通過執行 npm run build
,能夠呼叫 webpack-cli
來執行剛才編寫的配置檔案。編譯成功後,會在根目錄下生成一個 vue-dist
目錄,裡面存放的內容如下:(如果做了 Vue 的路由懶載入,即 const XXX = () => import('@/XXX.vue')
,檔案會根據路由分割,因此數量會更多)
總共 4 個檔案
-
index.html
存放唯一的 HTML 入口,裡面包含對各 JS, CSS 檔案的引用,並定義了容器節點。使用靜態伺服器啟動後,由於 JS 的執行,可以執行前端渲染。 -
style.css
存放所有的樣式。這些樣式都是從每個 Vue 檔案的<style lang="less">
部分中抽出來合併而成的。 -
app.[hash].js
存放所有的自定義 JS,即每個 Vue 檔案的<script>
部分,以及如app.js
,router.js
,store.js
的程式碼等等。 -
vendors~app.[hash].js
如上所述,存放所有類庫 JS,如 vue-router, vuex 本身的程式碼。
對 nodejs 來說,需要關心的只是這個 index.html
而已,其他 3 個都會由它負責引入。那麼我們接下來看看如何改造 nodejs 部分。
改造 nodejs(koa) 部分
koa 部分需要我們改造的點主要有:
-
package.json
nodejs 專案的標配,記錄依賴,指令碼,專案資訊等等。我們需要在這裡和 Vue 端的 package.json 進行合併,尤其是
npm run dev
指令碼的合併。 -
index.js
nodejs 的程式碼入口,通過命令
node index.js
啟動整個專案。在這裡可以註冊路由規則,註冊中介軟體,註冊 wdm 等等,絕大部分邏輯都在這裡。因為開發環境和生產環境的行為不盡相同(例如開發環境需要 wdm 而生產環境不需要),因此可以分為兩個檔案(
index.dev.js
和index.prod.js
),也可以在一個檔案中通過環境變數判斷,這個因人而異。雖然 koa 的路由規則和中介軟體都可以寫在這裡,但通常只要是略有規模的專案,都會把路由處理和中介軟體分別獨立成
actions
和middlewares
目錄分開存放(名字怎麼起看自己喜好)。配置檔案(例如配置啟動埠號)也通常會獨立成config.js
或者config
目錄。其他的例如util
目錄等也都按需建立。我們需要在這裡統一前後路由,並使用 wdm 等
package.json
在“改造 Vue 部分”的 package.json 中曾經講過,Vue 專案的依賴都直接複製到外層的 package.json 中來,還增加了一條 npm run build
命令。這裡會再列出兩條命令,達成最基本的的需求。
我為了區分執行環境,把 index.js
拆解為了 index.dev.js
和 index.prod.js
。如上面所說,你也可以就在一個檔案裡用 process.env.NODE_ENV
來判斷執行環境。
啟動開發伺服器
常規的 koa 服務,一般我們通過 node index.js
來啟動。但 nodejs 預設沒有熱載入,因此修改了 nodejs 程式碼需要重啟伺服器,比較麻煩。以前我會使用 chokidar
模組監聽檔案系統的變化,並在變化時執行 delete require.cache[path]
來實現簡單的熱載入機制。但現在有一款更方便的工具幫我們做了這個事情,那就是 nodemon
。
"nodemon -e js --ignore vue/ index.dev.js"
複製程式碼
它的使用方式也很簡單,把 node index.js
換成 nodemon index.js
,他就會監聽以這個入口執行的所有檔案的變化,並自動重啟。但我們這裡還額外使用了兩個配置項。-e
表示指定副檔名,這裡我們只監聽 js。 --ignore
指定忽略項,因為 vue/
目錄中有 webpack 幫我們執行熱載入,因此它的修改可以忽略。其他可用的配置項可以參考 nodemon 的主頁。
啟動線上環境伺服器
這個就簡單了,直接執行 node
命令即可。所以最終的指令碼部分如下:
{
"scripts": {
"dev": "nodemon -e js --ignore vue/ index.dev.js",
"build": "cross-env NODE_ENV=production webpack --config vue/webpack.config.js",
"start": "node index.prod.js"
}
}
複製程式碼
index.js
這個檔案是 koa 的啟動入口,它的大致結構如下(我使用了 koa-router 來管理路由,且只列舉最最簡單的骨架):
// 引用基本類庫
const Koa = require('koa')
const Router = require('koa-router')
const koaStatic = require('koa-static')
// 初始化
const app = new Koa()
const router = new Router()
// 常規專案可能有中介軟體,即處理所有路由的邏輯,如驗證登入,記錄日誌等等,這裡省略
// 註冊路由到 koa-router。
// 常規專案路由很多,應該獨立到一個目錄去一個個註冊
router.get('/api/hello', ctx => {
ctx.body = {message: 'Greeting from koa'}
})
// koa-router 以中介軟體的形式註冊給 koa
// 就理解為固定寫法
app.use(router.routes());
app.use(router.allowedMethods());
// 為 public 目錄啟動靜態服務,可以放圖片,字型等等。Vue 部分打包的資源在 vue-dist,不在這裡。
app.use(koaStatic('public'));
// 實際專案可能埠還要寫到配置檔案,這裡隨意了
app.listen(8080)
複製程式碼
我們從開發環境和線上環境兩個方面來討論對這個檔案的改造方式。
開發環境
首先是合併前後端路由。
Vue 端使用的是 history 路由模式,因此本身就需要 nodejs 來配合,Vue 官方推薦的是 connect-history-api-fallback 中介軟體,不過那是針對 express 的。我找到了一個給 koa 使用的相同功能的中介軟體,名為 koa2-history-api-fallback。
不論是哪一個中介軟體,原理是一樣的。因為 SPA 只生成一個 index.html
,因此所有的 navigate 路由都必須定向到這個檔案才行,否則例如 /user/index
這樣的路由,瀏覽器會去找 /user/index.html
,顯然是找不到的。
既然 Vue 需求的是所有的 navigate 路由,顯然它不能註冊在 koa 的路由之前,否則 koa 的路由將永遠無法生效。因此路由註冊順序就很自然了:先後端再前端。另外這裡說的 navigate 路由,指的是請求 HTML 的第一個請求,靜態資源的請求不在其內,因此例如上述的 public
靜態路由和 Vue 的中介軟體的前後順序就無所謂了。
所以路由部分融合後大概是這樣:
// 後端(koa)路由
// koa-router 的單個註冊部分省略
app.use(router.routes());
app.use(router.allowedMethods());
// 前端(vue)路由
// 所有 navigate 請求重定向到 '/',因為 webpack-dev-middleware 只服務這個路由
app.use(history({
htmlAcceptHeaders: ['text/html'],
index: '/'
}));
app.use(koaStatic('public'));
複製程式碼
其次就是問題的最開端,webpack-dev-middleware 的使用。
和 Vue 的中介軟體類似,webpack-dev-middleware 也是隻支援 express 的(這些都表明 express 的生態更好),然後我也找了個 koa 版本的替代方案,叫做 koa-webpack。
使用起來倒也不麻煩,如下:
const koaWebpack = require('koa-webpack')
const webpackConfig = require('./vue/webpack.config.js')
// 注意這裡是個非同步,所以和其他 app.use 以及最終的 app.listen 必須在一起執行
// 可以使用 async/await 或者 Promise 保證這一點
koaWebpack({
config: webpackConfig,
devMiddleware: {
stats: 'minimal'
}
}).then(middleware => {
app.use(middleware)
})
複製程式碼
一個完整的 index.dev.js
可以檢視這裡。
線上環境
線上環境和開發環境有兩處不同,我們著重講一下這兩個不同點。
首先,線上環境不使用 webpack-dev-middleware (koa-webpack),因此這部分程式碼不需要了。
其次,因為構建後的 Vue 程式碼全部位於 vue-dist 目錄,而我們需要的 HTML 入口以及其他 JS, CSS檔案都在其中,因此我們需要把 vue-dist 目錄新增到靜態服務中可供訪問,另外 history fallback 的目標也有所改變,如下:
// 後端(koa)路由
// koa-router 的單個註冊部分省略
app.use(router.routes());
app.use(router.allowedMethods());
// 前端(vue)路由
// 所有 navigate 請求重定向到 /vue-dist/index.html 這個檔案,配合下面的 koaStatic('vue-dist'),這裡只要填到 '/index.html' 即可。
app.use(history({
htmlAcceptHeaders: ['text/html'],
index: '/index.html'
}));
app.use(koaStatic('vue-dist'));
app.use(koaStatic('public'));
複製程式碼
一個完整的 index.prod.js
可以檢視這裡。
這麼多配置新手看了還是很懵怎麼辦?
雖然我們討論了這麼多,但不要害怕,實際上的重點只有三個,我們來總結一下:
-
我們需要自己編寫 Vue 的 webpack.config.js,處理 loader, plugins 等等
-
我們需要合併前後端的兩個 package.json,把兩方的依賴合併,並編寫三條指令碼 (
dev
,build
,start
) -
我們需要改動
index.js
,處理路由順序,並在開發環境呼叫 webpack-dev-middleware
為了簡單上手,我把專案中的業務程式碼抽離,留下了一個骨架,可以作為 Vue + koa 專案的啟動模板,放在 easonyq/vue-nodejs-template。不過我覺得我們還是應當掌握配置方法和原理,這樣以後如果技術棧的某一塊發生了變化(例如 webpack 出了 5),我們也能夠自己研究修改,而不是每次都以解決任務為最優先,能跑起來就不管了。
願我們大家在前端道路上都能越走越順!