深刻淺出的webpack4構建工具---比mock模擬數據更簡單的方式(二十一)

若是想要了解mock模擬數據的話,請看這篇文章(http://www.javashuo.com/article/p-xqhmaoki-bt.htmljavascript

在實際應用場景中,總感受mock數據比較麻煩,而且在webpack3中mock數據的代碼在正式環境並不能自動移除掉,致使正式環境有mock相對應的代碼,可是在webpack4中,會使用 tree shaking插件會自動移除掉未使用到的代碼的,想要了解tree shaking(http://www.javashuo.com/article/p-fqwhfmgs-bx.html),請看這篇文章。因此爲了兼容webpack版本的話,研究了一種新的方式來模擬後臺接口數據,使用webpack中的 devServer.before這個配置便可,詳細請看以下介紹。
在講解如何模擬數據以前,咱們來看下我目前整個項目架構以下:html

### 目錄結構以下:
demo1                                       # 工程名
|   |--- dist                               # 打包後生成的目錄文件             
|   |--- node_modules                       # 全部的依賴包
|   |--- app
|   | |---index
|   | | |-- views                           # 存放全部vue頁面文件
|   | | | |-- parent.vue                    # 父組件
|   | | | |-- child.vue                     # 子組件
|   | | | |-- index.vue
|   | | |-- components                      # 存放vue公用的組件
|   | | |-- js                              # 存放js文件的
|   | | |-- store                           # store倉庫
|   | | | |--- actions.js
|   | | | |--- mutations.js
|   | | | |--- state.js
|   | | | |--- mutations-types.js
|   | | | |--- index.js
|   | | |-- app.js                          # vue入口配置文件
|   | | |-- router.js                       # 路由配置文件
|   |--- views
|   | |-- index.html                        # html文件
|   |--- json                               # 存放全部模擬數據
|   | |-- parent_getPower.json
|   | |-- parent_reConfig.json
|   | |-- parent_reconlist.json
|   | |-- parent_reGroup.json 
|   |--- mock.js                            # mock 數據的全部調用方法
|   |--- webpack.config.js                  # webpack配置文件 
|   |--- .gitignore  
|   |--- README.md
|   |--- package.json
|   |--- .babelrc                           # babel轉碼文件

項目的結構如上所示:其中 json 文件夾內會存放全部模擬的數據,好比和開發後臺約定好的數據,我能夠直接把數據複製到json文件內,好比咱們簡單的看下 parent_reConfig.json 數據代碼以下(假如開發接口返回的數據是這樣的):vue

{
  "data": [{
      "bTableName": "reconfig",
      "businessCode": "reconfig",
      "businessImportImpl": "reconfig",
      "businessImportMethod": "reconfig",
      "businessName": "reconfig"
    }
  ],
  "code": 0
}

其餘的json文件也是相似的數據,這裏不一一貼代碼哦,有興趣的話,能夠到下面的github上查看demo。java

json文件命名方式:好比我上面json下的叫 parent_reConfig.json, 由於vue頁面叫 parent.vue, 因此前綴就是頁面的名稱,而後下劃線(_) + reConfig + 'json', 其中reConfig 是接口的最後一個名字,這樣命名的話,我一眼就能夠知道是那個頁面下的接口,接口是作什麼使用的。方便之後接口不少更容易區分。node

2. 在項目的根目錄下 mock.js 代碼是以下所示:webpack

const getPower = require('./json/parent_getPower.json');
const reConfig = require('./json/parent_reConfig.json');
const reConList = require('./json/parent_reconlist.json');
const reGroup = require('./json/parent_reGroup.json');

function Mock(app) {
  app.get('/xxxx/yyy', function(req, res) {
    console.log('getPower111');
    res.json(getPower);
  });
  app.post('/reconfig', function(req, res) {
    console.log('reConfig111');
    res.json(reConfig);
  });
  app.post('/conlist', function(req, res) {
    console.log('reConList111');
    res.json(reConList);
  });
  app.post('/regroup', function(req, res) {
    console.log('reGroup111');
    res.json(reGroup);
  });
}

module.exports = Mock;

如上代碼首先是把 json文件夾下的全部的json文件 require進來,而後定義一個函數,裏面寫全部的(get或post)方法,而後使用 res.json 方式就能夠把上面的json數據模擬返回回來。如上的app參數是從webpack.config.js 配置傳進來的。git

3. webpack.config.js 配置方式以下:github

// 引入mock.js
const Mock = require('./mock.js');

module.exports = {
  devServer: {
    port: 8082,
    host: '0.0.0.0',
    headers: {
      'X-foo': '112233'
    },
    inline: true,
    overlay: true,
    stats: 'errors-only',
    before: function(app) {
      console.log(app);
      if (process.env.NODE_ENV === 'mock') {
        Mock(app);
      }
    }
  },
  plugins: [
    // 設置環境變量信息
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV)
      }
    })
  ]
}

如上配置代碼,首先引入 mock.js 進來,上面的mock.js對外返回函數,所以在devServer.before中配置調用下Mock函數,傳入參數是app,而且環境變量也判斷了下,若是是 mock環境,就執行mock函數代碼的數據,不然不是mock命令的話,就不會執行mock數據,而是執行真正環境的數據。下面咱們來看下 上面 before函數打印的app是什麼東西,以下所示:web

