如今webpack已经成为前端项目开发过程中必不可少的一部分,一直以来都是大概了解一些内容,没有做详细的分析,这篇文章总结一下我的所获。
1、build文件(我们最终会把所有要发布的代码放到这里)
1.1 build.js (生产环境配置脚本-打包过程需要引入的配置信息)
const ora = require('ora')
//Elegant terminal spinner 优雅的终端微调器 打包开始提示对cli进行输出一个带spinner的文案,告诉用户正在打包中
const rm = require('rimraf')
//The UNIX command rm -rf for node.以包的形式包装rm -rf命令,就是用来删除文件和文件夹的,不管文件夹是否为空,都可以删除。
// 去除先前的打包,这个模块是用来清除之前的打的包,
// 因为在vue-cli中每次打包会生成不同的hash,每次打包都会生成新的文件,那就不对了,
// 我们要复盖原先的文件,因为hash不同复盖不了,所以要清除
const path = require('path')
// 模块提供了一些工具函数,用于处理文件与目录的路径。
const chalk = require('chalk')
// Terminal string styling done right,更好的命令行字符串格式
const webpack = require('webpack')
// 把webpack模块包引入
const config = require('../config')
//引入config文件
const spinner = ora('building for production...正在打包')
spinner.start()
// 对cli进行输出一个带spinner的文案,告诉用户正在打包中,也可以这样设置多个值
// const spinner = ora({
// color: 'green',
// text: '正为生产环境打包,耐心点,不然自动关机。。。'
// })
// spinner.start()
1.2 check-versions.js(检测node和npm的版本)
const chalk = require('chalk')
// chalk插件,作用是在控制台中输出不同颜色的字,
// 大致这样用chalk.blue('Hello world'),这款插件只能改变命令行中的字体颜色
const semver = require('semver')
// The semantic versioner for npm
// semver插件,是用来对特定的版本号做判断的,
// 比如 semver.gt('1.2.3','9.8.7') false 1.2.3版本比9.8.7版本低
// semver.satisfies('1.2.3','1.x || >=2.5.0 || 5.0.0 - 7.2.3') true 1.2.3的版本符合后面的规则
const packageConfig = require('../package.json')
// 上面是导入package.json文件,要使用里面的engines选项,
// 要注意require是直接可以导入json文件的,并且requrie返回的就是json对象
const shell = require('shelljs')
// Unix shell commands for Node.js
// 上面这个插件是shelljs,作用是用来执行Unix系统命令
function exec (cmd) {
// 脚本可以通过 child_process 模块新建子进程,从而执行 Unix 系统命令
// 下面这段代码实际就是把cmd这个参数传递的值转化成前后没有空格的字符串,也就是版本号
// https://nodejs.org/api/child_process.html这是nodejs的子进程教程
// require('child_process') node的模块,execSync(cmd)创建同步进程
return require('child_process').execSync(cmd).toString().trim()
// child_process.execSync(command[, options])
}
var versionRequirements = [
{
name: 'node',
currentVersion: semver.clean(process.version),
// 使用semver插件吧版本信息转化成规定格式,也就是 ' =v1.2.3 ' -> '1.2.3' 这种功能
versionRequirement: packageConfig.engines.node
// 这是规定的pakage.json中engines选项的node版本信息 "node":">= 4.0.0"
},
]
/*shell.which('npm') 返回:C:\PROGRAM FILES\NODEJS\NPM.CMD 返回绝对路径,否则返回null*/
if (shell.which('npm')) {
// shell.which方法是去环境变量搜索有没有参数这个命令
versionRequirements.push({
name: 'npm',
currentVersion: exec('npm --version'),
// 自动调用npm --version命令,并且把参数返回给exec函数,从而获取纯净的版本号
versionRequirement: packageConfig.engines.npm
// 这是规定的pakage.json中engines选项的node版本信息 "npm": ">= 3.0.0"
})
}
module.exports = function () {
var warnings = []
for (var i = 0; i < versionRequirements.length; i++) {
var mod = versionRequirements[i]
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
// 如果版本号不符合package.json文件中指定的版本号,就执行下面的代码
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.3 utils.js(定义了项目编译过程中会用到公用工具函数,主要用来处理css-loader和vue-style-loader)
const path = require('path')
// 引入nodejs路径模块
const config = require('../config')
// 引入config目录下的index.js配置文件
const ExtractTextPlugin = require('extract-text-webpack-plugin')
// 引入extract-text-webpack-plugin插件,用来将css提取到单独的css文件中
// exports其实就是一个对象,用来导出方法的最终还是使用module.exports,此处导出assetsPath
exports.assetsPath = function (_path) {
// 如果是生产环境assetsSubDirectory就是'static',否则还是'static'
const 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 || {}
const cssLoader = {
loader: 'css-loader',
options: {
minimize: process.env.NODE_ENV === 'production',
sourceMap: options.sourceMap
}
// options是用来传递参数给loader的
// minimize表示压缩,如果是生产环境就压缩css代码
// minimize: process.env.NODE_ENV === 'production',
// 是否开启cssmap,默认是false
}
// generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) {
// 将上面的基础cssLoader配置放在一个数组里面
const loaders = [cssLoader]
if (loader) {
// 如果该函数传递了单独的loader就加到这个loaders数组里面,这个loader可能是less,sass之类的
loaders.push({
loader: loader + '-loader',// 加载对应的loader
options: Object.assign({}, loaderOptions, {
// Object.assign是es6的方法,主要用来合并对象的,浅拷贝
sourceMap: options.sourceMap
})
})
}
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
// 注意这个extract是自定义的属性,可以定义在options里面,
// 主要作用就是当配置为true就把文件单独提取,false表示不单独提取,这个可以在使用的时候单独配置
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(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
}
// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
// 下面这个主要处理import这种方式导入的文件类型的打包,上面的exports.cssLoaders是为这一步服务的
const output = []
const loaders = exports.cssLoaders(options)
// 把每一种文件的loader都提取出来
for (var extension in loaders) {
var loader = loaders[extension]
output.push({
// 把最终的结果都push到output数组中
test: new RegExp('\\.' + extension + '$'),
use: loader