1.dev-server.js

// dev-server.js
// 调用check-versions.js 模块,检查版本node和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)
}

// opn模块,使用默认应用程序,打开网址、文件、 可执行程序等内容的一个插件。
// 例如,使用默认浏览器打开urls。跨平台可用。
// 这里用它来调用默认浏览器打开dev-server监听的端口,例如: localhost:8080
var opn = require('opn')
// path模块提供用于处理文件和目录路径的实用程序。
var path = require('path')
// 引入express 模块
var express = require('express')
// 引入 webpack模块
var webpack = require('webpack')

// 一个express中间件,用于将http请求代理到其他服务器
// 例:localhost:8080/api/xxx  -->  localhost:3000/api/xxx
// 这里使用该插件可以将前端开发中涉及到的请求代理到API服务器上,方便与服务器对接
var proxyMiddleware = require('http-proxy-middleware')

// 根据 Node 环境来引入相应的 webpack 配置
// 这里用 "testing" 来判断Node环境, 是因为在两个webpack.***.conf中还会有判断
var webpackConfig = process.env.NODE_ENV === 'testing'
  ? require('./webpack.prod.conf')
  : require('./webpack.dev.conf')

// dev-server 监听的端口,默认为config.dev.port设置的端口,即8080
// default port where dev server listens for incoming traffic
var port = process.env.PORT || config.dev.port

// 用于判断是否要自动打开浏览器的布尔变量,
// 当配置文件中没有设置自动打开浏览器的时候其值为 false
// `!!`是一个逻辑操作,表示强制转换类型。这里强制转换为`bool`类型
// automatically open browser, if not set will be false
var autoOpenBrowser = !!config.dev.autoOpenBrowser

// 定义HTTP代理,到自定义API接口
// Define HTTP proxies to your custom API backend
// https://github.com/chimurai/http-proxy-middleware
var proxyTable = config.dev.proxyTable

// 创建一个express实例
var app = express()

// 根据webpack配置文件创建Compiler对象
var compiler = webpack(webpackConfig)

// 引入webpack开发中间件, 此插件只在开发环境中有用。
// 使用compiler对象来对相应的文件进行编译和绑定
// 编译绑定后将得到的产物存放在内存中而没有写进磁盘
// 将这个中间件交给express使用之后即可访问这些编译后的产品文件
var devMiddleware = require('webpack-dev-middleware')(compiler, {
  //绑定中间件到publicpath中,使用方法和在webpack中相同
  publicPath: webpackConfig.output.publicPath, 
  quiet: true // 允许在console控制台显示 警告 和 错误 信息
})

// 引入热重载功能的中间件。
// Webpack热重载仅使用webpack-dev-middleware开发中间件。
// 这个中间件,允许您在没有webpack-dev-server的情况下,将热重载功能到现有服务器中。
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
  // 用于打印行的功能
  log: () => {}
})

// 当html-webpack-plugin 提交之后通过热重载中间件发布重载动作使得页面重载
// force page reload when html-webpack-plugin template changes
compiler.plugin('compilation', function (compilation) {
  compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
    hotMiddleware.publish({ action: 'reload' })
    cb()
  })
})

// 将 proxyTable 中的代理请求配置挂在express服务器上
// proxy api requests
Object.keys(proxyTable).forEach(function (context) {
  var options = proxyTable[context]
  if (typeof options === 'string') {
    options = { target: options }
  }
  app.use(proxyMiddleware(options.filter || context, options))
})

// connect-history-api-fallback 模块,通过指定的索引页来代理请求的中间件,对于使用HTML5历史API的单个页面应用程序非常有用。
// 处理 HTML5历史api回退的问题
// handle fallback for HTML5 history API
app.use(require('connect-history-api-fallback')())

// 为webpack打包输出服务
// serve webpack bundle output
app.use(devMiddleware)

// 热重载和状态保留功能
// 显示编译错误信息
// enable hot-reload and state-preserving
// compilation error display
app.use(hotMiddleware)

// posix属性提供了对路径方法的POSIX特定实现的访问。
// 服务纯静态资源。 利用Express托管静态文件,使其可以作为资源访问
// 想要访问static文件夹下的资源,必须添加 staticPath 返回的地址作为上一级地址。
// serve pure static assets
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
app.use(staticPath, express.static('./static'))

