环境变量
通过DefinePlugin配置环境变量
new webpack.DefinePlugin({
ENV:JSON.stringify('production'),
ENV_ID:1234,
CONSTANTS:JSON.stringify({TYPES:['foo','bar']})
})
注意:我们在一些值外面加上了JSON.stringify,这是因为DefinePlugin在替换环境变量时对于字符串是直接替换,如果不加JSON.stringify,在替换后就会变成变量名,而非字符串。因此对于字符串环境变量及包含字符串的对象都要加上JSON.stringify才行
设置mode可以默认定义process.env.NODE\_ENVDE的值
source map
原理
webpack对于工程源码的每一步处理都可能会改变代码的位置,结构甚至是所处文件。所以我们生成map文件,方便我们在调试时寻找代码源头。他是源码的映射,可以将压缩后的代码再对应回未压缩的源码。使得我们在调试线上产品时,就好像在调试开发环境的代码。文件默认就是打包后的文件名加上.map,如bundle.js.map。
在生成map文件的同时,bundle文件中会追加一行注释来标注map文件的位置。如:
//bundle.js
(function(){
//bundle的内容
})();
//# sourceMappingURL=bundle.js.map
设置sourcemap
module.exports = {
//...
devtool:'source-map'
}
对于css,scss,less来说需要添加额外的source map配置项
loaders: {
css: {
options:{
sourceMap: true
}
},
less:{
options:{
javascriptEnabled: true,
sourceMap: true
}
}
}
资源压缩
压缩js
webpack4中默认使用terser的插件terser-webpack-plugin压缩js
开启压缩
1手动配置
module.exports = {
//...
optimization:{
minimize:true
}
}
2 生产环境默认配置
设置mode为production后webpack也会默认开启压缩
压缩css
压缩css的前提时使用mini-css-extract-plugin将样式提取出来。然后手动配置如下代码
//...
{ loader: 'css-loader', options: { sourceMap: true } }
资源缓存
hash、chunkhash、contenthash
hash一般是结合CDN缓存来使用,通过webpack构建之后,生成对应文件名自动带上对应的MD5值。如果文件内容改变的话,那么对应文件哈希值也会改变,对应的HTML引用的URL地址也会改变,触发CDN服务器从源服务器上拉取对应数据,进而更新本地缓存。但是在实际使用的时候,这几种hash计算还是有一定区别。
我们先建一个测试案例来模拟下:
项目结构
我们的项目结构很简单,入口文件index.js,引用了index.css。然后新建了jquery.js和test.js作为公共库。
//index.js
require('./index.css')
module.exports = function(){
console.log(`I'm jack`)
var a = 12
}
//index.css
.selected : {
display: flex;
transition: all .6s;
user-select: none;
background: linear-gradient(to bottom, white, black);
}
接着我们修改webpack.config.js来模拟不同hash计算
hash
hash是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的hash值都会更改,并且全部文件都共用相同的hash值
var extractTextPlugin = require('extract-text-webpack-plugin'),
path = require('path')
module.exports = {
context : path.join(__dirname,'src'),
entry:{
main: './index.js',
vender:['./jquery.js','./test.js']
},
module:{
rules:[{
test:/\.css$/,
use: extractTextPlugin.extract({
fallback:'style-loader',
use:'css-loader'
})
}]
},
output:{
path:path.join(__dirname, '/dist/js'),
filename: 'bundle.[name].[hash].js',
},
plugins:[
new extractTextPlugin('../css/bundle.[name].[hash].css')
]
}
根据上面的配置,我们执行webpack命令之后,可以得到下面的结果
采用hash计算的执行结果1:
执行结果2:
我们可以看到构建生成的文件hash值都是一样的,所以hash计算是跟整个项目的构建相关,同一次构建过程中生成的哈希都是一样的
**chunkhash
**
采用hash计算的话,每一次构建后生成的哈希值都不一样,即使文件内容压根没有改变。这样子是没办法实现缓存效果,我们需要换另一种哈希值计算方式,即chunkhash。
chunkhash和hash不一样,它根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值。我们在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。
var extractTextPlugin = require('extract-text-webpack-plugin'),
path = require('path')
module.exports = {
...
...
output:{
path:path.join(__dirname, '/dist/js'),
filename: 'bundle.[name].[chunkhash].js',
},
plugins:[
new extractTextPlugin('../css/bundle.[name].[chunkhash].css')
]
}
采用chunkhash计算的执行结果1:
执行结果2:
我们可以看到,由于采用chunkhash,所以项目主入口文件Index.js及其对应的依赖文件Index.css由于被打包在同一个模块,所以共用相同的chunkhash,但是公共库由于是不同的模块,所以有单独的chunkhash。这样子就保证了在线上构建的时候只要文件内容没有更改就不会重复构建
contenthash
在chunkhash的例子,我们可以看到由于index.css被index.js引用了,所以共用相同的chunkhash值。但是这样子有个问题,如果index.js更改了代码,css文件就算内容没有任何改变,由于是该模块发生了改变,导致css文件会重复构建。
这个时候,我们可以使用extra-text-webpack-plugin里的contenthash值,保证即使css文件所处的模块里就算其他文件内容改变,只要css文件内容不变,那么不会重复构建。
var extractTextPlugin = require('extract-text-webpack-plugin'),
path = require('path')
module.exports = {
...
...
output:{
path:path.join(__dirname, '/dist/js'),
filename: 'bundle.[name].[chunkhash].js',
},
plugins:[
new extractTextPlugin('../css/bundle.[name].[contenthash].css')
]
}
采用contenthash计算的执行结果1:
执行结果2:
html-webpack-plugin
//webpack.config.js
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
home: path.resolve(__dirname, './src/app.js')
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
plugins: [
new htmlWebpackPlugin({
template: './src/index.html'//可以指定html模板,方便我们放入个性化内容。它就会以该html生成一个一摸一样的html文件,然后自动塞入打包后的资源。当然也可以不指定模板。
})
]
}