1. 程式人生 > >vue:一群java後臺死在配置上

vue:一群java後臺死在配置上

一、檔案結構

本文主要分析開發(dev)和構建(build)兩個過程涉及到的檔案,故下面檔案結構僅列出相應的內容。

├─build
│   ├─build.js
│   ├─check-versions.js
│   ├─dev-client.js
│   ├─dev-server.js
│   ├─utils.js
│   ├─vue-loader.conf.js
│   ├─webpack.base.conf.js
│   ├─webpack.dev.conf.js
│   ├─webpack.prod.conf.js
│   └─webpack.test.conf.js
├─config
│   ├─dev.env
.js │ ├─index.js │ ├─prod.env.js │ └─test.env.js ├─... └─package.json
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

二、指令分析

首先看package.json裡面的scripts欄位,

"scripts": {
  "dev": "node build/dev-server.js",
  "build": "node build/build.js",
  "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run"
, "e2e": "node test/e2e/runner.js", "test": "npm run unit && npm run e2e", "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs" }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

測試的東西先不看,直接看”dev”和”build”。執行”npm run dev”的時候執行的是build/dev-server.js檔案,執行”npm run build”的時候執行的是build/build.js檔案,我們可以從這兩個檔案開始進行程式碼閱讀分析。

三、build資料夾分析

build/dev-server.js

首先來看執行”npm run dev”時候最先執行的build/dev-server.js檔案。該檔案主要完成下面幾件事情:

  1. 檢查node和npm的版本
  2. 引入相關外掛和配置
  3. 建立express伺服器和webpack編譯器
  4. 配置開發中間件(webpack-dev-middleware)和熱過載中介軟體(webpack-hot-middleware)
  5. 掛載代理服務和中介軟體
  6. 配置靜態資源
  7. 啟動伺服器監聽特定埠(8080)
  8. 自動開啟瀏覽器並開啟特定網址(localhost:8080)

說明: express伺服器提供靜態檔案服務,不過它還使用了http-proxy-middleware,一個http請求代理的中介軟體。前端開發過程中需要使用到後臺的API的話,可以通過配置proxyTable來將相應的後臺請求代理到專用的API伺服器。

詳情請看程式碼註釋:

// 檢查NodeJS和npm的版本
require('./check-versions')()

// 獲取配置
var config = require('../config')
// 如果Node的環境變數中沒有設定當前的環境(NODE_ENV),則使用config中的配置作為當前的環境
if (!process.env.NODE_ENV) {
  process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
}

// 一個可以呼叫預設軟體開啟網址、圖片、檔案等內容的外掛
// 這裡用它來呼叫預設瀏覽器開啟dev-server監聽的埠,例如:localhost:8080
var opn = require('opn')
var path = require('path')
var express = require('express')
var webpack = require('webpack')

// 一個express中介軟體,用於將http請求代理到其他伺服器
// 例:localhost:8080/api/xxx  -->  localhost:3000/api/xxx
// 這裡使用該外掛可以將前端開發中涉及到的請求代理到API伺服器上,方便與伺服器對接
var proxyMiddleware = require('http-proxy-middleware')

// 根據 Node 環境來引入相應的 webpack 配置
var webpackConfig = process.env.NODE_ENV === 'testing'
  ? require('./webpack.prod.conf')
  : require('./webpack.dev.conf')

// dev-server 監聽的埠,預設為config.dev.port設定的埠,即8080
var port = process.env.PORT || config.dev.port

// 用於判斷是否要自動開啟瀏覽器的布林變數,當配置檔案中沒有設定自動開啟瀏覽器的時候其值為 false
var autoOpenBrowser = !!config.dev.autoOpenBrowser

// 定義 HTTP 代理表,代理到 API 伺服器
var proxyTable = config.dev.proxyTable

// 建立1個 express 例項
var app = express()

// 根據webpack配置檔案建立Compiler物件
var compiler = webpack(webpackConfig)

// webpack-dev-middleware使用compiler物件來對相應的檔案進行編譯和繫結
// 編譯繫結後將得到的產物存放在記憶體中而沒有寫進磁碟
// 將這個中介軟體交給express使用之後即可訪問這些編譯後的產品檔案
var devMiddleware = require('webpack-dev-middleware')(compiler, {
  publicPath: webpackConfig.output.publicPath,
  quiet: true
})

// webpack-hot-middleware,用於實現熱過載功能的中介軟體
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
  log: () => {}
})

