【新手向】Vue.js + Node.js(koa) 合體指南

webpack 大法好

Webpack 是你們熟知的前端開發利器,它能夠搭建包含熱更新的開發環境,也能夠生成壓縮後的生產環境代碼,還擁有靈活的擴展性和豐富的生態環境。但它的缺點也很是明顯,那就是配置項又多又複雜,隨便拿出某一個配置項(例如 rulespluginsdevtool等等)都夠寫上一篇文章來講明它的 N 種用法,對新手形成極大的困擾。Vue.js(如下簡稱 Vue)絕大部分狀況使用 webpack 進行構建,間接地把這個問題丟給了 Vue 的新手們。不過不管是 Vue 仍是 webpack,其實他們都知道配置問題的癥結所在,所以他們也想了各自的辦法來解決這個問題,咱們先看看他們的努力。javascript

Vue cli 2.x - 提供開箱即用的配置

在以前一長段時間中,咱們要初始化一個 Vue 項目,通常是使用 vue-cli 提供的 vue init 命令(這也是 Vue cli 的 v2 版本,以後簡稱 Vue cli 2.x)。並且一般一些比較有規模的項目都會使用 vue init webpack my-project 來使用 webpack 模板,那麼上面提到的配置問題就來了。css

爲了解決這個問題, Vue 的作法是提供開箱即用的配置,即經過 vue init 出來的項目,默認生成的巨多的配置文件,截圖以下:html

Vue cli 2 build 目錄

開箱即用是保證了,但一旦要修改,就至關因而進入了一個黑盒,開發者對於一堆文件,一堆 JSON 望洋興嘆。前端

webpack 4 - 極大地簡化配置

webpack 4 推出也有一年左右了,它的核心改動之一是極大地簡化配置。它添加了 mode,把一些顯而易見的配置作成內置的。所以例如 NoEmitOnErrorsPlugin(), UglifyJSPlugin() 等等都沒必要寫了;分包用的 CommonsChunkPlugin() 也濃縮成了一個配置項 optimization.splitChunks,而且已有能適應絕大部分狀況的默認值。vue

聽說 webpack 4 構建出來的代碼的體積還更小了,所以此次升級顯然是必要的。java

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 項目清爽了很多。node

Vue cli 3 目錄

因此如今的問題是什麼?

若是咱們單純開發一個前端 Vue 項目,webpack-dev-server 能幫助咱們啓動一個 nodejs 服務器並支持熱加載,很是好用。可若是咱們要開發的是一個 nodejs + Vue 的全棧項目呢?二者是不可能啓動在同一個端口的。那咱們能作的只是讓 nodejs 啓動在端口 A,讓 Vue (webpack-dev-server) 啓動在端口 B。而若是 Vue 須要發送請求訪問 nodejs 提供的 API 時,還會趕上跨域問題,雖然能夠經過配置 proxy 解決,但依然很是繁瑣。而實質上,這是一整個項目的先後端而已,咱們應該使用一條命令,一個端口來啓動它們。webpack

拋開 Vue,此類需求 webpack 自己實際上是支持的。由於它除了提供 webpack-dev-server 以外,還提供了 webpack-dev-middleware。它以 express middleware 的方式,一樣集成了熱加載的功能。所以若是咱們的 nodejs 使用的是 express 做爲服務框架的話,咱們能夠以 app.use 的方式引入這個中間件,就能夠達成二者的融合了。git

再說回 Vue cli 3。它經過 vue-cli-service 命令,把 webpack 和 webpack-dev-server 包裹起來,這樣用戶就看不到配置文件了,達成了簡潔的目的。不過實質上,配置文件依然存在,只是移動到了 node_modules/@vue/cli-service/webpack.config.js 而已。固然爲了個性化需求,它也支持用戶經過配置對象 (configureWebpack) 或者鏈式調用 (chainWebpack) 兩種間接的方式,但再也不提供直接修改配置文件的方式了。github