// 应用启动时候的访问地址信息,例如 http://localhost:8080
var uri = 'http://localhost:' + port

// 异步回调
var _resolve
var readyPromise = new Promise(resolve => {
  _resolve = resolve
})

console.log('> Starting dev server...')
// 如果webpack开发中间件有效执行,那么执行后面的回调函数。
devMiddleware.waitUntilValid(() => {
  console.log('> Listening at ' + uri + '\n')
  // 如果是 testing 环境, 不需要打开浏览器
  // when env is testing, don't need open it
  if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
    opn(uri)
  }
  _resolve()
})

// 启动express服务器并监听相应的端口(8080)
var server = app.listen(port)

// 模块导出。
// 1:执行异步函数
// 2:提供close方法,关闭服务器
module.exports = {
  ready: readyPromise,
  close: () => {
    server.close()
  }
}

2.check-versions.js

var chalk = require('chalk') //定制终端字符串的颜色输出样式
var semver = require('semver')  // 语义化版本控制规范
var packageConfig = require('../package.json') 
var shell = require('shelljs') // 调用系统命令

// 调用子线程同步执行 cmd终端命令
function exec (cmd) {
  return require('child_process').execSync(cmd).toString().trim()
}

var versionRequirements = [
  {
    name: 'node',
    currentVersion: semver.clean(process.version),
    versionRequirement: packageConfig.engines.node
  },
]

if (shell.which('npm')) {
  versionRequirements.push({
    name: 'npm',
    currentVersion: exec('npm --version'),
    versionRequirement: packageConfig.engines.npm
  })
}

module.exports = function () {
  var warnings = []
  for (var i = 0; i < versionRequirements.length; i++) {
    var mod = versionRequirements[i]
    // semver.satisfies如果版本满足要求,返回true
    // 这里取反,不满足则将 警告存入warnings数组,供后面使用
    // 警告的内容是: 系统当前版本(红色字体) should be 应用程序要求的版本(绿色字体)
    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
      warnings.push(mod.name + ': ' +
        chalk.red(mod.currentVersion) + ' should be ' +
        chalk.green(mod.versionRequirement)
      )
    }
  }

// 如果有警告,则用黄色字体将警告输出到终端,并终止当前进程
  if (warnings.length) {
    console.log('')
    console.log(chalk.yellow('To use this template, you must update following to modules:'))
    console.log()
    for (var i = 0; i < warnings.length; i++) {
      var warning = warnings[i]
      console.log('  ' + warning)
    }
    console.log()
    process.exit(1)
  }
}
  1. config/index.js:
// see http://vuejs-templates.github.io/webpack for documentation.
var path = require('path')

module.exports = {
  // 构建应用程序时使用的配置
  build: { // 生产环境
    env: require('./prod.env'), // 环境变量,使用config/prod.env.js中定义的编译环境
    index: path.resolve(__dirname, '../dist/index.html'), // html入口文件
    assetsRoot: path.resolve(__dirname, '../dist'), // 应用程序存放的资源路径,本地文件系统上的绝对路径
    assetsSubDirectory: 'static', // 应用程序存放的资源主目录
    assetsPublicPath: './', // 资源发布的根目录,如果资源不是放在宿主机的根目录,一般修改为'./'
    productionSourceMap: true, // 打包的文件,是否打开source-map  true打开 false 不打开
    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    // Gzip默认关闭的。在流行的静态主机 例如Surge或者Netlify已经帮你把所有的静态资源文件都gzip了。 
    // 在设置为'true'之前,请确保安装了插件'compression-webpack-plugin'
    productionGzip: false, // 是否开启gzip
    productionGzipExtensions: ['js', 'css'], // 使用gzip压缩的文件扩展名
    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    // 使用一个额外的参数运行构建命令
    // 构建完成后,异步查看包分析报告。
    // `npm run build --report`
    // 设置'true'或者'false'来控制它的'执行'或'关闭'
    bundleAnalyzerReport: process.env.npm_config_report
  },
  dev: { // 开发环境
    env: require('./dev.env'),  // 环境变量,使用config/dev.env.js中定义的编译环境
    port: 8017, // 运行测试页面时候的端口号
    autoOpenBrowser: true, // 是否自动打开浏览器。true 是,false 否
    assetsSubDirectory: 'static', // 应用程序存放的资源主目录 
    assetsPublicPath: '/', // 编译发布的根目录,可配置为资源服务器域名或 CDN 域名
    proxyTable: {}, // 需要 proxyTable 代理的接口(可跨域)
    // CSS Sourcemaps off by default because relative paths are "buggy"
    // with this option, according to the CSS-Loader README
    // (https://github.com/webpack/css-loader#sourcemaps)
    // In our experience, they generally work as expected,
    // just be aware of this issue when enabling this option.
    cssSourceMap: false // 是否开启cssSourceMap,默认是false关闭的
  }
}

