更新 webpack4 的部分配置
- 问题
1、不能再使用 extract-text-webpack-plugin提取 css 文件,而是用 mini-css-extract-plugin
2、production 模式下 optimization 的配置中,要加上 concatenateModules: false, 否则打出的包会有问题,这似乎是 webpack 的bug
- 新配置 optimization 中的 SplitChunksPlugin
SplitChunksPlugin 提供了两种控制 chunk 抽取模块范围的方式:
第一种是 test 属性。这个属性可以传入字符串、正则或者函数,所有的 module 都会去匹配 test 传入的条件,如果条件符合,就被纳入这个 chunk 的备选模块范围。
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all'
}
第二种方式是 chunks 属性。chunks 可以是字符串,比如 'all'|'async'|'initial',分别代表了全部 chunk,按需加载的 chunk 以及初始加载的 chunk。chunks 也可以是一个函数,在这个函数里我们可以拿到 chunk.name。
// 有 a, b, c 三个入口,我们希望 a,b 的公共代码单独打包为 common
optimization: {
splitChunks: {
cacheGroups: {
common: {
chunks(chunk) {
return chunk.name !== 'c'
}
name: 'common',
minChunks: 2
}
}
}
}
以下为原文:
本文记录webpack2中的常用配置项和插件
1、常用配置
module.exports = {
cache: true, //开启缓存功能,这样只有变化的文件才会重新加载,可提升构建速度
entry:{},
output: {},
module: {},
resolve: {},
externals:{},
plugins:{}
}
1.1 entry
-
单入口时key为app,value写上相对于webpack.config.js的入口文件路径即可,如:
注意:value还可以是数组,这种情况要注意顺序,确保主入口在数组的末位上!
-
多入口时key为app的是主入口,其他key可自己取名,但要加引号,如:
注意:有几个入口,webpack就会打几个包(bundle)出来,打出来的包的文件名与这里的key对应,比如上图会打出类似app.js和vendor.js两个文件(这里省略了hash)。
1.2 output
- path
规定打包后的文件放哪儿,必须是绝对路径,常取值为:
__dirname+’/build’或path.resolve(__dirname,’build’) - filename
规定打包后的文件的名字,对于单入口文件,可以取一个固定的名字,如’build.js’,对于多入口文件,要使用[name].bundle.js或[id].bundle.js来对应,其中name和id是根据多入口文件对象的属性动态确定的 - publicPath
规定线上地址,打包后的文件中资源的引用地址会根据这个地址而改变,一般取为’/assets/’ - chunkFilename
webpack可以做代码分割,这个属性规定那些做了代码分割的块(chunk)的名字
默认使用 [id].js
webpack中的path、publicPath、contentBase的区分
1.3 module
- rules:数组
数组中每一项类似于这样配置:
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory=true', //当使用多个loader时,请用use而不是loaders代替loader
include: [resolve('src'), resolve('test')],
exclude: [resolve('node_modules')]
}
有时还会有query或options配置,二者都是use:{options}的简写,所以在用了use后就不需要这两个配置了,如下(一个loader对应一个options,使用多个loader时用use):
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
importLoaders: 1
}
},
{
loader: 'less-loader',
options: {
noIeCompat: true
}
}
]
- noParser
防止 webpack 解析任何与给定正则表达式相匹配的文件,忽略大型库文件(library)可以提高构建性能
noParse: /jquery|lodash/
1.4 resolve
配置模块如何解析
- root:字符串或值为字符串的数组,绝对路径,配置alias中依赖项的基地址
- alias
创建 import 或 require 的别名,来确保模块引入变得更简单。
对象,key为变量名,值为路径。key指定的变量将成为全局变量,比如想在任何文件中都是用jquery而不必每次都显示引入,可以这样{$:jquery文件的地址},地址可以是相对地址(相对root指定),也可是绝对地址(使用path.resolve(__dirname,’jquery’)). - extensions:数组,文件扩展名,某文件的扩展名在该数组中时,该文件在引入时可省略扩展名,常取值有[‘’ , ’.js’ , ‘.json’ , ‘.scss’ , ‘.vue’]
- modules
告诉 webpack 解析模块时应该搜索的目录
resolve: {
extensions: ['.js', '.vue', '.json'],
modules: [
resolve('src'), //实际返回了src的路径,会优先于node_modules搜索
resolve('node_modules')
],
alias: {
'vue$': 'vue/dist/vue.common.js',
'src': resolve('src'),
'assets': resolve('src/assets'),
'components': resolve('src/components'),
'styles': resolve('src/styles'),
'utils':resolve('src/utils'),
'demos':resolve('src/demos'),
'cnode':resolve('src/cnode')
}
}
1.5 externals
提供了不从 bundle 中引用依赖的方式。也就是所创建的 bundle 依赖于那些存在于用户环境(consumer environment)中的依赖。比如jquery是用script的方式从html引入的,要想在其他模块中引入的时候就可以使用这个配置
// html
// 配置
externals: {
$: 'jQuery' //key不加引号,value是脚本里的全局对象,这里value还可以是数组或对象,但表示的含义大不一样,可参看[这里](http://www.css88.com/doc/webpack2/configuration/externals/)
}
// 其他模块引入的方式
import $ from 'jquery';
1.6 performance、stat
performance:某个打包后的包超过给定阈值时给出提示
stat:控制webpack打包后输出哪些信息
1.7 plugins
plugins是除module外最为重要的配置了,插件机制提供了loader无法完成的功能,常用的plugin有:
- CommonsChunkPlugin
- DefinePlugin
- HtmlWebpackPlugin
- UglifyjsWebpackPlugin
- ExtractTextWebpackPlugin
- OptimizeCSSPlugin
- CompressionWebpackPlugin
- SourceMapDevToolPlugin
- FriendlyErrorsPlugin
- BundleAnalyzerPlugin
2、插件用法配置
- CommonsChunkPlugin
new webpack.optimize.CommonsChunkPlugin(options)
options的配置:
name:抽取出公共代码后的模块名,若没有filename项,该项也决定打包后的文件名
chunks:从哪些模块中抽取公共代码,若省略,则从所有模块中抽取(一般是从入口模块抽)
minChunks:number|Infinity|function(module, count) -> boolean
为数字A时,表示模块必须被引用超过A次才提取到公共代码里;为infinity时,表示无穷,不抽取任何模块;为函数时,函数返回true就抽取,实例:
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function(module, count) {
// 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
)
}
})
- DefinePlugin
允许你创建一个在编译时可以配置的全局常量。
new webpack.DefinePlugin({
'process.env': config.dev.env
})
注意这里定义的常量是在业务模块中使用的,并不是在webpack这些配置文件中使用,因为webpack本身运行在node环境下,node中自身就有process等全局变量。如在入口main.js中不用声明process.env就可以直接使用process.env判断环境
- HtmlWebpackPlugin
生成一个HTML5文件,该文件的 body 中使用script 标记引用了所有 webpack bundle。若有多个webpack入口点,它们都将包含在生成的HTML中,使用script
标记引用。如果有任何CSS资源在webpack的 output 中,(例如,使用ExtractTextPlugin提取的CSS)那么这些资源将被包含在HTML head 中,使用标记引用。实例:
var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpackConfig = {
entry: 'index.js',
output: {
path: 'dist',
filename: 'index_bundle.js'
},
plugins: [new HtmlWebpackPlugin()]
};
//生成一个文件 dist/index.html
webpack App
配置:
-
title
: 生成的html中的title -
filename
: 生成的html的名字 -
template
: 用哪个模板来生成html -
inject
:true | 'head' | 'body' | false
取true或body时,all javascript 放在body底部,'head'
放head里 -
favicon
:指定生成的html的favicon -
minify
:{...} | false
压缩生成的html -
hash
:true | false
是否给所有scripts和css添加hash -
cache
: 只有当html中内容变化了才重新输出,默认true -
showErrors
:true | false
错误细节是否写到html,默认true -
chunks
: 只添加哪些chunk -
excludeChunks
: 去掉哪些chunk
- UglifyjsWebpackPlugin
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
})
// 或使用这个代替
var ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin')
new ParallelUglifyPlugin({
cacheDir: '.cache/',
uglifyJS: {
output: {
comments: false,
beautify: false
},
compress: {
warnings: false,
drop_console: true
}
}
}),
配置项和uglify一样的
- ExtractTextWebpackPlugin
将所有的 入口chunk (entry chunks) 中的 require("style.css") 或import 'style.css' 移动到分开的 css 文件.
需要两步:1、rules中配置 ExtractTextPlugin.extract 2、plugins中配置new ExtractTextPlugin("styles.css")
const ExtractTextPlugin = require("extract-text-webpack-plugin");
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
]
- OptimizeCSSPlugin
去除重复的CSS代码
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
// 配置
plugins: [
new OptimizeCSSPlugin()
]
- CompressionWebpackPlugin
压缩资源
var CompressionPlugin = require("compression-webpack-plugin");
// 配置
plugins: [
new CompressionPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: /\.js$|\.html$/,
threshold: 10240,
minRatio: 0.8
})
]
asset: 目标资源名称。 [file] 会被替换成原始资源。[path] 会被替换成原始资源的路径, [query] 会被替换成查询字符串。默认值是 "[path].gz[query]"。
algorithm: 可以是 function(buf, callback) 或者字符串。对于字符串来说依照 zlib 的算法(或者 zopfli 的算法)。默认值是 "gzip"。
test: 所有匹配该正则的资源都会被处理。默认值是全部资源。
threshold: 只有大小大于该值的资源会被处理。单位是 bytes。默认值是 0。
minRatio: 只有压缩率小于这个值的资源才会被处理。默认值是 0.8。
- BundleAnalyzerPlugin
分析打包构成
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins: [
new BundleAnalyzerPlugin({
// Can be `server`, `static` or `disabled`.
// In `server` mode analyzer will start HTTP server to show bundle report.
// In `static` mode single HTML file with bundle report will be generated.
// In `disabled` mode you can use this plugin to just generate Webpack Stats JSON file by setting `generateStatsFile` to `true`.
analyzerMode: 'server',
// Host that will be used in `server` mode to start HTTP server.
analyzerHost: '127.0.0.1',
// Port that will be used in `server` mode to start HTTP server.
analyzerPort: 8888,
// Path to bundle report file that will be generated in `static` mode.
// Relative to bundles output directory.
reportFilename: 'report.html',
// Module sizes to show in report by default.
// Should be one of `stat`, `parsed` or `gzip`.
// See "Definitions" section for more information.
defaultSizes: 'parsed',
// Automatically open report in default browser
openAnalyzer: true,
// If `true`, Webpack Stats JSON file will be generated in bundles output directory
generateStatsFile: false,
// Name of Webpack Stats JSON file that will be generated if `generateStatsFile` is `true`.
// Relative to bundles output directory.
statsFilename: 'stats.json',
// Options for `stats.toJson()` method.
// For example you can exclude sources of your modules from stats file with `source: false` option.
// See more options here: https://github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
statsOptions: null,
// Log level. Can be 'info', 'warn', 'error' or 'silent'.
logLevel: 'info'
})
]
3、webpack 配置热更新步骤
这里热更新是指局部重新加载,而非整个网页重新加载。
- 开启webpack-dev-sever的hot:true
module.exports = {
port: 3000,
contentBase: './src',
hot:true
}
- 引入热加载插件 HotModuleReplacementPlugin
module.exports = [
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new HtmlWebpackPlugin({
template: resolve('src/index.html'),
filename: resolve('dist/index.html')
}),
new webpack.HotModuleReplacementPlugin() // 热加载插件
]
- 在入口文件接收热更新
ReactDOM.render(
,
document.getElementById('root')
)
if (module.hot) {
module.hot.accept() // 这里不用写特定组件路径
}
4、webpack v4 的一些变化
参考
- Vue项目Webpack优化实践,构建效率提高50%
- 基于webpack4.X从零搭建React脚手架
- [Webpack 4 不完全迁移指北 ](https://github.com/dwqs/blog/issues/60