{ [EventEmitter: app]
  domain: undefined,
  _events: { mount: [Function: onmount] },
  _maxListeners: undefined,
  setMaxListeners: [Function: setMaxListeners],
  getMaxListeners: [Function: getMaxListeners],
  emit: [Function: emit],
  addListener: [Function: addListener],
  on: [Function: addListener],
  prependListener: [Function: prependListener],
  once: [Function: once],
  prependOnceListener: [Function: prependOnceListener],
  removeListener: [Function: removeListener],
  removeAllListeners: [Function: removeAllListeners],
  listeners: [Function: listeners],
  listenerCount: [Function: listenerCount],
  eventNames: [Function: eventNames],
  init: [Function: init],
  defaultConfiguration: [Function: defaultConfiguration],
  lazyrouter: [Function: lazyrouter],
  handle: [Function: handle],
  use: [Function: use],
  route: [Function: route],
  engine: [Function: engine],
  param: [Function: param],
  set: [Function: set],
  path: [Function: path],
  enabled: [Function: enabled],
  disabled: [Function: disabled],
  enable: [Function: enable],
  disable: [Function: disable],
  acl: [Function],
  bind: [Function],
  checkout: [Function],
  connect: [Function],
  copy: [Function],
  delete: [Function],
  get: [Function],
  head: [Function],
  link: [Function],
  lock: [Function],
  'm-search': [Function],
  merge: [Function],
  mkactivity: [Function],
  mkcalendar: [Function],
  mkcol: [Function],
  move: [Function],
  notify: [Function],
  options: [Function],
  patch: [Function],
  post: [Function],
  propfind: [Function],
  proppatch: [Function],
  purge: [Function],
  put: [Function],
  rebind: [Function],
  report: [Function],
  search: [Function],
  subscribe: [Function],
  trace: [Function],
  unbind: [Function],
  unlink: [Function],
  unlock: [Function],
  unsubscribe: [Function],
  all: [Function: all],
  del: [Function],
  render: [Function: render],
  listen: [Function: listen],
  request: IncomingMessage { app: [Circular] },
  response: ServerResponse { app: [Circular] },
  cache: {},
  engines: {},
  settings: {},
  _eventsCount: 1,
  locals: 
   { settings: {}},
  mountpath: '/',
  _router: {} 
}

更多關於 devServer.before能夠看官網(https://webpack.js.org/configuration/dev-server/#devserver-before)。vuex

4. package.json 配置以下:

{
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --progress --colors --devtool cheap-module-eval-source-map --hot --inline",
    "build": "cross-env NODE_ENV=production webpack --progress --colors --devtool cheap-module-source-map",
    "build:dll": "webpack --config webpack.dll.config.js",
    "start": "webpack-dev-server --progress --colors --devtool cheap-module-eval-source-map --hot --inline",
    "mock": "cross-env NODE_ENV=mock npm run start"
  },
}

5. app/index/views/parent.vue 代碼以下所示:

<template>
  <div>
  </div>
</template>
<script type="text/javascript">
  import { mapActions } from 'vuex';
  export default {
    data() {
      return {
      }
    },
    created() {
      this.testMock();
    },
    methods: {
      testMock() {
        const obj = {
          'xx': 11
        };
        // 請求的地址是 '//xxx.abc.com/xxxx/yyy'
        Promise.all([this.commonActionGet(['getPower', obj])]).then((res) => {
          console.log('getPower');
          console.log(typeof res);
          console.log(res);
        });

        Promise.all([this.commonActionPost(['reConfig', obj])]).then((res) => {
          console.log('reConfig');
          console.log(res);
        });

        Promise.all([this.commonActionPost(['reConList', obj])]).then((res) => {
          console.log('reConList');
          console.log(res);
        });

        Promise.all([this.commonActionPost(['reGroup', obj])]).then((res) => {
          console.log('reGroup');
          console.log(res);
        });
      },
      ...mapActions(['commonActionGet', 'commonActionGetJSON', 'commonActionPost', 'commonActionPostJSON'])
    },
    mounted() {

    }
  }
</script>

如上代碼,當我執行打包命令 npm run mock 時,就會調用webpack中的 devServer.before函數,該函數會判斷當前的環境是不是mock命令,若是是mock命令就執行 mock.js中的Mock函數,而後會請求數據。

注意:上面的請求數據是:'//0.0.0.0:8082/reconfig' 這樣的,這樣就能夠把 json/parent_reConfig.json請求的數據返回回來,可是咱們真正的接口的前綴多是 '//xxx.abc.com', 所以咱們在配置全部的接口名稱的時候,接口域名的前綴咱們能夠定義一個變量,而後傳遞進去。好比我下面是這樣定義的:

// const prefix = '//xxx.abc.com'; // 真正的域名接口先註釋掉
const prefix = '//0.0.0.0:8082';

咱們能夠簡單的判斷下:

let prefix;
if (process.env.NODE_ENV === 'mock') {
  prefix = '//0.0.0.0:8082'; // 測試域名
} else {
  prefix = '//xxx.abc.com'; // 正式域名
}

const url = prefix + '/reconfig';

相似上面這中形式,所以當咱們在頁面上請求 this.$http.get(url);的時候,實際上在mock數據下請求的是 '//0.0.0.0:8082/reconfig' 這樣的,所以會直接被 devServer.before中攔截到,所以會返回咱們的模擬上的數據,可是在咱們使用 npm run dev 或 npm run build 的時候,咱們須要把 //xxx.abc.com 這個真正的接口域名前綴打開,'//0.0.0.0:8082' 須要被註釋掉。就能夠了,其餘的vue中的代碼不須要作任何改動,之前該怎麼寫,如今也仍是就那麼寫。

查看github上的代碼

相關文章
相關標籤/搜索