本文项目代码位置: 源码地址javascript
webpack 能干什么?css
module.exports = {
entry: '', // 指定入口文件
output: '', // 指定输出目录和输出文件名
mode: '', // 环境
module: {
rules: [ // loader配置
{test: '', use: ''}
]
},
plugins: [ // 插件配置
new xxxPlugin()
]
}
复制代码
为何须要 loader ?html
webpack 原生只支持 js、json 两种模块类型,因此须要 loader 把其余类型的文件转化成有效的模块,并能够添加到依赖图中。vue
loader 自己是一个函数,接受源文件做为参数,返回转换的结果html5
功能 | loader | 说明 |
---|---|---|
解析es6 | babel-loader | 配合.babelrc使用 |
解析vue | vue-loader | |
解析css | css-loader | 用于加载.css文件,并转换成commonjs对象 |
style-loader | 将样式经过<style> 标签插入到head中 |
|
解析less | less-loader | 将less转换成css |
解析图片和字体 | file-loader | 用于处理文件(图片、字体) |
url-loader | 也能够处理图片和字体,和file-loader功能相似,但它还能够设置较小资源自动转base64(内部用了file-loader),使用options:{limit: xxx} |
插件用于 bundle 文件的优化、资源管理和环境变量注入,它做用于整个构建过程java
style-loader
功能互斥,不能同时使用JS文件的压缩 :默认开启了内置的 terser-webpack-plugin
,webpack 在打包时会自动压缩 js 代码
css文件的压缩 :使用 optimize-css-assets-webpack-plugin
,同时使用 cssnano
(处理器)node
plugins: [
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano')
})
]
复制代码
html文件的压缩:修改 html-webpack-plugin
,设置压缩参数react
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html',
chunks: ['main', 'other'], //要包含哪些chunk
inject: true, //将chunks自动注入html
minify: { // 压缩相关
html5: true,
collapseWhitespace: true, //压缩空白字符
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: true
}
})
]
复制代码
开启 dev-server
后默认只要有一个文件变化,会从新构建,刷新浏览器页面。jquery
模块热替换: 只从新打包变动的模块,局部刷新,保留数据状态,(而不是将全部模块从新打包,刷新页面)提高构建速度,使开发更加方便webpack
经过 devServer.hot
启用,其内部依赖 webpack.HotModuleReplacementPlugin
实现,HotModuleReplacementPlugin
会在 hot: true
时自动被引入,能够不写
style-loader
内部实现了if(module.hot){ // 若是开启了HMR功能
// 监听xxx.js文件的变化,一旦发生变化,其余模块不会从新打包,会执行回调函数
module.hot.accept('./xxx.js', function(){
fn()
})
}
复制代码
因为通过 webpack
打包后的代码是通过各类 loaders
,plugins
转换事后的一个大的js文件,开发过程当中没法调试。source-map
是一种提供源代码到构建后代码映射的技术,报错时经过 source map
能够定位到源代码。
启用方式:
module.exports = {
devtool: 'source-map'
}
复制代码
选项:
[inline- | hidden- | eval-] [nosources- ] [cheap- [module- ]]source-map
.map
文件,提供错误代码准确信息和源代码的错误位置.map
做为 DataURI
嵌入,不单独生成 .map
文件,构建速度更快eval
包裹模块代码,指定模块对应文件loader
的 sourcemap
推荐组合:
eval-source-map
(eval
速度最快,source-map
调试最友好)
1.考虑是否要隐藏源代码?
nosources-source-map
---所有隐藏
hidden-source-map
---只隐藏源代码,会提示构建后代码错误信息
2.考虑是否要调试友好?
source-map
当设置了 http 强缓存,好比有效期为一天,若是不使用 hash,当这个文件改变了,由于文件名没变,因此客户端使用的仍是旧的缓存;若是使用了 hash,这时文件名就改变了,就会请求新的资源,而没有更改过的文件继续使用缓存
hash
,每次构建都会改变,不建议使用webpack
打包的 chunk
有关,不一样的 entry
会生成不一样的 chunkhash
值contenthash
不变,推荐在 css
文件上使用js 文件的指纹设置:
//设置 output 的 filename,使用 [chunkhash]
module.exports = {
output: {
filename: '[name][chunkhash:8].js',
path:__dirname+'/dist'
}
}
复制代码
css 文件的指纹设置:
使用 MiniCssExtractPlugin
将 css
从 js
中提出来,而后使用 [contenthash]
plugins: [
new MiniCssExtractPlugin({
filename: '[name][contenthash:8].css'
})
]
复制代码
补充:
module、chunk、bundle的区别
chunk
,能够理解为一个 entry
对应一个 chunk
chunk
就对应一个 bundle
,但也能够经过一些插件进行拆包,把一个大chunk
拆分为多个 bundle
,好比 MiniCssExtractPlugin
tree shaking
(摇树优化):一个模块可能有多个方法,只要其中的某个方法使用到了,则整个文件都会被打到 bundle
里面去,tree shaking
就是只把用到的方法打入bundle
,没用到的方法会在 uglify
阶段被擦除掉。
使用:webpack
默认支持,在 .babelrc
里设置 module:false
便可
webpack
会在 production mode
的状况下默认开启 tree shaking
要求:必须是 es6 语法,cjs 的方式不支持
tree shaking 原理
DCE:永远不会被用到的代码,好比引入了一个方法可是没调用 或者 if(false){xxx}
利用 ES6 模块的特色:
import
的模块名只能是字符串常量import binding
是immutable
的在打包以前静态的分析文件,在uglify阶段删除无用代码
将一个大bundle文件拆包,拆包的方案能够在cacheGroups里配置
// splitChunks默认配置
optimization: {
splitChunks: {
chunks: 'all', // 不管同步引入仍是异步引入
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/, // 匹配node_modules目录下的文件
priority: -10 // 优先级配置项
},
default: {
minChunks: 2, // 至少引用了2次
priority: -20, // 优先级配置项
reuseExistingChunk: true
}
}
}
}
复制代码
在默认设置中
node_mudules
文件夹中的模块打包进一个叫 vendors
的 bundle
中default bundle
中 ,能够经过 priority
来设置优先级。将第三方库和业务基础包单独打成一个文件,只在第一次打,或者须要更新依赖的时候打,此后每次就能够只打本身的源代码,加快了构建速度。
方法:使用 DLLPlugin
进行分包,DllReferencePlugin
对 manifest.json
引用
分包须要单独的配置文件:
// webpack.dll.js
module.exports={
entry: {
lib: [
'lodash',
'jquery'
]
},
output: {
filename: '[name]_[chunkhash].dll.js',
path: path.join(__dirname, 'build/lib'),
library: '[name]' // 打包后对外暴露的全局变量名称
},
plugins: [
new webpack.DllPlugin({
name: '[name]', // manifest.json中的name,要与ouput.library名一致
path: path.join(__dirname, 'build/lib/manifest.json'),
})
]
}
复制代码
在 package.json
中添加命令对 dll
单独打包:
"scripts": {
"dll": "webpack --config webpack.dll.js"
},
复制代码
使用 DllReferencePlugin
对 manifest.json
进行引用,告诉 webpack
使用了哪些动态连接库,不用再打包这里面的东西
// webpack.prod.js
new webpack.DllReferencePlugin({
manifest: require('./build/lib/manifest.json')
}),
复制代码
使用 addAssetHtmlWebpackPlugin
将 dll
资源插到 html
里
// webpack.prod.js
new addAssetHtmlWebpackPlugin([
{
filepath: path.resolve(__dirname, './build/lib/*.dll.js'),
outputPath: 'static', // 将*.dll.js拷贝后的输出路径,相对于html文件
publicPath: 'static'
}
])
复制代码
demo 地址: webpack实践-dll-plugin分支
使用先后对比:
使用 dllplugin
前,基础库打到了 main.js
里,占了 160kb
: 使用后:
main.js
只剩 1.23kb
splitChunks
是在构建时拆包,dll
是提早构建好基础库,打包的时候就不须要打基础库了,时间上 dll
比 splitChunks
快一点dll
须要多配置一个 webpack.dll.config.js
,并且一旦 dll
中的依赖有更新,得走两遍打包,比 splitChunks
麻烦一些splitChunks
去提取页面间的公共 js
文件。DllPlugin
用于基础包(框架包、业务包)的分离。使用 thread-loader
开启多进程打包,加快打包速度!
注意:启动进程须要大概 600ms
,进程间通讯也有花销,项目小的话开启多进程得不偿失,因此只有当项目比较大,打包耗时较长的时候才适合使用多进程。
module: {
rules: [
{
test: /.js$/,
use: [
{
loader: 'thread-loader',
options: {
workers: 2 //开启两个进程
}
},
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
cacheDirectory: true
}
}
]
},
]
}
复制代码
多页面打包须要多个入口文件,多个 HtmlWebpackPlugin
产生多个 html
。咱们不可能去手写不少个入口和 HtmlWebpackPlugin
方案: 动态获取 entry
和设置 html-webpack-plugin
数量
// 核心方法
const setMPA = () => {
const entry = {};
const htmlWebpackPlugins = [];
const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js'));
entryFiles.forEach(entryFile => {
const match = entryFile.match(/src\/(.*)\/index\.js/);
const pageName = match && match[1];
entry[pageName] = entryFile;
htmlWebpackPlugins.push(
new HtmlWebpackPlugin({
template: path.join(__dirname, `src/${pageName}/index.html`),
filename: `${pageName}.html`,
chunks: [pageName], //要包含哪些chunk
inject: true, //将chunks自动注入html
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
}),
)
})
return {
entry,
htmlWebpackPlugins
}
}
复制代码
其余具体配置见 webpack实践-mpa-build分支