vue-cli配置文件详解

该webpack版本号为3.6.0  

  这段时间以来,项目一直都是用Vue全家桶及vue-cli,于是便把vue-cli配置文件给整理了以下,希望对大家能有所帮助。

一:文件的配置结构如下

├─build
│ ├─build.js
│ ├─check-versions.js
│ ├─logo.png
│ ├─utils.js
│ ├─vue-loader.conf.js
│ ├─webpack.base.conf.js
│ ├─webpack.dev.conf.js
│ ├─webpack.prod.conf.js
├─config
│ ├─dev.env.js
│ ├─index.js
│ ├─prod.env.js
├─…
└─package.json

二:文章内容

  文章主要对生产环境和开发环境以及打包所相关的文件进行分析。
  首先看package.json里面的scripts字段。

  "scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "build": "node build/build.js"
  },

   npm run dev 这里默认执行的是开发环境。
开发环境和生产环境区别
   开发环境(development)和生产环境(production)的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时重新加载(live reloading)或热模块替换(hot module replacement)能力的 source map 和 localhost server。而在生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。

三:build文件夹分析

3.1 build/webpack.dev.conf.js
  当执行npm run dev时,我们执行的就是该js文件,该文件主要完成以下任务:
  1.引入相关插件和配置
  2.生成处理各种样式的规则
  3.配置开发环境,如热更新、监听端口号,是否自动打开浏览器等都在webpack中的devServer中配置完成
  4.寻找可利用的端口和添加显示程序编译运行时的错误信息。
  文件内容如下(一些插件和语句的具体作用见注释):

'use strict'
const utils = require('./utils')
// utils提供工具函数,包括生成处理各种样式语言的loader,获取资源文件存放路径的工具函数。 
const webpack = require('webpack')
// 引入webpack模块
const config = require('../config')
// 默认是index文件
const merge = require('webpack-merge')
// 将基础配置和开发环境配置或者生产环境配置合并在一起的包管理
const baseWebpackConfig = require('./webpack.base.conf')
// 引入基本webpack基本配置
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 文件名及时更改,自动打包并且生成响应的文件在index.html里面
// 传送门:https://webpack.js.org/plugins/html-webpack-plugin/#src/components/Sidebar/Sidebar.jsx
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
// Friendly-errors-webpack-plugin可识别某些类型的webpack错误并清理,汇总和优先化它们以提供更好的开发者体验。
// 传送门:http://npm.taobao.org/package/friendly-errors-webpack-plugin
const portfinder = require('portfinder')
// 查看空闲端口位置,默认情况下搜索8000这个端口,
// 传送门:https://www.npmjs.com/package/portfinder
const HOST = process.env.HOST
//processs为node的一个全局对象获取当前程序的环境变量,即host,
// 传送门:http://javascript.ruanyifeng.com/nodejs/process.html#toc5
const PORT = process.env.PORT && Number(process.env.PORT) //
//processs为node的一个全局对象获取当前程序的环境变量,即host,
// 传送门:http://javascript.ruanyifeng.com/nodejs/process.html#toc5
const devWebpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
    //自动生成了css,postcss,less等规则,并进行模块转换,转换成webpack可识别的文件,进行解析转换
  },
  devtool: config.dev.devtool,
  // 增加调试信息
  // 传送门:https://doc.webpack-china.org/configuration/devtool
  devServer: {
    clientLogLevel: 'none',
    // 在开发工具(DevTools)的控制台将显示消息【如:在重新加载之前,在一个错误之前,或者模块热替换(HMR)启动时,这可能显示得很繁琐】
    // 传送门:https://doc.webpack-china.org/configuration/dev-server/#devserver-clientloglevel
    historyApiFallback: true,
    // 当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 index.html。
    // 传送门:https://doc.webpack-china.org/configuration/dev-server/#devserver-historyapifallback
    hot: true,
    // 启动模块热更新特性
    // 传送门:https://doc.webpack-china.org/configuration/dev-server/#devserver-hot
    compress: true,
    // 一切服务都启动用gzip方式进行压缩代码
    // 传送门:https://doc.webpack-china.org/configuration/dev-server/#devserver-compress
    host: HOST || config.dev.host,
    // 指定使用一个host,默认是localhost,获取HOST地址,该文件定义或config中index里的dev配置里获取
    // 传送门:https://doc.webpack-china.org/configuration/dev-server/#devserver-host
    port: PORT || config.dev.port,
    // 指定要监听的端口号
    // 传送门:https://doc.webpack-china.org/configuration/dev-server/#devserver-port
    open: config.dev.autoOpenBrowser,
    // 发开服务器是否自动代开默认浏览器
    // 传送门:https://doc.webpack-china.org/configuration/dev-server/#devserver-open
    overlay: config.dev.errorOverlay
      ? { warnings: false, errors: true }
      : false,
    // 当出现编译器错误或警告时,在浏览器中显示全屏叠加,覆盖到浏览器的项目页面的上方。{warning:false,errors:true}这个选项为 显示错误和警告
    // 传送门:https://doc.webpack-china.org/configuration/dev-server/#devserver-overlay
    publicPath: config.dev.assetsPublicPath,
    // 服务器假设运行在http://localhost:8080并且output.filename被设置为bundle.js默认。publicPath是"/",所以你的包(束)通过可以http://localhost:8080/bundle.js访问。
    // 比如将config中的index.js dev对象的中的assertsPublicPath设置为"/asserts/"那么文件打开后将通过http://localhost:8080/asserts/来进行访问
    // 传送门:https://doc.webpack-china.org/configuration/dev-server/#devserver-publicpath-
    proxy: config.dev.proxyTable,
    // 如果你有单独的后端开发服务器API,并且希望在同域名下发送API请求,那么代理某些URL将很有用.简称就是API代理,中间件  需引入 http-proxy-middleware
    // 传送门:https://doc.webpack-china.org/configuration/dev-server/#devserver-proxy
    quiet: false, // necessary for FriendlyErrorsPlugin
    // 启用quiet后,除了初始启动信息之外的任何内容都不会被打印到控制台。这也意味着来自的WebPack的错误或警告在控制台不可见。
    // 传送门:https://doc.webpack-china.org/configuration/dev-server/#devserver-quiet-
    watchOptions: {
      poll: config.dev.poll,
    }
    // webpack使用文件系统(file system)获取文件改动的通知
    // 传送门:https://doc.webpack-china.org/configuration/dev-server/#devserver-watchoptions-
  },

  plugins: [
    new webpack.DefinePlugin({
      'process.env': require('../config/dev.env')
    }),
    // 将DefinePlugin允许您创建可在配置全局常量的编译时间。这对于允许开发构建和发布构建之间的不同行为是有用的
    // 传送门:https://webpack.js.org/plugins/define-plugin/#src/components/Sidebar/Sidebar.jsx
    new webpack.HotModuleReplacementPlugin(),
    // 永远不能用在生产模式,模块热更新,修改文件的内容,允许在运行时更新各种模块,而无需进行完全刷新。
    // 传送门:https://doc.webpack-china.org/guides/hot-module-replacement/
    new webpack.NamedModulesPlugin(),
    // 当进行热更新时,相关文件名会被展示出来
    // 传送门:https://webpack.js.org/plugins/named-modules-plugin/#src/components/Sidebar/Sidebar.jsx
    new webpack.NoEmitOnErrorsPlugin(),
    // 跳过编译时出错的代码并记录,使编译后运行时的包不会发生错误。
    // 传送门:https://webpack.js.org/plugins/no-emit-on-errors-plugin/#src/components/Sidebar/Sidebar.jsx

    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      inject: true
    }),
    // 该插件可自动生成一个 html5 文件或使用模板文件将编译好的代码注入进去
    // 传送门:https://webpack.js.org/plugins/html-webpack-plugin/#src/components/Sidebar/Sidebar.jsx  
    // https://github.com/ampedandwired/html-webpack-plugin
  ]
})

