在my-project项目中的build文件夹下我们看到了这四个文件:
下面我们一个一个剖析:
webpack.base.conf.js 主要对build目录下的webpack配置做详细分析
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
//入口
entry: {
app: './src/main.js'
},
//输出
output: {
path: config.build.assetsRoot,//导出目录的绝对路径
filename: '[name].js',//导出文件的文件名
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath//生产模式或开发模式下html、js等文件内部引用的公共路径
},
//文件解析
resolve: {
extensions: ['.js', '.vue', '.json'],//自动解析确定的拓展名,使导入模块时不带拓展名
alias: {// 创建import或require的别名
// 'vue': 'vue/dist/vue.js',
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
//模块解析
module: {
rules: [
{
test: /\.(js|vue)$/,//js和vue文件后缀
loader: 'eslint-loader',//使用eslint-loader处理
enforce: 'pre',//
include: [resolve('src'), resolve('test')],//
options: {
formatter: require('eslint-friendly-formatter')
}//对eslint-loader做的额外处理
},
{
test: /\.vue$/,//vue文件后缀
loader: 'vue-loader',//使用vue-loader处理
options: vueLoaderConfig//对vueloader的一些额外处理
},
{
test: /\.js$/,//js文件后缀
loader: 'babel-loader',//使用babel-loader处理
include: [resolve('src'), resolve('test')]//必须包含src和test文件夹
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,//图片后缀
loader: 'url-loader',//使用url-loader处理
options: { //对loader做的额外的选项配置
limit: 10000,//图片小于10000字节,以base64方式引用
name: utils.assetsPath('img/[name].[hash:7].[ext]')//文件名是name.7位hash值.拓展名
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,//媒体文件
loader: 'url-loader',//媒体文件使用url-loader来处理
options: {//对loader做的额外的选项配置
limit: 10000,//媒体文件小于10000字节,以base64方式引用
name: utils.assetsPath('media/[name].[hash:7].[ext]')//文件名是name.7位hash值.拓展名
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,//字体文件
loader: 'url-loader',//使用url-loader来处理
options: {//对字体文件的loader做的额外的选项配置
limit: 10000,//字体文件小于10000字节,以base64方式引用
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')//文件名是name.7位hash值.拓展名
}
}
]
}
}
//注: 关于query 仅由于兼容性原因而存在。请使用 options 代替。
webpack.dev.conf.js 开发环境下的webpack配置,通过merge方法合并webpack.base.conf.js基础配置
'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
// add hot-reload related code to entry chunks
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})
module.exports = merge(baseWebpackConfig, {
//模块配置
module: {
//通过传入一些配置来获取rules配置,此处传入了sourceMap: false,表示不生成sourceMap
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
},
// cheap-module-eval-source-map is faster for development
devtool: '#cheap-module-eval-source-map',
//插件配置
plugins: [
new webpack.DefinePlugin({// 编译时配置的全局变量
'process.env': config.dev.env//当前环境为开发环境
}),
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage
new webpack.HotModuleReplacementPlugin(),//热更新插件
new webpack.NoEmitOnErrorsPlugin(),//不触发错误,即编译后运行的包正常运行
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({//自动生成html文件,比如编译后文件的引入
filename: 'index.html',//生成的文件名
template: 'index.html',//模板
inject: true
}),
new FriendlyErrorsPlugin()//友好的错误提示
]
})
webpack.prod.conf.js 生产环境下的webpack配置,通过merge方法合并webpack.base.conf.js基础配置
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const env = process.env.NODE_ENV === 'testing'
? require('../config/test.env')
: config.build.env
const webpackConfig = merge(baseWebpackConfig, {
//module的处理,主要是针对css的处理
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true
})
},
devtool: config.build.productionSourceMap ? '#source-map' : false,
//输出文件
output: {
path: config.build.assetsRoot,//导出文件目录
filename: utils.assetsPath('js/[name].[chunkhash].js'),//导出文件名
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')//非入口文件的文件名,而又需要被打包出来的文件命名配置,如按需加载的模块
},
//插件
plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
'process.env': env//配置全局环境为生产环境
}),
// UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify
new webpack.optimize.UglifyJsPlugin({//js文件压缩插件
compress: {//压缩配置
warnings: false//不显示警告
},
sourceMap: true//生成sourceMap文件
}),
// extract css into its own file
new ExtractTextPlugin({//将js中引入的CSS分离的插件
filename: utils.assetsPath('css/[name].[contenthash].css')//分离出的CSS文件名
}),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
//压缩提取的CSS,并解决ExtractTextPlugin分离出的js重复的问题(多个文件引入同一CSS文件)
new OptimizeCSSPlugin({
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文件的插件,引入CSS文件和js文件
new HtmlWebpackPlugin({
filename: process.env.NODE_ENV === 'testing'
? 'index.html'
: config.build.index,//生成的HTML文件名
template: 'index.html',//依据的模板
inject: true,//注入的js文件将会被放在body标签中,当值为head时将会被放在head标签中
minify: {//压缩配置
removeComments: true,//删除HTML中的注释代码
collapseWhitespace: true,//删除HTML中的空白字符
removeAttributeQuotes: true//删除HTML元素中属性的引号
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'//按照dependency的顺序引入
}),
// keep module.id stable when vender modules does not change 保持模块。当vender模块没有改变时,id就稳定了
new webpack.HashedModuleIdsPlugin(),
// split vendor js into its own file 将供应商js分解为自己的文件
//分离公共js到vendor中
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',//文件名
minChunks: function (module) {//申明公共的模块来自node_modules中
// any required modules inside node_modules are extracted to 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运行时和模块清单提取到自己的文件中,以防止当应用程序包被更新时,供应商哈希被更新。
//上面虽然已经分离了第三方库,每次修改编译都会改变vendor的hash值,导致浏览器缓存失效。
//原因是vendor包含了webpack在打包过程中会产生一些运行时代码,运行时代码中实际上保存了打包后的文件名。
//当修改业务代码时,业务代码的js文件的hash值必然会改变。一旦改变必然会导致vendor变化。vendor变化会导致其hash值变化。
//下面主要是将运行时代码提取到单独的manifest文件中,防止其影响vendor.js
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor']
}),
// copy custom static assets
// 复制静态资源,将static文件内的内容复制到指定文件夹
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']//忽略*文件
}
])
]
})
//额外配置
if (config.build.productionGzip) {//配置文件开启了gzip压缩
//引入压缩文件的组件,该插件会对生成的文件进行压缩,生成一个.gz文件
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]',//目标文件名
algorithm: 'gzip',//使用gzip压缩
test: new RegExp(//满足正则表达式的文件会被压缩
'\\.(' +
config.build.productionGzipExtensions.join('|') +
')$'
),
threshold: 10240,//资源文件大于10240B = 10KB大小才会被压缩
minRatio: 0.8//最小压缩比达到0.8时才会被压缩
})
)
}
if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig
webpack.test.conf.js
'use strict'
// This is the webpack config used for unit tests.
//这是用于单元测试的webpack配置。
const utils = require('./utils')
const webpack = require('webpack')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const webpackConfig = merge(baseWebpackConfig, {
// use inline sourcemap for karma-sourcemap-loader
//为karma-sourcemap加载器使用内联sourcemap
module: {
rules: utils.styleLoaders()
},
devtool: '#inline-source-map',
resolveLoader: {
alias: {
// necessary to to make lang="scss" work in test when using vue-loader's ?inject option
// see discussion at https://github.com/vuejs/vue-loader/issues/724
// 在使用vuloader的时候,需要使lang=“scss”在测试中工作吗?请参阅[https://github.com/vuejs/vue-loader/issues/724]的讨论注入选项
'scss-loader': 'sass-loader'
}
},
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/test.env')
})
]
})
// no need for app entry during tests
//在测试中不需要应用程序条目
delete webpackConfig.entry
module.exports = webpackConfig