4.webpack.base.conf.js:

// webpack的基本配置文件
// 1:配置webpack入口文件
// 2:配置webpack输出路径和命名规则
// 3: 配置模块resolve规则
// 4: 配置不同类型模块的处理规则
var path = require('path')
var utils = require('./utils')
var config = require('../config') // 获取配置
var vueLoaderConfig = require('./vue-loader.conf') // 获取loader配置

// 获取绝对路径
function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  // 入口起点。这里应用程序开始执行,webpack 开始打包
  entry: {
    app: './src/main.js'
  }, 
  // 输出。webpack如何输出结果的相关选项
  output: {
    path: config.build.assetsRoot, // 所有输出文件的目标路径。必须是绝对路径
    filename: '[name].js', // 入口分块(entry chunk) 的文件名模块
    // 输出解析文件的目录。 url 相对于 HTML 页面
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  // 解析模块请求的选项 (不适用于对 loader 解析)
  resolve: {
    // 使用的扩展名
    extensions: ['.js', '.vue', '.json'],
    // 模块别名列表,使用别名,方便引用模块
    alias: {
      // 起别名 'vue$' -> 'vue/dist/vue.esm.js'
      'vue$': 'vue/dist/vue.esm.js',
      // 起别名: '@' ->  'src的绝对路径'
      '@': resolve('src')
    }
  },
  // 模块配置
  module: {
    // 模块规则(配置 loader、解析器等选项)
    
    // 匹配条件,每个选项都接收一个正则表达式或字符串
    // test 和 inclue 具有相同的作用, 都是必须匹配选项
    // exclude 是必不匹配选项(优先于 test 和 include)
    // 最佳实践:
    // - 只在 test 和 文件名匹配 中使用正则表达式
    // - 在 include 和 exclude 中使用绝对路径数组
    // - 尽量避免 exclude,更倾向于使用 include
    rules: [
      {
        // 对所有.vue文件使用vue-loader进行编译
        test: /\.vue$/, 
        loader: 'vue-loader', // 应该应用的loader,它相对上下文解析
        options: vueLoaderConfig  // loader的可选项
      },
      {
        // 对src和test文件夹下的.js文件使用babel-loader将es6+的代码转成es5
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test')]
      },
      {
        // 对图片资源文件使用url-loader
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          // 小于10k的图片转成base64编码的dataURL字符串写到代码中
          // 其他的图片转移到静态资源文件夹img/
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        // 对字体资源文件使用url-loader
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          // 小于10K的资源转成base64编码的dataURL字符串写到代码中
          // 其他的资源转移到静态资源文件夹fonts/
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  }
}

5.webpack.prod.conf

// 下面是引入nodejs的路径模块
var path = require('path')
// 下面是utils工具配置文件,主要用来处理css类文件的loader
var utils = require('./utils')
// 下面引入webpack,来使用webpack内置插件
var webpack = require('webpack')
// 下面是config目录下的index.js配置文件,主要用来定义了生产和开发环境的相关基础配置
var config = require('../config')
// 下面是webpack的merger插件,主要用来处理配置对象合并的,可以将一个大的配置对象拆分成几个小的,合并,相同的项将覆盖
var merge = require('webpack-merge')
// 下面是webpack.base.conf.js配置文件,我其他博客文章已经解释过了,用来处理不同类型文件的loader
var baseWebpackConfig = require('./webpack.base.conf')
// copy-webpack-plugin使用来复制文件或者文件夹到指定的目录的
var CopyWebpackPlugin = require('copy-webpack-plugin')
// html-webpack-plugin是生成html文件,可以设置模板,之前的文章将过了
var HtmlWebpackPlugin = require('html-webpack-plugin')
// extract-text-webpack-plugin这个插件是用来将bundle中的css等文件产出单独的bundle文件的,之前也详细讲过
var ExtractTextPlugin = require('extract-text-webpack-plugin')
// optimize-css-assets-webpack-plugin插件的作用是压缩css代码的,还能去掉extract-text-webpack-plugin插件抽离文件产生的重复代码,因为同一个css可能在多个模块中出现所以会导致重复代码,换句话说这两个插件是两兄弟
// 详情见(1)
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')

// 如果当前环境变量NODE_ENV的值是testing,则导入 test.env.js配置文,设置env为"testing"
// 如果当前环境变量NODE_ENV的值不是testing,则设置env为"production"
var env = process.env.NODE_ENV === 'testing'
  ? require('../config/test.env')
  : config.build.env

// 把当前的配置对象和基础的配置对象合并
var webpackConfig = merge(baseWebpackConfig, {
  module: {
      // 下面就是把utils配置好的处理各种css类型的配置拿过来,和dev设置一样,就是这里多了个extract: true,此项是自定义项,设置为true表示,生成独立的文件
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,
      extract: true
    })
  },
  // devtool开发工具,用来生成个sourcemap方便调试
  // 按理说这里不用生成sourcemap多次一举,这里生成了source-map类型的map文件,只用于生产环境
  devtool: config.build.productionSourceMap ? '#source-map' : false,
  output: {
      // 打包后的文件放在dist目录里面
    path: config.build.assetsRoot,
    // 文件名称使用 static/js/[name].[chunkhash].js, 其中name就是main,chunkhash就是模块的hash值,用于浏览器缓存的
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    // chunkFilename是非入口模块文件,也就是说filename文件中引用了chunckFilename
    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
    }),
    new webpack.optimize.UglifyJsPlugin({
        // UglifyJsPlugin插件是专门用来压缩js文件的
      compress: {
        warnings: false // 禁止压缩时候的警告信息,给用户一种vue高大上没有错误的感觉
      },
      // 压缩后生成map文件
      sourceMap: true
    }),
    // extract css into its own file
    new ExtractTextPlugin({
        // 生成独立的css文件,下面是生成独立css文件的名称
      filename: utils.assetsPath('css/[name].[contenthash].css')
    }),
    // Compress extracted CSS. We are using this plugin so that possible
    // duplicated CSS from different components can be deduped.
    new OptimizeCSSPlugin({
        // 压缩css文件
      cssProcessorOptions: {
        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({
        //非测试环境生成index.html
      filename: process.env.NODE_ENV === 'testing'
        ? 'index.html'
        : config.build.index,
        // 模板是index.html加不加无所谓
      template: 'index.html',
      // 将js文件放到body标签的结尾
      inject: true,

      minify: {
          // 压缩产出后的html页面
        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
      // 分类要插到html页面的模块
      chunksSortMode: 'dependency'
    }),


    // split vendor js into its own file
    // 下面的插件是将打包后的文件中的第三方库文件抽取出来,便于浏览器缓存,提高程序的运行速度
    new webpack.optimize.CommonsChunkPlugin({
        // common 模块的名称
      name: 'vendor',
      minChunks: function (module, count) {
        // any required modules inside node_modules are extracted to vendor
        // 将所有依赖于node_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
    // 把webpack的runtime代码和module manifest代码提取到manifest文件中,防止修改了代码但是没有修改第三方库文件导致第三方库文件也打包的问题
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      chunks: ['vendor']
    }),
    // copy custom static assets
    // 下面是复制文件的插件,我认为在这里并不是起到复制文件的作用,而是过滤掉打包过程中产生的以.开头的文件
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.build.assetsSubDirectory,
        ignore: ['.*']
      }
    ])
  ]
})

