1. 程式人生 > >vue-cli 專案 webpack.prod.conf.js 檔案程式碼註釋

vue-cli 專案 webpack.prod.conf.js 檔案程式碼註釋

// 生產模式配置檔案 webpack.prod.conf.js
// 註釋參考 https://www.cnblogs.com/ye-hcj/p/7082620.html 和 https://yq.aliyun.com/articles/609824 和 https://segmentfault.com/a/1190000012472099

'use strict'
// 下面是引入nodejs的路徑模組
const path = require('path')
// 下面是utils工具配置檔案,主要用來處理css類檔案的loader
const utils = require('./utils')
// 下面引入webpack,來使用webpack內建外掛
const webpack = require('webpack')
// 下面是config目錄下的index.js配置檔案,主要用來定義了生產和開發環境的相關基礎配置
const config = require('../config')
// 下面是webpack的merger外掛,主要用來處理配置物件合併的,可以將一個大的配置物件拆分成幾個小的,合併,相同的項將覆蓋
const merge = require('webpack-merge')
// 引入開發環境和生產環境公共的配置
const baseWebpackConfig = require('./webpack.base.conf')
// 引入copy-webpack-plugin模組 這個模組主要用於在webpack中拷貝檔案和資料夾
const CopyWebpackPlugin = require('copy-webpack-plugin')
// 引入html-webpack-plugin外掛 這個外掛主要是用於基於模版生成html檔案的
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 引入extract-text-webpack-plugin外掛 這個外掛主要是用於將入口中所有的chunk,移到獨立的分離的css檔案中
const ExtractTextPlugin = require('extract-text-webpack-plugin')
// 引入optimize-css-assets-webpack-plugin外掛 這個外掛主要是用於壓縮css模組的
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
// 引入uglifyjs-webpack-plugin外掛 這個外掛主要是用於壓縮js檔案的
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

// 引入用於生產環境的一些基本變數
const env = require('../config/prod.env')