然而致命的是,即使它提供了足夠的方式修改配置,但它不能把 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 部分的改造點主要是:

  1. package.json 融合到根目錄(nodejs) 的 package.json 裏面去。這裏主要包括依賴 (dependencydevDependency)以及執行命令(scripts)兩部分。其他的如 browserslist, engine 等 babel 可能用到的字段,由於 nodejs 代碼不須要 babel,因此能夠直接複製過去,不存在融合。

  2. 編寫 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_ENVproduction 來讓 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 種文件的處理方式,它們分別是:

  1. /\.vue$/

    處理 Vue 文件,使用 Vue 專門提供的 vue-loader。這個處理器作的事情就是把 Vue 裏面的 <script><style> 的部分獨立出來,讓它們能夠繼續由下面的 rules 分別處理。不然一個 .vue 文件是不可能進入 .js 或者 .css 的處理流程的。另外若是 <style>lang 屬性,還能夠進入例如 .less, .styl 等其餘處理流程。

    它還須要專門的插件 VueLoaderPlugin(),以後能夠看到,不要漏掉。

  2. /\.js?$/

    表面上是處理後綴爲 .js 的文件,但實質上在這裏也用來處理 Vue 裏面 <script> 的內容。在這裏咱們要作的是使用 babel-loader 對代碼中的高級寫法轉譯爲兼容低版本瀏覽器的寫法。具體轉譯規則使用 .babelrc 文件配置。另外這裏還忽略了 node_modules(由於其餘包在發佈時都已經轉碼過了,不用再處理徒增時間)。不過得確保 node_modules 裏的單體 Vue 文件依然參與轉譯,這也是 Vue 官方文檔 的推薦寫法。

  3. /\.less$/

    個人項目中使用 less 做爲樣式預處理器,所以在每一個 Vue 文件都使用了 <style lang="less">。這樣經過 vue-loader,就能讓這條規則中配置的幾個 loader 來處理 Vue 文件中的樣式了。這幾個 loader 分別作的事情是:

    1. vue-style-loader

      把樣式以 <style> 標籤的形式插入在頁面頭部,只在開發狀態下使用

      它和 style-loader 的差別並不大,但既然 Vue 官方文檔建議使用這個,那咱們就用這個吧。

    2. mini-css-extract-plugin 的 loader

      把樣式抽成一個單獨的 css 文件並在 <head> 標籤中以 <link rel="stylesheet"> 的方式引用,取代原來 webpack 3.x 的 extract-text-webpack-plugin只在生產狀態下使用

      它一樣須要在插件中增長 MiniCssExtractPlugin() 以配合使用。

    3. css-loader

      支持經過隱式的方式加載資源。例如若是在 JS 文件中編寫 import 'style.css',或者在樣式文件中編寫 url('image.png'),通過 css-loader 能夠把 style.cssimage.png 都引入到 webpack 的處理流程中。這樣針對 css 的全部 loader 就能夠處理 style.css,而針對全部圖片的 loader(例如尺寸很小就自動轉爲 base64 的 url-loader)均可以處理 image.png 了。

    4. less-loader

      使用 less 預處理器必須加載的 loader,用以把 less 語法轉化爲普通的 css 語法。

      基本上每一個預處理器都有對應的 loader,例如 stylus-loader, sass-loader 等等,能夠按需使用。

  4. /\.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'),文件會根據路由分割,所以數量會更多)

vue-dist

總共 4 個文件

  1. index.html 存放惟一的 HTML 入口,裏面包含對各 JS, CSS 文件的引用,並定義了容器節點。使用靜態服務器啓動後,因爲 JS 的執行,能夠執行前端渲染。

  2. style.css 存放全部的樣式。這些樣式都是從每一個 Vue 文件的 <style lang="less"> 部分中抽出來合併而成的。

  3. app.[hash].js 存放全部的自定義 JS,即每一個 Vue 文件的 <script> 部分,以及如 app.js, router.js, store.js 的代碼等等。

  4. vendors~app.[hash].js 如上所述,存放全部類庫 JS,如 vue-router, vuex 自己的代碼。

對 nodejs 來講,須要關心的只是這個 index.html 而已,其餘 3 個都會由它負責引入。那麼咱們接下來看看如何改造 nodejs 部分。

改造 nodejs(koa) 部分

koa 部分須要咱們改造的點主要有:

  1. package.json

    nodejs 項目的標配,記錄依賴,腳本,項目信息等等。咱們須要在這裏和 Vue 端的 package.json 進行合併,尤爲是 npm run dev 腳本的合併。

  2. index.js

    nodejs 的代碼入口,經過命令 node index.js 啓動整個項目。在這裏能夠註冊路由規則,註冊中間件,註冊 wdm 等等,絕大部分邏輯都在這裏。

    由於開發環境和生產環境的行爲不盡相同(例如開發環境須要 wdm 而生產環境不須要),所以能夠分爲兩個文件(index.dev.jsindex.prod.js),也能夠在一個文件中經過環境變量判斷,這個因人而異。

    雖然 koa 的路由規則和中間件均可以寫在這裏,但一般只要是略有規模的項目,都會把路由處理和中間件分別獨立成 actionsmiddlewares 目錄分開存放(名字怎麼起看本身喜愛)。配置文件(例如配置啓動端口號)也一般會獨立成 config.js 或者 config 目錄。其餘的例如 util 目錄等也都按需創建。

    咱們須要在這裏統一先後路由,並使用 wdm 等

package.json

在「改造 Vue 部分」的 package.json 中曾經講過,Vue 項目的依賴都直接複製到外層的 package.json 中來,還增長了一條 npm run build 命令。這裏會再列出兩條命令,達成最基本的的需求。

我爲了區分運行環境,把 index.js 拆解爲了 index.dev.jsindex.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 能夠查看這裏

這麼多配置新手看了仍是很懵怎麼辦?

雖然咱們討論了這麼多,但不要懼怕,實際上的重點只有三個,咱們來總結一下:

  1. 咱們須要本身編寫 Vue 的 webpack.config.js,處理 loader, plugins 等等

  2. 咱們須要合併先後端的兩個 package.json,把兩方的依賴合併,並編寫三條腳本 (dev, build, start)

  3. 咱們須要改動 index.js,處理路由順序,並在開發環境調用 webpack-dev-middleware

爲了簡單上手,我把項目中的業務代碼抽離,留下了一個骨架,能夠做爲 Vue + koa 項目的啓動模板,放在 easonyq/vue-nodejs-template。不過我以爲咱們仍是應當掌握配置方法和原理,這樣之後若是技術棧的某一塊發生了變化(例如 webpack 出了 5),咱們也可以本身研究修改,而不是每次都以解決任務爲最優先,能跑起來就無論了。

願咱們你們在前端道路上都能越走越順!

相關文章
相關標籤/搜索