if (config.build.productionGzip) {
    // 开启Gzi压缩打包后的文件,老铁们知道这个为什么还能压缩吗??,就跟你打包压缩包一样,把这个压缩包给浏览器,浏览器自动解压的
    // 你要知道,vue-cli默认将这个神奇的功能禁用掉的,理由是Surge 和 Netlify 静态主机默认帮你把上传的文件gzip了
  var CompressionWebpackPlugin = require('compression-webpack-plugin')

  webpackConfig.plugins.push(
    new CompressionWebpackPlugin({
      asset: '[path].gz[query]',
      algorithm: 'gzip',
      test: new RegExp( // 这里是把js和css文件压缩
        '\\.(' +
        config.build.productionGzipExtensions.join('|') +
        ')$'
      ),
      threshold: 10240,
      minRatio: 0.8
    })
  )
}

if (config.build.bundleAnalyzerReport) {
    // 打包编译后的文件打印出详细的文件信息,vue-cli默认把这个禁用了,个人觉得还是有点用的,可以自行配置
  var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig

6.webpack.prod.conf.js

//引入当前目录下的utils.js文件模块
var utils = require('./utils')
//node的path模块
var path = require('path')
//内置模块
var webpack = require('webpack')
//引入config目录下的index.js文件
var config = require('../config')
//进行合并对象,相同项目会进行覆盖
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
// 下面是一个自动生成html的插件,能够把资源自动加载到html文件中
// 详情请看 (1)
var HtmlWebpackPlugin = require('html-webpack-plugin')
// 下面这个插件是用来把webpack的错误和日志收集起来,漂亮的展示给用户
// 详情请看 (2)
var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')

//=======================静态编译ssi资源==================================
var SSICompileWebpackPlugin = require('ssi-webpack-plugin')

// add hot-reload related code to entry chunks
// Object.keys(obj) Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,
//数组中属性名的排列顺序和使用 
for...in
 循环遍历该对象时返回的顺序一致 (两者的主要区别是 一个 for-in 循环还会枚举其原型链上的属性)。
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
// 下面这个结果就是把webpack.base.conf.js中的入口entry改成如下配置 
// app: ['./build/dev-client','./src/main.js']    //即数组多加了一个元素
  baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})