// 合併公共配置和生產環境獨有的配置並返回一個用於生產環境的webpack配置檔案
const webpackConfig = merge(baseWebpackConfig, {
  // 用於生產環境的一些loader配置
  module: {
    // 樣式檔案的處理規則,對css/sass/scss等不同內容使用相應的styleLoaders
    // 由utils配置出各種型別的預處理語言所需要使用的loader,例如sass需要使用sass-loader
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,
      // 在生產環境中使用extract選項,這樣就會把thunk中的css程式碼抽離到一份獨立的css檔案中去
      extract: true,
      usePostCSS: true
    })
  },
  // 配置生產環境中使用的source map的形式。在這裡,生產環境使用的是#source map的形式
  devtool: config.build.productionSourceMap ? config.build.devtool : false,
  output: {
    // build所產生的檔案的存放的資料夾地址
    path: config.build.assetsRoot,
    // build之後的檔案的名稱
    // 這裡[name]和[chunkhash]都是佔位符
    // 其中[name]指的就是模組的名稱
    // [chunkhash]chunk內容的hash字串,長度為20
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    // [id]也是一個佔位符,表示的是模組識別符號(module identifier)
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  },
  plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    // 下面是利用DefinePlugin外掛,定義process.env環境變數為env
    new webpack.DefinePlugin({
      'process.env': env
    }),
    // 壓縮javascript的外掛
    new UglifyJsPlugin({
      uglifyOptions: {
        compress: {
          // 在刪除未使用的變數等時,顯示警告資訊,預設就是false
          warnings: false // 禁止顯示壓縮時候的警告資訊
        }
      },
      // 使用 source map 將錯誤資訊的位置對映到模組(這會減慢編譯的速度)
      // 而且這裡不能使用cheap-source-map
      sourceMap: config.build.productionSourceMap,
      // 使用多程序並行執行和檔案快取來提高構建速度
      parallel: true
    }),
    // extract css into its own file
    // 提取css檔案到一個獨立的檔案中去
    new ExtractTextPlugin({
      // 提取之後css檔案存放的地方
      // 其中[name]和[contenthash]都是佔位符
      // [name]就是指模組的名稱
      // [contenthash]根據提取檔案的內容生成的 hash
      filename: utils.assetsPath('css/[name].[contenthash].css'),
      // 從所有額外的 chunk(additional chunk) 提取css內容
      // (預設情況下,它僅從初始chunk(initial chunk) 中提取)
      // 當使用 CommonsChunkPlugin 並且在公共 chunk 中有提取的 chunk(來自ExtractTextPlugin.extract)時
      // 這個選項需要設定為true
    }),
    // Compress extracted CSS. We are using this plugin so that possible
    // duplicated CSS from different components can be deduped.
    // 使用這個外掛壓縮css,主要是因為,對於不同元件中相同的css可以剔除一部分
    new OptimizeCSSPlugin({
      // 這個選項的所有配置都會傳遞給cssProcessor
      // cssProcessor使用這些選項決定壓縮的行為
      cssProcessorOptions: config.build.productionSourceMap
        // safe我不是很明白是什麼意思???求留言告知。。。
        ? { safe: true, map: { inline: false } }
        : { safe: true }
    }),
    // generate dist index.html with correct asset hash for caching.
    // you can customize output by editing /index.html
    // see https://github.com/ampedandwired/html-webpack-plugin
    // 建立一個html檔案
    new HtmlWebpackPlugin({
      // 生成的檔案的名稱
      filename: config.build.index,
      // 使用的模板的名稱
      template: 'index.html',
      // 把script和link標籤放在body底部
      inject: true,
      // 配置html的壓縮行為
      minify: {
        removeComments: true, // 移除註釋
        collapseWhitespace: true, // 去除空格和換行
        removeAttributeQuotes: true // 儘可能移除屬性中的引號和空屬性
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference
      },
      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
      // 控制chunks的順序,這裡表示按照依賴關係進行排序
      // 也可以是一個函式,自己定義排序規則
      chunksSortMode: 'dependency'
    }),
    // keep module.id stable when vendor modules does not change
    // 根據模組的相對路徑生成一個四位數的hash作為模組id
    new webpack.HashedModuleIdsPlugin(),
    // enable scope hoisting
    // webpack2處理過的每一個模組都會使用一個函式進行包裹
    // 這樣會帶來一個問題:降低瀏覽器中JS執行效率,這主要是閉包函式降低了JS引擎解析速度。
    // webpack3中,通過下面這個外掛就能夠將一些有聯絡的模組,
    // 放到一個閉包函式裡面去,通過減少閉包函式數量從而加快JS的執行速度。
    new webpack.optimize.ModuleConcatenationPlugin(),
    // split vendor js into its own file
    // 這個外掛用於提取多入口chunk的公共模組
    // 通過將公共模組提取出來之後,最終合成的檔案能夠在最開始的時候載入一次
    // 然後快取起來供後續使用,這會帶來速度上的提升。
    new webpack.optimize.CommonsChunkPlugin({
      // 這是 common chunk 的名稱
      name: 'vendor',
      minChunks (module) {
        // any required modules inside node_modules are extracted to vendor
        // 把所有從mnode_modules中引入的檔案提取到vendor中
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
    }),
    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    // 為了將專案中的第三方依賴程式碼抽離出來,官方文件上推薦使用這個外掛,當我們在專案裡實際使用之後,
    // 發現一旦更改了 app.js 內的程式碼,vendor.js 的 hash 也會改變,那麼下次上線時,
    // 使用者仍然需要重新下載 vendor.js 與 app.js——這樣就失去了快取的意義了。所以第二次new就是解決這個問題的
    // 參考:https://github.com/DDFE/DDFE-blog/issues/10
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      minChunks: Infinity
    }),
    // This instance extracts shared chunks from code splitted chunks and bundles them
    // in a separate chunk, similar to the vendor chunk
    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
    new webpack.optimize.CommonsChunkPlugin({
      name: 'app',
      async: 'vendor-async',
      children: true,
      minChunks: 3
    }),

    // copy custom static assets
    // 拷貝靜態資源到build資料夾中
    new CopyWebpackPlugin([
      {
        // 定義要拷貝的資源的源目錄
        from: path.resolve(__dirname, '../static'),
        // 定義要拷貝的資源的目標目錄
        to: config.build.assetsSubDirectory,
        // 忽略拷貝指定的檔案,可以使用模糊匹配
        ignore: ['.*']
      }
    ])
  ]
})

if (config.build.productionGzip) {
  // 如果開啟了生產環境的gzip
  const CompressionWebpackPlugin = require('compression-webpack-plugin')

  webpackConfig.plugins.push(
    new CompressionWebpackPlugin({
      // 目標資源的名稱
      // [path]會被替換成原資源路徑
      // [query]會被替換成原查詢字串
      asset: '[path].gz[query]',
      // gzip演算法
      // 這個選項可以配置成zlib模組中的各個演算法
      // 也可以是(buffer, cb) => cb(buffer)
      algorithm: 'gzip',
      // 處理所有匹配此正則表示式的資源
      test: new RegExp(
        '\\.(' +
        config.build.productionGzipExtensions.join('|') +
        ')$'
      ),
      // 只處理比這個值大的資源
      threshold: 10240,
      // 只有壓縮率比這個值小的資源才會被處理
      minRatio: 0.8
    })
  )
}

// 如果啟動了report,則通過外掛給出webpack構建打包後的產品檔案分析報告
if (config.build.bundleAnalyzerReport) {
  // 如果需要生成一分bundle報告,則需要使用下面的這個外掛
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig