概述
本章主要是针对webpack5的基础配置,以基础配置为首开启webpack5的进修
如有疑问可转webpack5官网:webpack.docschina.org/configurati… 或者留下评论
Webpack5配置过程可能出现的问题
- 相关依赖的安装不兼容,不兼容的情况可以尝试调低版本
- webpack5的配置与webpack4的配置有些许不同,可能运用到了webpack4的写法
- plugin、loader的版本与相关依赖有冲突,有的plugin、loader版本与webpack5不兼容
- 注意文件的相对路径是否正确
- 有的配置项有明确的参数规定,需要正确地配置,比如devServer
- plugin在执行的过程中可能会混入不规范的参数到devServer,导致报错,不过这也有可能是webpack相关模块的版本不兼容导致的
相关依赖
//核心依赖如下,可以作为参考,其他的loader、plugin等的依赖自行下载,注意兼容性
"dependencies": {
"@webpack-cli/serve": "^2.0.5",
"webpack-cli": "^5.1.4",
},
"devDependencies": {
"webpack": "^5.39.1",
"webpack-dev-server": "^5.1.0"
},
配置项
mode
// production、development
module.exports = {
mode: 'development',
};
development- 开发模式- 它会启用
更快速的构建速度,因为在开发过程中,开发者通常更关注代码的快速更新和调试,而不是极致的代码优化 - 它不会对代码进行过度的压缩和混淆,代码基本保持原始的格式,方便开发者阅读和调试,减少了构建过程中的时间消耗
- Webpack 会生成更详细的错误信息和源代码映射
source maps,源代码映射是一种将打包后的代码映射回原始源代码的技术,使得在浏览器调试工具中,能够方便地定位到原始代码中的错误位置。 - 设置
devServer选项中的hot: true,搭配Webpack 开发服务器(webpack-dev-server)启用热加载或者热重载 devtool默认值是eval-source-map
- 它会启用
production- 生产模式- 如果不设置
mode或者设置为production,Webpack 会默认对代码进行全面的优化,JavaScript 代码可能会被 TerserPlugin深度压缩,变量名会被缩短,空格和注释会被大量去除,当然也包括提取CSS,devtool默认值是false,不生产source map
- 如果不设置
devtool
// eval、eval-source-map、cheap-eval-source-map...
module.exports = {
devtool:'eval-source-map'
};
eval- 使用
eval()函数来执行每个模块,模代码会在运行时被解析和执行,没有完整的源代码映射source-map,因此构建速度极快,没有source-map精度不够,只能定位到eval包裹的代码内部的错误
- 使用
eval-source-map- 兼顾速度,也有源代码映射,包括文件,综合性强,更
常用
- 兼顾速度,也有源代码映射,包括文件,综合性强,更
cheap-eval-source-map- 比
eval-source-map快,生成源代码映射文件时,主要关注行信息,忽略了列信息,精度不够
- 比
cheap-module-source-map- 不使用
eval加载模块,生成一个简单的source-map,重点关注模块级别的错误定位和行信息。能快速定位模块级别的错误,相比eval更安全
- 不使用
source-map- 生成完整、详细的源代码映射文件,能够将打包后的代码精确地映射回原始源代码的文件、行号和列号,由于生成的文件较为复杂,所有构建速度相对较慢
hidden-source-map- 会生成完整的源代码映射文件,但不会将映射文件作为单独的文件暴露给浏览器,通过特殊的调试工具或方式利用文件定位错误,保护文件信息,比如:浏览器开发者工具
nosource-source-map- 生成的源代码映射文件只包含错误位置信息,不包含原始源代码内容,可以定位错误在原始文件中的位置,但无法查看原始源代码,安全,最大程度保护源代码
entry
单入口
module.exports = {
entry: {
main: './src/main.js',
},
};
多入口
module.exports = {
entry: {
main: './src/main.js',
vendor: './src/vendor.js' //可能用于单独打包第三方库或公共的依赖模块
},
};
动态入口配置
module.exports = {
entry: () => {
const entryPoints = {}; // 根据某些条件动态添加入口点
if (process.env.NODE_ENV === 'development') {
entryPoints.dev = './src/dev - entry.js';
}else {
entryPoints.prod = './src/prod - entry.js';
}
return entryPoints;
},
};
};
output
module.exports = {
output: {
// 加上hash值,使用哈希值可以确保在文件内容改变时,
//文件名也随之改变,方便浏览器缓存更新后的文件
filename: '[name].[contenthash].js',
//指定打包文件的目录
path: path.resolve(__dirname, 'dist'),
//不使用箭头函数
environment: {
arrowFunction: false
},
//表示打包后的文件在浏览器中可以通过根路径来访问
publicPath: '/',
//用于配置资源模块(如图片、字体等)的输出路径和文件名
assetModuleFilename: 'assets/[hash][ext]',
},
};
cache
module.exports = {
//主要针对整个 Webpack 构建过程进行缓存优化
cache: {
//type: 'memory'
type: 'filesystem',
cacheDirectory: path.resolve(__dirname, '.cache/webpack'),
buildDependencies : {
// 构建依赖缓存
// Webpack 配置文件本身
config: [__filename]
}
},
};
type: 'memory'- 缓存类型将缓存数据存储在
内存中,当 Webpack 需要重新使用已经处理过的模块或其他构建资源时,可以直接从内存中获取,而不需要重新计算或加载。它的优点是速度非常快,因为内存访问速度远远高于磁盘访问速度。在构建过程结束后,缓存数据就会丢失,因为内存是临时存储介质,所以这种类型适用于在一次构建过程中需要频繁复用模块的情况,例如在开发过程中的热更新场景下,当文件频繁修改但模块依赖关系变化不大时,可以提高构建效率。
- 缓存类型将缓存数据存储在
type: 'filesystem'- 缓存类型将缓存数据存储在
文件系统中,在构建过程中,Webpack 会将模块信息、编译后的代码等缓存数据以文件的形式存储在指定的缓存目录(通过cacheDirectory属性指定)。这样,在下次构建时,如果模块没有变化,就可以直接从文件系统中读取缓存数据,而不需要重新处理模块。这种缓存方式的优点是缓存数据可以在多次构建过程中持久保存,适用于长时间的开发周期或者持续集成 / 持续部署(CI/CD)环境。不过,由于涉及文件系统的读写操作,它的速度相对内存缓存会慢一些。
- 缓存类型将缓存数据存储在
module
module.exports = {
//指定webpack打包时使用的模块
module: {
//指定加载的规则
rules: [
{
test: /\.vue$/,
use: [
{
loader: 'thread-loader',
}, {
loader: 'vue-loader',
options: {
presets: ['@vue/babel-preset-jsx'],
cacheDirectory: true
}
}]
},
{
test: /\.(js|jsx)$/,
use: [
{
loader: 'thread-loader',
},
{
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
]
},
{
test: /\.(jpg|jpeg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'images/',
publicPath: 'images/'
}
}
]
},
};
test指定了哪些文件会被当前规则所处理,为了减少重复loader的加载,将js和jsx放一起exclude指定哪些文件或目录不应该应用当前规则include指定哪些文件或目录应该应用当前规则use是一个数组或一个对象,指定处理匹配文件的加载器(loader)或加载器链loader将不同类型的文件转换为 Webpack 能够理解和处理的模块的工具optionspresets预先指定好的转换或处理规则cacheDirectory对文件进行缓存,下次处理时会先检查缓存
plugins
const { VueLoaderPlugin } = require('vue-loader');
module.exports = {
plugins: [
new VueLoaderPlugin(),
],
};
- 在 Webpack 中,插件(Plugin)是一个具有
apply方法的 JavaScript 类对象。可以引入现有的plugin也可以自定义,插件可以用来扩展 Webpack 的功能,它能够在 Webpack 构建过程的各个阶段(如编译开始、模块创建、打包完成等)插入自定义的逻辑,读取compiler信息。
devServer
module.exports = {
devServer: {
static: {
directory: path.join(__dirname, 'dist'),
publicPath: '/'
},
port: 8080, 端口号
// liveReload : true,
hot: true,
open: true,
historyApiFallback: true,
},
};
devServer是Webpack 开发服务器相关的配置选项liveReload热重载 刷新页面hot热加载or热更新 更新模块historyApiFallback开发服务器会将任何没有匹配到实际文件的请求都重定向到index.html,404的时候跳转到index.htmlopen启动开发服务器后自动打开默认浏览器
resolve
module.exports = {
resolve: {
// 只在node_modules目录下查找模块
modules: ['node_modules', 'src'],
// includes:['dist'],
// 自动补全的文件扩展名
extensions: [
'.ts', '.js', '.json', '.vue', '.tsx', '.css', '.sass', '.less'
],
alias: {
'@': path.resolve(__dirname, 'src')
}
},
};
alias是一个对象,用于为模块路径创建别名,通过设置别名,可以使用更简短、更清晰的路径来引用模块,用@替代srcextensions告诉 Webpack 在解析导入的模块时自动尝试添加的文件扩展名modules告诉 Webpack 在解析模块时应该去哪些目录中查找
optimization
module.exports = {
optimization: {
// 当这个配置应用后,在打包后的代码中,模块 ID 的分配更加稳定。
moduleIds: 'deterministic',
// 开启代码压缩
minimize: true,
runtimeChunk: 'single',
// 代码分割
splitChunks: {
chunks: 'all',
minSize: 29.3 * 1024,
maxSize: 50 * 1024,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
},
minimizer: [
new TerserPlugin({
// 设置需要进行压缩优化的文件范围,这里可以是正则表达式等,示例为匹配所有.js文件
test: /\.js$/,
// 设置包含的文件范围,可省略,若设置则需符合特定格式,这里示例为包含src目录下所有文件
include: /src/,
// 设置排除的文件范围,可省略,若设置则需符合特定格式,这里示例为排除node_modules目录下所有文件
exclude: /node_modules/,
// 设置terser的具体压缩选项,这里可以根据需求详细设置,比如压缩等级等
terserOptions: {
// 去除警告信息
warnings: false,
compress: {
warnings: false,
// 去掉console.log
drop_console: true,
// 去除debug
drop_debugger: true,
}
},
// 是否提取注释,可设置为布尔值或对象以进行更精细的设置,这里示例为不提取注释
extractComments: false,
// 是否启用并行压缩,可设置为布尔值,这里示例为启用并行压缩
parallel: true,
}),
]
},
};
minimize代码压缩,减小代码文件的大小,以提高网页的加载速度minimizer用于配置具体的代码压缩工具和相关选项,有的工具功能差不多,没必要都用,比如TerserPlugin和TerserWebpackPlugin功能很相似,TerserPlugin的terserOptions配置了minify函数执行时的压缩选项。compress选项用于控制各种压缩操作,当 Webpack 在优化阶段调用minify函数时,它会根据compress选项对 JavaScript 代码进行压缩,比如删除console语句,删除所有注释,删除debugsplitChunks代码分割,将代码分割成多个较小的块(chunks),以便更好地进行缓存和按需加载runtimeChunk用于将运行时代码(如模块加载、解析等相关的代码)提取到一个单独的块中。在 Webpack 构建过程中,会生成一些用于管理模块加载和运行的代码,将这些代码提取出来可以方便地进行缓存和更新moduleIds: 'deterministic'是一种用于控制模块标识符(module ID)生成方式的设置,Webpack 会根据模块的相对路径和一些其他确定的因素(如文件名等),以一种确定性的方式生成模块标识符,模块标识符是 Webpack 用来唯一标识每个模块的字符串或数字,在模块的加载、缓存和其他相关操作中起着关键作用
Webpack5 启动
//--mode development --progress --cache --profile...
"scripts": {
"buildWebpack": "webpack --config webpack.config.js",
},
以下参数也能在
webpack.config.js文件中配置
--mode development- 假如命令行
--mode development,webpack.config.js文件是mode:production,命令行优先级更大,它会覆盖在webpack.config.js文件中配置的mode选项
- 假如命令行
--config- 后面跟webpack文件名,
webpack.config.js
- 后面跟webpack文件名,
--progress- 启用进度条显示打包进度
--watch- 监控文件变化并自动重新打包(用于开发环境)
-o dist/custom - output或者--output - path dist/custom - output- 指定输出目录
--cache- 控制缓存(提高重新打包速度)
--profile- 生成性能分析报告(用于优化打包性能)
运行代码:npm run buildWebpack
完整代码
const path = require('path') //拼写路径信息
// 优化代码压缩
const TerserPlugin = require('terser-webpack-plugin');
const webpack = require('webpack');
//webpack 中的所有配置信息都应该写在 module.exports 中
const { VueLoaderPlugin } = require('vue-loader');
const HTMLWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 去掉注释 去掉log
// const TerserWebpackPlugin = require('terser-webpack-plugin');
// 将 CSS 从 JavaScript 文件中提取出来,生成独立的 CSS 文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 为模块创建了一个缓存 不兼容
// const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
// 打包性能监控插件
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// 自制插件查看devServer 变化
//const MyPlugin = require('./MyPlugin')
// 显示进度条
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
// const chalk = require('chalk');
// 不适用element plus 自动插入插件 因为会引起devServer的属性变更
// const AutoImport = require('unplugin-auto-import/webpack')
// const Components = require('unplugin-vue-components/webpack')
// const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
const webpackConfig = {
mode: 'development',
devtool: 'eval-source-map',
// devtool: false,
//指定入口文件
entry: './src/main.ts',
//指定打包文件所在目录
output: {
// 加上hash值,使用哈希值可以确保在文件内容改变时,文件名也随之改变,方便浏览器缓存更新后的文件
filename: '[name].[contenthash].js',
//指定打包文件的目录
path: path.resolve(__dirname, 'dist'),
//打包后文件的文件
environment: {
arrowFunction: false
},
publicPath: '/',//表示打包后的文件在浏览器中可以通过根路径来访问
assetModuleFilename: 'assets/[hash][ext]',//用于配置资源模块(如图片、字体等)的输出路径和文件名
},
cache: {
type: 'filesystem',
// type: "memory",
// 选项仅当 cache.type 被设置成 'filesystem' 才可用
cacheDirectory: path.resolve(__dirname, '.cache/webpack'),
buildDependencies: {
// 配置哪些依赖发生变化时需要重新构建缓存
// webpack.config.js文件本身发生变化时,才会重新构建缓存
config: [__filename]
}
},
//指定webpack打包时使用的模块
module: {
//指定加载的规则
rules: [
{
test: /\.vue$/,
use: [
{
loader: 'thread-loader',
}, {
loader: 'vue-loader',
options: {
presets: ['@vue/babel-preset-jsx'],
cacheDirectory: true
}
}]
},
{
test: /\.(js|jsx)$/,
use: [
{
loader: 'thread-loader',
},
{
loader: 'babel-loader',
options: {
// 当 Webpack 解析模块之间的依赖关系时,
// 会将这些关系存储在cacheDirectory中。
// 如果下次构建时模块的依赖关系没有改变,
// Webpack 可以直接从缓存中获取这些信息,而不需要重新解析
cacheDirectory: true
}
}
]
},
{
test: /\.(ts|tsx)$/,
use: [
// thread-loader 可能与 webpack 版本冲突
// {
// loader: 'thread-loader',
// },
{
loader: 'ts-loader',
}
],
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
}
]
},
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.(jpg|jpeg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'images/',
publicPath: 'images/'
}
}
]
},
//配置webpack插件
plugins: [
//new MyPlugin(),
new VueLoaderPlugin(),
// 在每次构建之前,自动清理之前构建生成的文件。
// 这可以确保输出目录只包含最新构建的文件,
// 避免旧文件的积累导致混乱。
new CleanWebpackPlugin(
{
cleanOnceBeforeBuildPatterns: ['dist']
}
),
new webpack.DefinePlugin({
'__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': JSON.stringify(false),
}),
// 自动生成 HTML 文件,
// 并将打包后的 JavaScript 和 CSS 文件自动引入到 HTML 中。
// 它简化了 HTML 文件与 Webpack 打包输出之间的关联,
// 确保在每次构建后,HTML 文件能够正确引用最新的打包资源。
new HTMLWebpackPlugin({
template: 'index.html', //相对路径
filename: 'index.html'
}),
new MiniCssExtractPlugin({
filename: 'styles.css'
}),
// new HardSourceWebpackPlugin()
// new webpack.HotModuleReplacementPlugin(),
// 打包性能监控
// new BundleAnalyzerPlugin(),
// 自动引入element plus
// AutoImport({
// resolvers: [ElementPlusResolver()],
// }),
// Components({
// resolvers: [ElementPlusResolver()],
// }),
new ProgressBarPlugin({
format: 'build [:bar] :percent :elapsed seconds :msg',
customTotal: 100,
width: 30
})
],
devServer: {
static: {
directory: path.join(__dirname, 'dist'),
publicPath: '/'
},
// port: 8080,
// liveReload: true,
hot: true,
// open: true,
historyApiFallback: true,
},
// devServer: finalDevServerConfig,
//用来设置引用模块
resolve: {
// 只在node_modules目录下查找模块
modules: ['node_modules', 'src'],
// includes:['dist'],
// 自动补全的文件扩展名
extensions: [
'.ts', '.js', '.json', '.vue', '.tsx', '.css', '.sass', '.less'
],
alias: {
'@': path.resolve(__dirname, 'src')
}
},
//...其他配置
optimization: {
// 当这个配置应用后,在打包后的代码中,模块 ID 的分配更加稳定。
moduleIds: 'deterministic',
runtimeChunk: 'single',
// 开启代码压缩
minimize: true,
// 代码分割
splitChunks: {
chunks: 'all',
minSize: 29.3 * 1024,
maxSize: 50 * 1024,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
},
minimizer: [
new TerserPlugin({
// 设置需要进行压缩优化的文件范围,这里可以是正则表达式等,示例为匹配所有.js文件
test: /\.js$/,
// 设置包含的文件范围,可省略,若设置则需符合特定格式,这里示例为包含src目录下所有文件
include: /src/,
// 设置排除的文件范围,可省略,若设置则需符合特定格式,这里示例为排除node_modules目录下所有文件
exclude: /node_modules/,
// 设置terser的具体压缩选项,这里可以根据需求详细设置,比如压缩等级等
terserOptions: {
// 去除警告信息
warnings: false,
compress: {
warnings: false,
// 去掉console.log
drop_console: true,
// 去除debug
drop_debugger: true,
}
},
// 是否提取注释,可设置为布尔值或对象以进行更精细的设置,这里示例为不提取注释
extractComments: false,
// 是否启用并行压缩,可设置为布尔值,这里示例为启用并行压缩
parallel: true,
// 是否进行压缩操作,可设置为布尔值,这里示例为进行压缩操作
// minify: (file, sourceMap) => {
// // 自定义minify函数
// const terser = require('terser');
// return terser.minify(file, {
// // 这里是传递给terser.minify的参数,如sourceMap等
// sourceMap: sourceMap
// });
// },
}),
// new TerserWebpackPlugin({
// terserOptions: {
// compress: {
// drop_console: true, // 去掉console.log语句
// pure_funcs: ['console.log'], // 另一种去掉console.log的方式,可以和上面的选项配合使用
// warnings: false, // 关闭压缩过程中的警告信息
// dead_code: true, // 去除无用代码,可用于去掉注释等
// },
// output: {
// comments: false, // 去掉输出文件中的注释
// }
// }
// })
]
},
}
module.exports = webpackConfig