// 下面是合并配置对象,将这个配置文件特有的配置添加替换到base配置文件中
module.exports = merge(baseWebpackConfig, {
  module: {
  // 下面是把utils配置中的处理css类似文件的处理方法拿过来,并且不生成cssMap文件
    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
  },
  // cheap-module-eval-source-map is faster for development
// devtool是开发工具选项,用来指定如何生成sourcemap文件,cheap-module-eval-source-map此款soucemap文件性价比最高

  devtool: '#source-map',
  plugins: [
// DefinePlugin内置webpack插件,专门用来定义全局变量的,下面定义一个全局变量 process.env 并且值是如下
 /* 'process.env': { NODE_ENV: '"development"' }
 这样的形式会被自动转为 'process.env': '"development"' 
各位骚年看好了,development如果不加双引号就当做变量处理,程序会报错 */
    new webpack.DefinePlugin({
      'process.env': config.dev.env
    }),

    //提取公共代码块 babel-polyfill只能有一个实例
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      chunks: ['index', 'admin'],
      minChunks: function (module, count) {
        return (
          module.resource && 
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0 
        )
      }
    }),
    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
    new webpack.HotModuleReplacementPlugin(),
// 下面这个插件比较简单,就是当webpack编译错误的时候,来中端打包进程,防止错误代码打包到文件中,你还不知道
    new webpack.NoEmitOnErrorsPlugin(),
    // https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      favicon: './src/assets/images/favicon.ico',
      excludeChunks: ['admin'],
      inject: true
    }),
    new HtmlWebpackPlugin({
      filename: 'admin.html',
      template: 'admin.html',
      favicon: './src/assets/images/favicon.ico',
      excludeChunks: ['index'],
      inject: true
    }),
    new SSICompileWebpackPlugin({
      publicPath:'',
      localBaseDir:'C:/Developer/newWorkspace',
      minify:false
    }),
    new FriendlyErrorsPlugin()
  ]
})

util.js:

