一、source-map
- 外部map文件
- 错误代码准确信息 和 源代码的错误位置
// 可任意组合
devtool: [inline-|hidden-|eval][nosource-][cheap-[module-]]source-map
inline-source-map
- 只生成一个内联
- 错误代码准确信息 和 源代码的错误位置
hidden-source-map
- 外部map文件
- 不能追踪源代码的错误位置,只能提示到构建后的错误位置
- 只隐藏源代码
eval-source-map
- 每一个文件会生成对应的source-map,以内联方式都在eval中
- 错误代码准确信息 和 源代码的错误位置
nosource-source-map
- 外部map文件
- 错误代码准确信息,但是没有任何构建后代码信息和源代码信息
- 隐藏源代码和构建后的代码
cheap-source-map
- 外部map文件
- 错误代码准确信息 和 源代码的错误位置
- 只能精确到行
cheap-module-source-map
- 外部map文件
- 错误代码准确信息 和 源代码的错误位置
- 支持第三方loader的错误提示
效果对比
- 速度:eval > inline > chheap > ...
- 调试友好:source-map > cheap-module-source-map > cheap-source-map > ...
- 平衡选择
- 开发环境:eval-source-map > eval-cheap-source-map
- 生产环境:source-map / cheap-module-source-map(内联会让代码体积变大)
二、缓存
babel
让第二次打包构建更快
cacheDirectory: true
文件资源缓存
让代码上线运行缓存更好使用
filename: 'css/[name].[contenthash:10][ext][query]'
- hash
- 每次webpack构建时都会生成一个唯一的hash值
- 问题:因为js与css同时使用一个hash值,如果重新打包,会导致所有缓存失效,而又可能只改动了一个文件
- chunkhash
- 根据chunk生成的hash值,如果打包来自于同一个chunk,那么hash值一样
- 问题:因为js与css同属于一个chunk,使用一个hash值
- contenthash
- 根据文件内容生成的hash值,不同文件hash值不一样
三、tree shaking
去除无用代码
- 使用ES6模块
- 开启production模式
- oneOf 在package.json中配置:
sideEffects: false
/*
所有代码都没有副作用,都可以进行tree shaking
问题:可能会把css / @babel/polyfill 文件干掉
可以配置:sideEffects: ["*.css", "*.less"]
*/
四、code split(代码分割)
多入口配置
entry: {
index: './src/js/index.js',
main: './src/js/main.js'
}
配置splitChunks
/*
1、可以自动将node_modules中代码单独打包成一个chunk最终输出
2、自动分析多入口chunk中,有没有公共的文件,如果有会打包成单独的chunk(webpack 有默认的限制配置,比如大小超过20k等)
*/
optimization: {
splitChunks: {
chunks: 'all'
}
}
配置文档:SplitChunksPlugin
import
import(/* webpackChunkName: 'test' */'./main').then().catch()
结合splitChunks配置,import动态导入模块
五、懒加载与预加载
/*
懒加载:当资源被使用时才会去加载
预加载:prefetch会在其他正常加载的资源加载完毕后,浏览器空闲了再去加载资源,使用时直接从prefetch中拿取(会有浏览器版本要求)
*/
import(/* webpackChunkName: 'test', webpackPrefetch: true */'./main').then().catch()
六、PWA
渐进式网络开发应用程序(离线时可访问)
workbox --> workbox-webpack-plugin
渐进式网络应用程序
七、多进程打包
一般作用于耗时的操作,比如:babel-loader
thread-loader
八、externals
防止将某些
import的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies) 外部扩展(Externals)
九、DLL
单独打包,仅打包一次
DLL
十、性能优化总结
- 开发环境优化:HMR、source-map
- 生产环境优化:one-of、source-map、缓存(hash-chunkhash-contenthash)、tree shaking、code split、懒加载/预加载、pwa、external、dll
十一、基础配置
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const WorkboxPlugin = require('workbox-webpack-plugin')
module.exports = {
// 入口文件
entry: './src/index.js',
// 输出
output: {
filename: 'bundle.js', // 输出文件名
path: resolve(__dirname, 'dist'), // 输出路径,__dirname:node.js变量,代表当前文件的目录绝对路径
// assetModuleFilename: 'images/[name].[hash][ext][query]', // 自定义输出文件名 -- 适用于全部
clean: true
},
// loader配置:1.下载 2.使用
module: {
// 不同文件需要单独配置不同的loader
rules: [
{
// 正则表达式匹配
test: /\.css$/i,
// 使用哪些loader:从上到下,从右到左倒序执行数组中的loader
// 多个loader使用use数组
use: [
'style-loader', // 创建style标签,将js中的样式资源添加到head1中
'css-loader' // 将css文件变成commonjs模块加载到js中,内容是 样式字符串
]
},
{
test: /\.less$/i,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
// type: 'asset/resource', // 指定 资源模式 resource
type: 'asset', // webpack 将按照默认条件,自动地在 resource 和 inline 之间进行选择:小于 8kb 的文件,将会视为 inline 模块类型,否则会被视为 resource 模块类型
parser: { // 修改限制
dataUrlCondition: {
maxSize: 8 * 1024 // 4kb
}
},
generator: {
filename: 'images/[name].[hash:10][ext][query]'
}
},
{
test: /\.html$/i,
// 单个loader使用loader
loader: 'html-loader', // 处理img标签路径问题
// generator: {
// filename: '[name][ext]'
// }
}
]
},
// plugins: 1.下载 2.引入 3.使用
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
}),
// pwa
new WorkboxPlugin.GenerateSW({
// 这些选项帮助快速启用 ServiceWorkers
// 不允许遗留任何'旧的' ServiceWorkers
clientsClaim: true,
skipWaiting: true,
}),
],
// webpack-dev-server 在编译之后不会写入到任何输出文件。而是将 bundle 文件保留在内存中
devServer: {
static: './dist'
},
mode: 'development'
}