// 當html-webpack-plugin提交之後通過熱過載中介軟體釋出過載動作使得頁面過載
compiler.plugin('compilation', function (compilation) {
  compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
    hotMiddleware.publish({ action: 'reload' })
    cb()
  })
})

// 將 proxyTable 中的代理請求配置掛在到express伺服器上
Object.keys(proxyTable).forEach(function (context) {
  var options = proxyTable[context]
  // 格式化options,例如將'www.example.com'變成{ target: 'www.example.com' }
  if (typeof options === 'string') {
    options = { target: options }
  }
  app.use(proxyMiddleware(options.filter || context, options))
})

// handle fallback for HTML5 history API
// 重定向不存在的URL,常用於SPA
app.use(require('connect-history-api-fallback')())

// serve webpack bundle output
// 使用webpack開發中間件
// 即將webpack編譯後輸出到記憶體中的檔案資源掛到express伺服器上
app.use(devMiddleware)

// enable hot-reload and state-preserving
// compilation error display
// 將熱過載中介軟體掛在到express伺服器上
app.use(hotMiddleware)

// serve pure static assets
// 靜態資源的路徑
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)

// 將靜態資源掛到express伺服器上
app.use(staticPath, express.static('./static'))

// 應用的地址資訊,例如:http://localhost:8080
var uri = 'http://localhost:' + port

// webpack開發中間件合法(valid)之後輸出提示語到控制檯,表明伺服器已啟動
devMiddleware.waitUntilValid(function () {
  console.log('> Listening at ' + uri + '\n')
})

// 啟動express伺服器並監聽相應的埠(8080)
module.exports = app.listen(port, function (err) {
  if (err) {
    console.log(err)
    return
  }

  // when env is testing, don't need open it
  // 如果符合自動開啟瀏覽器的條件,則通過opn外掛呼叫系統預設瀏覽器開啟對應的地址uri
  if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
    opn(uri)
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115

build/webpack.base.conf.js

從程式碼中看到,dev-server使用的webpack配置來自build/webpack.dev.conf.js檔案(測試環境下使用的是build/webpack.prod.conf.js,這裡暫時不考慮測試環境)。而build/webpack.dev.conf.js中又引用了webpack.base.conf.js,所以這裡我先分析webpack.base.conf.js。

webpack.base.conf.js主要完成了下面這些事情:

  1. 配置webpack編譯入口
  2. 配置webpack輸出路徑和命名規則
  3. 配置模組resolve規則
  4. 配置不同型別模組的處理規則

說明: 這個配置裡面只配置了.js、.vue、圖片、字型等幾類檔案的處理規則,如果需要處理其他檔案可以在module.rules裡面配置。

具體請看程式碼註釋:

var path = require('path')
var utils = require('./utils')
var config = require('../config')
var vueLoaderConfig = require('./vue-loader.conf')

// 給出正確的絕對路徑
function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  // 配置webpack編譯入口
  entry: {
    app: './src/main.js'
  },

  // 配置webpack輸出路徑和命名規則
  output: {
    // webpack輸出的目標資料夾路徑(例如:/dist)
    path: config.build.assetsRoot,
    // webpack輸出bundle檔案命名格式
    filename: '[name].js',
    // webpack編譯輸出的釋出路徑
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },

  // 配置模組resolve的規則
  resolve: {
    // 自動resolve的副檔名
    extensions: ['.js', '.vue', '.json'],
    // resolve模組的時候要搜尋的資料夾
    modules: [
      resolve('src'),
      resolve('node_modules')
    ],
    // 建立路徑別名,有了別名之後引用模組更方便,例如
    // import Vue from 'vue/dist/vue.common.js'可以寫成 import Vue from 'vue'
    alias: {
      'vue$': 'vue/dist/vue.common.js',
      'src': resolve('src'),
      'assets': resolve('src/assets'),
      'components': resolve('src/components')
    }
  },

  // 配置不同型別模組的處理規則
  module: {
    rules: [
      {// 對src和test資料夾下的.js和.vue檔案使用eslint-loader
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: "pre",
        include: [resolve('src'), resolve('test')],
        options: {
          formatter: require('eslint-friendly-formatter')
        }
      },
      {// 對所有.vue檔案使用vue-loader
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {// 對src和test資料夾下的.js檔案使用babel-loader
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test')]
      },
      {// 對圖片資原始檔使用url-loader,query.name指明瞭輸出的命名規則
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        query: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {// 對字型資原始檔使用url-loader,query.name指明瞭輸出的命名規則
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        query: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65<