// 引入nodejs路径模块
var path = require('path')
// 引入config目录下的index.js配置文件
var config = require('../config')
// 引入extract-text-webpack-plugin插件,用来将css提取到单独的css文件中
// 详情请看(1)
var ExtractTextPlugin = require('extract-text-webpack-plugin')
// exports其实就是一个对象,用来导出方法的最终还是使用module.exports,此处导出assetsPath
exports.assetsPath = function (_path) {
    // 如果是生产环境assetsSubDirectory就是'static',否则还是'static',哈哈哈
    var assetsSubDirectory = process.env.NODE_ENV === 'production'
        ? config.build.assetsSubDirectory
        : config.dev.assetsSubDirectory
    // path.join和path.posix.join的区别就是,前者返回的是完整的路径,后者返回的是完整路径的相对根路径
    // 也就是说path.join的路径是C:a/a/b/xiangmu/b,那么path.posix.join就是b
    return path.posix.join(assetsSubDirectory, _path)
    // 所以这个方法的作用就是返回一个干净的相对根路径
}

// 下面是导出cssLoaders的相关配置
exports.cssLoaders = function (options) {
    // options如果没值就是空对象
    options = options || {}
    // cssLoader的基本配置
    var cssLoader = {
        loader: 'css-loader',
        options: {
            // options是用来传递参数给loader的
            // minimize表示压缩,如果是生产环境就压缩css代码
            minimize: process.env.NODE_ENV === 'production',
            // 是否开启cssmap,默认是false
            sourceMap: options.sourceMap
        }
    }

    // generate loader string to be used with extract text plugin
    function generateLoaders (loader, loaderOptions) {
        // 将上面的基础cssLoader配置放在一个数组里面
        var loaders = [cssLoader]
        // 如果该函数传递了单独的loader就加到这个loaders数组里面,这个loader可能是less,sass之类的
        if (loader) {
            loaders.push({
                // 加载对应的loader
                loader: loader + '-loader',
                // Object.assign是es6的方法,主要用来合并对象的,浅拷贝
                options: Object.assign({}, loaderOptions, {
                    sourceMap: options.sourceMap
                })
            })
        }

        // Extract CSS when that option is specified
        // (which is the case during production build)
        // 注意这个extract是自定义的属性,可以定义在options里面,主要作用就是当配置为true就把文件单独提取,false表示不单独提取,这个可以在使用的时候单独配置,瞬间觉得vue作者好牛逼
        if (options.extract) {
            return ExtractTextPlugin.extract({
                use: loaders,
                fallback: 'vue-style-loader'
            })
        } else {
            return ['vue-style-loader'].concat(loaders)
        }
        // 上面这段代码就是用来返回最终读取和导入loader,来处理对应类型的文件
    }

    // https://vue-loader.vuejs.org/en/configurations/extract-css.html
    return {
        css: generateLoaders(), // css对应 vue-style-loader 和 css-loader
        postcss: generateLoaders(), // postcss对应 vue-style-loader 和 css-loader
        less: generateLoaders('less'), // less对应 vue-style-loader 和 less-loader
        sass: generateLoaders('sass', { indentedSyntax: true }), // sass对应 vue-style-loader 和 sass-loader
        scss: generateLoaders('sass'), // scss对应 vue-style-loader 和 sass-loader
        stylus: generateLoaders('stylus'), // stylus对应 vue-style-loader 和 stylus-loader
        styl: generateLoaders('stylus') // styl对应 vue-style-loader 和 styl-loader 
    }
}

// Generate loaders for standalone style files (outside of .vue)
// 下面这个主要处理import这种方式导入的文件类型的打包,上面的exports.cssLoaders是为这一步服务的
exports.styleLoaders = function (options) {
    var output = []
    // 下面就是生成的各种css文件的loader对象
    var loaders = exports.cssLoaders(options)
    for (var extension in loaders) {
        // 把每一种文件的laoder都提取出来
        var loader = loaders[extension]
        output.push({
            // 把最终的结果都push到output数组中,大事搞定
            test: new RegExp('\\.' + extension + '$'),
            use: loader
        })
    }
    return output
}
Logo

前往低代码交流专区

更多推荐