module.exports = new Promise((resolve, reject) => {
  portfinder.basePort = process.env.PORT || config.dev.port
  //由于portfinder这个插件本身是从8000开始查找,这里设置查找的默认端口号
  portfinder.getPort((err, port) => {
    if (err) {
      reject(err)
    } else {
      // publish the new Port, necessary for e2e tests
      process.env.PORT = port
      // 如果端口被占用就对进程设置端口
      devWebpackConfig.devServer.port = port
      // 如果端口被占用就设置devServer的端口
      // Add FriendlyErrorsPlugin
      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
        compilationSuccessInfo: {
          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
        },
        // 添加提示信息,所在域名和端口的提示信息
        onErrors: config.dev.notifyOnErrors
          ? utils.createNotifierCallback()
          : undefined
      }))
      // 窗口提示信息,调用utils工具函数的createNotifierCallBack()方法

      resolve(devWebpackConfig)
      // 如果找到能用的端口号,就把配置信息提示抛出去
    }
  })
})

3.2 build/webpack.base.conf.js
  从webpack.dev.conf.js来看文件中引入了utils.js工具类函数和config文件夹中的index.js环境配置模块,以及引入了webpack.base.conf.js基础(开发和生产环境公共)配置。所以这里先分析webpack.base.conf.js文件。
  webpack.base.conf.js主要完成了下面这些事件:
  1.配置webpack编译入口
  2.配置webpack输出路径和命名规则
  3.配置模块resolve规则
  4.配置不同类型模块的处理规则
  文件内容如下(一些插件和语句的具体作用见注释):

