在webpack-dev-server內新增mock server

Harlan2016發表於2019-03-04

在開發基於api互動、前後端分離的網頁應用時,經常會遇到幾個問題:

  • 前端頁面已經編排好了,但是後臺介面還沒準備好,或者是突然出現Bug,這樣沒辦法進行對接測試。
  • 我們希望伺服器返回特定型別的資料,以測試某頁面在特定條件下是否存在問題,但作為前端我們一般不會接觸到後端程式碼和資料庫,每次都找後端新增模擬資料又很麻煩。

為解決這兩個問題,最簡單的解決辦法就是搭建一個mock server,專門返回需要的模擬資料。

webpack-dev-server是我們開發vue、react時必備的工具,通過webpack-dev-serverbefore鉤子,可以在webpack-dev-server上新增我們需要的mock server功能,而不需要另行搭建伺服器。

在一通搜尋後,我找到了這篇文章和這個webpack中介軟體webpack-api-mocker,只需要少許修改就能webpack-dev-server當做mock server來用,並且對同一URL下的GETPOSTPATCH等不同的HTTP METHOD做分別處理,支援熱切換。

使用方法很簡單,在webpack.dev.conf.jsdevServer中新增新鉤子before,將所有請求交由apiMocker處理,然後當需要使用模擬資料時,只需要將請求的URL改為webpack伺服器上既可。

npm install webpack-api-mocker --save-dev
複製程式碼
const apiMocker = require(`webpack-api-mocker`)
config = {
  ...
  devServer: {
    before(app) { 
      apiMocker(app, path.resolve(`mock/api.js`))
    }
  }
  ...
}
複製程式碼

api.js

const fs = require(`fs`);

function fromJSONFile(filename) {
    return (req, res) => {
        const data = fs.readFileSync(`mock/data/${filename}.json`).toString();
        const json = JSON.parse(data);
        return res.json(json);
    };
}
const proxy = {
    `GET /app/user/profile`: fromJSONFile(`profile`),
};
module.exports = proxy;
複製程式碼

修改URL

axios.get(`user/info`).then(...)
// 修改URL,加上字首
axios.get(`http://127.0.0.1:8080/` + `user/info`).then(...)
複製程式碼

更進一步

經過上面的步驟,mock server已經基本能執行了,但還是有一些不友好。每次需要使用模擬資料時,都要修改專案原始碼,改寫請求的URL,在測試完畢後還得再改回來,如果該請求在原始碼內有多處地方使用,那改動的地方就多了,比較麻煩。我們可以再進行一些改進。

改進的思路就是開啟mock server後,將所有對api伺服器的請求都傳送到webpack server上,webpack server攔截並處理所有已定義有模擬資料的介面請求,而未定義的介面請求則轉發到api伺服器上。

上面說的那個專案作者已經合併了我的PR,下面這段可以不用理了,繼續用上面那個webpack-api-mocker

首先,我們要對前面用到的那個中介軟體webpack-api-mocker進行改進,修改後的程式碼在我的github上,外掛主要就一個檔案index.js,複製下來直接使用即可。修改了那些內容可以看commit log

然後新增一個新的npm命令dev-mock,定義一個環境變數MOCK來控制是否開啟mock server:

"script": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+   "dev-mock": "MOCK=true webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
}
複製程式碼

webpack config中當MOCK變數存在時才開啟mock server

config = {
  ...
  devServer: {
    if (process.env.MOCK) {
        before(app) {
          apiMocker(app, path.resolve(`mock/api.js`), {
            proxy: {
              `/app//*`: `http://api.leaderlegend.com`,
            }
          });
        }
    }
  }
  ...
}
複製程式碼

為了在程式碼中使用環境變數MOCK,我們要在webpack config內傳遞該值。如何傳值參考StackOverflow上的這個回答Passing environment-dependent variables in webpack

config = {
    ...
    devServer: ...
    plugins: [
        new webpack.DefinePlugin({
            `process.env`: {
                NODE_ENV: process.env.NODE_ENV,
                MOCK: process.env.MOCK,
            }
        }),
        ...
    ]
    ...
}
複製程式碼

通過判斷環境變數MOCK來確定api伺服器地址,這裡最好保持第一個path相同以更方便轉發

const BASE_URL = process.env.MOCK ? `http://127.0.0.1:8080/app/` : `http://api.harlanluo.com/app/`;
複製程式碼

到此為止已經全部完成,需要使用模擬資料時,使用npm run dev-mock命令來執行,,不需要時則使用npm run dev,無需對專案原始碼對做任何修改。

相關文章