'use strict'
const path = require('path')
// node.js的文件路径,用来处理文件当中的路径问题
// 传送门:http://www.jianshu.com/p/fe41ee02efc8
const utils = require('./utils')
//引入utils.js模块
const config = require('../config')
// 默认是index文件,引入index.js模块
const vueLoaderConfig = require('./vue-loader.conf')
// vue-loader.conf配置文件是用来解决各种css文件的,定义了诸如css,less,sass之类的和样式有关的loader
function resolve(dir) {
  return path.join(__dirname, '..', dir)
}
// 此函数是用来返回当前目录的平行目录的路径,因为有个'..'

module.exports = {
  context: path.resolve(__dirname, '../'),
  //基础目录(绝对路径),用于从配置中解析入口点和加载程序
  // 传送门:https://webpack.js.org/configuration/entry-context/#context
  entry: {
    app: './src/main.js'
  },
  // 定义入口文件
  output: {
    path: config.build.assetsRoot,
    // 打包生成的出口文件所放的位置
    filename: '[name].js',
    // 打包生成app.js文件
    publicPath: process.env.NODE_ENV === 'production' ?
      config.build.assetsPublicPath : config.dev.assetsPublicPath
    // 项目上线地址,也就是真正的文件引用路径,如果是production环境,其实这里都是'/'
    // path和publicPath的区别传送门:https://www.webpackjs.com/concepts/output/
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    // 省略扩展名,比方说import index from '../js/index'会默认去找index文件,然后找index.js,index.vue,index.json文件
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
    // 使用别名  使用上面的resolve函数,意思就是用@代替src的绝对路径
  },
  module: {
    rules: [{
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  },
  // 不同文件模块使用不同的loader
  node: {
    setImmediate: false,
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  }
  //这些选项可以配置是否 polyfill 或 mock 某些 Node.js 全局变量和模块。这可以使最初为 Node.js 环境编写的代码,在其他环境(如浏览器)中运行.
  //传送门:http://www.css88.com/doc/webpack/configuration/node/
}

3.3 build/utils.js
  utils提供工具函数,包括生成处理各种样式语言的loader,获取资源文件存放路径的工具函数。
  1. 计算资源文件存放路径
  2. 生成cssLoaders用于加载.vue文件中的样式
  3. 生成styleLoaders用于加载不在.vue文件中的单独存在的样式文件
  4. 处理程序在编译过程中出现的错误,并在桌面进行错误信息的提示
   文件内容如下(一些插件和语句的具体作用见注释):

   'use strict'
const path = require('path')
// node.js的文件路径,用来处理文件当中的路径问题
// 传送门:http://www.jianshu.com/p/fe41ee02efc8
const config = require('../config')
// 引入config中的index.js文件
const ExtractTextPlugin = require('extract-text-webpack-plugin')
// extract-text-webpack-plugin可以提取bundle中的特定文本,将提取后的文本单独存放到另外的文件
// 传送门:https://webpack.js.org/plugins/extract-text-webpack-plugin/#src/components/Sidebar/Sidebar.jsx
const packageConfig = require('../package.json')
// 引入包的json文件
exports.assetsPath = function (_path) {
  const assetsSubDirectory = process.env.NODE_ENV === 'production' ?
    config.build.assetsSubDirectory :
    config.dev.assetsSubDirectory

  return path.posix.join(assetsSubDirectory, _path)
  // path.posix以posix兼容的方式交互,是跨平台的,如果是path.win32的话,只能在win上
  // 传送们:https://nodejs.org/api/path.html#path_path_posix
}
// 资源存放的路径,区别在于生产环境和开发环境
exports.cssLoaders = function (options) {
  options = options || {}

  const cssLoader = {
    loader: 'css-loader',
    options: {
      sourceMap: options.sourceMap
      // 是否使用sourceMap
      // 传送门:https://webpack.js.org/loaders/css-loader/#src/components/Sidebar/Sidebar.jsx
    }
  }

  const postcssLoader = {
    loader: 'postcss-loader',
    options: {
      sourceMap: options.sourceMap
      // 是否使用sourceMap,postcss-loader用来解决各浏览器的前缀问题
      // 传送门:https://webpack.js.org/loaders/postcss-loader/#src/components/Sidebar/Sidebar.jsx
    }
  }

  function generateLoaders(loader, loaderOptions) {
    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]

    // 判断将cssLoader和postcssLoader推入loaders数组
    if (loader) {
      loaders.push({
        loader: loader + '-loader',
        options: Object.assign({}, loaderOptions, {
          sourceMap: options.sourceMap
        })
      })
    }
    // 处理各种各样的loader,并且将各种各样的loader推入loaders数组当中去
    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        fallback: 'vue-style-loader'
      })
    }
    //如果options.extract存在,则用extract-text-plugin提取样式
    else {
      return ['vue-style-loader'].concat(loaders)
    }
    // 无需提取样式则简单使用vue-style-loader配合各种样式loader去处理vue当中的