webpack基础配置
开发准备
安装
npm install webpack webpack-cli -D
运行
# webpack详细打包信息
webpack --stats detailed
需要全局安装 webpack 使用,没有全局 webpack 时,使用npx webpack
来执行
自定义配置
自定义配置文件名:webpack.config.js

打包入口:entry
打包出口:output
打包模式:mode
插件:plugins
加载器:loader
注意:output 输出路径必须是绝对路径
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
clean: true, // 每次打包前清除dist内残留文件
},
mode: "none",
};
plugins 插件
插件作为 webpack 核心功能之一,为 webpack 拓展各种各样不同的功能。
以 html-webpack-plugin 为例,该插件实现 webpack 的打包结果生成一个 html 文件到指定位置,用于静态服务器部署访问。
npm install html-webpack-plugin -D
plugins: [
new HtmlWebpackPlugin({
template: "./index.html",
filename: "app.html",
inject: "body",
}),
];
mode 选项
development
mode: 'development',
使用 source map 定位错误的准确位置
devtool: "inline-source-map";
使用 watch 实时打包最新修改的文件
控制台输出:
npx webpack --watch
webpack-dev-server
开发模式静态打包目录
devServer: {
static: "./dist";
}
控制台输出
npm install webpack-dev-server -D
阶段性配置代码
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
clean: true,
},
mode: "development",
devtool: "inline-source-map",
plugins: [
new HtmlWebpackPlugin({
template: "./index.html",
inject: "body",
}),
],
devServer: {
static: "./dist",
},
};
资源模块
resource
配置图片资源的引入、打包、路径控制
output: {
filename: "bundle.js",
path: path.resolve(__dirname, './dist'),
clean: true,
assetModuleFilename: "images/[contenthash][ext]"
}
module: {
rules: [
{
test: /\.png$/,
type: 'asset/resource',
generator: {
filename: 'images/[contenthash][ext]'
}
}
]
}
generator 优先级高于 assetModulFilename
inline
{
test: /\.svg$/,
type: 'asset/inline'
}
生成的 url 为 dataURL BASE64 格式
source
{
test: /\.txt$/,
type: '/asset/source'
}
导出源代码
5.4 asset
{
test: /\.jpg$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 4 * 1024 * 1024 //当jpg文件小于4M时自动生成base64,大于4M才生成资源文件
}
}
}
小结
在 webpack 5 之前,通常使用:
raw-loader 将文件导入为字符串
url-loader 将文件作为 data URI 内联到 bundle 中
file-loader 将文件发送到输出目录
webpack5 增加了资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:
asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。
asset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现。
asset/source 导出资源的源代码。之前通过使用 raw-loader 实现。
asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现。
loader 加载器
css-loader
npm install style-loader css-loader less-loader -D
{
test: /\.(css|less)$/,
use: ['style-loader', 'css-loader', 'less-loader']
}
use 数组逆序,链式调用(上述的 css-loader 调用顺序为 less-loader -> css-loader -> style-loader)
抽离和压缩 css
抽离
mini-css-extract-plugin:对于 webpack4 它是一个第三方插件,而 webpack5 直接默认导出这个插件对象了,写法略有不同
webpack4,需要先安装再配置
npm install mini-css-extract-plugin -D
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
plugins: [
new HtmlWebpackPlugin({
template: './index.html',
inject: 'body'
}),
new MiniCssExtractPlugin({
filename: 'styles/[contenthash].css'
})
],
module: {
rules: [
{
test: /\.(css|less)$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
}
webpack5,直接引入无需安装
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
// ...
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "style.css",
}),
],
};
打包后生成独立的 css 文件
压缩
npm install css-minimizer-webpack-plugin -D
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin');
mode: 'production',
optimization: {
minimizer: [
new CssMinimizerWebpackPlugin()
]
}
加载 images 图像
在 css 的 background 属性中按相对路径添加图片,自动生成相应的 dataURLbase64 图像数据
6.4 加载 font 字体
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource'
}
加载数据
npm install csv-loader xml-loader -D
{
test: /\.(scv|tsv)$/,
use: 'csv-loader'
},
{
test: /\.xml$/,
use: 'xml-loader'
}
自定义 JSON 模块 parser
适用文件名:toml yaml json5
npm install toml yaml json5 -D
{
test: /\.toml$/,
type: 'json',
parser: {
parse: toml.parse
}
},
{
test: /\.yaml$/,
type: 'json',
parser: {
parse: yaml.parse
}
},
{
test: /\.json5$/,
type: 'json',
parser: {
parse: json5.parse
}
}
babel-loader
npm install babel-loader @babel/core @babel/preset-env -D
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
注意:promise 语法需要安装 regeneratorRuntime ,否则 webpack-dev-server 运行报错
regeneratorRuntime:该插件用于兼容 async/await 的语法。
npm install @babel/runtime @babel/plugin-transform-runtime -D
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
[
'@babel/plugin-transform-runtime'
]
]
}
}
}
代码分离方法
入口起点:使用 entry 配置手动地分离代码
防止重*:使用 Entry dependencies 或者 SplitChunksPlugin 去重和分离代码
动态导入:通过模块的内联函数调用来分离代码
1.入口起点
如果入口 chunks 之间包含重复的模块,那些重复模块都会被引入到各个 bundle 中
这种方法不够灵活,并且不能将核心应用程序逻辑进行动态拆分代码。
2.防止重复
(1)配置 dependOn 选项,这样可以在多个 chunk 之间共享模块
entry: {
index: {
import: './src/index.js',
dependOn: 'shared'
},
another: {
import: './src/another-module.js',
dependOn: 'shared'
},
shared: 'lodash'
},

(2)SplitChunksPlugin
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
optimization: {
minimizer: [
new CssMinimizerWebpackPlugin()
],
splitChunks: {
chunks: "all"
}
}
(3)使用 CommonsChunkPlugin
const path = require("path");
const webpack = require("webpack");
module.exports = {
entry: {
index: "./src/index.js",
another: "./src/page.js",
},
plugins: [
new webpack.optimize.CommonChunkPlugin({
name: "common", // 指定公共bundle的名称
}),
],
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "dist"),
},
};
貌似是 webpack4 的语法,5 没有该方法
3.动态导入,按需加载
import('lodash') => { }
// src/index.js
function getComponent() {
return import(/* webpackChunkName: 'lodash' */ "lodash")
.then((_) => {
var element = document.createElement("div");
element.innerHTML = _.join(["Hello", "webpack"], " ");
return element;
})
.catch((error) => "An error occurred while loading the component");
}
getComponent().then((component) => {
document.body.appendChild(component);
});
应用:
魔法注释
/* webpackChunkName: 'math' */
预获取(网络空闲时才去加载)
/* webpackChunkName: 'math', webpackPrefetch: true */
预加载(与主模块并行加载)
/* webpackChunkName: 'math', webpackPreload: true */
调整输出文件夹与文件名
1.输出文件名,增加哈希实时缓存
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, './dist')
}
2.缓存第三方库
optimization: {
minimizer: [
new CssMinimizerWebpackPlugin()
],
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
3.所有 js 文件放一个文件夹
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, './dist')
}
环境配置拆分
1.公共路径 publicPath
更改资源引用的路径,默认为相对路径
output: {
filename: 'scripts/[name].[contenthash].js',
path: path.resolve(__dirname, './dist'),
clean: true,
assetModuleFilename: "images/[contenthash][ext]"
publicPath: 'http://localhost:8080/'
},
2.环境变量
将 module.exports 写为箭头函数,参数为 env
npx webpack --env production --env goal=local
module.exports = (env) => {
console.log(env.goal)
return {
entry: {
index: './src/index.js',
another: './src/another-module.js'
}
},
output: {
filename: 'scripts/[name].[contenthash].js',
path: path.resolve(__dirname, './dist'),
clean: true,
assetModuleFilename: "images/[contenthash][ext]",
}
}

3.拆分配置文件
开发环境不需要的配置:文件名哈希值,publicPath、压缩
开发环境需要的配置:devTool、devServer
npm 脚本
package.json 文件:
"scripts": {
"start": "webpack serve -c ./config/webpack.config.dev.js",
"build": "webpack -c ./config/webpack.config.prod.js"
}
最终配置
拆分与合并
config.common
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const toml = require("toml");
const yaml = require("yaml");
const json5 = require("json5");
module.exports = {
entry: {
// index: {
// import: './src/index.js',
// dependOn: 'shared'
// },
// another: {
// import: './src/another-module.js',
// dependOn: 'shared'
// },
// shared: 'lodash'
index: "./src/index.js",
another: "./src/another-module.js",
},
output: {
path: path.resolve(__dirname, "../dist"),
clean: true,
assetModuleFilename: "images/[contenthash][ext]",
},
plugins: [
new HtmlWebpackPlugin({
template: "./index.html",
inject: "body",
}),
new MiniCssExtractPlugin({
filename: "styles/[contenthash].css",
}),
],
module: {
rules: [
{
test: /\.png$/,
type: "asset/resource",
generator: {
filename: "images/[contenthash][ext]",
},
},
{
test: /\.svg$/,
type: "asset/inline",
},
{
test: /\.txt$/,
type: "/asset/source",
},
{
test: /\.jpg$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 4 * 1024 * 1024, //当jpg文件小于4M时自动生成base64,大于4M才生成资源文件
},
},
},
{
test: /\.(css|less)$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: "asset/resource",
},
{
test: /\.(scv|tsv)$/,
use: "csv-loader",
},
{
test: /\.xml$/,
use: "xml-loader",
},
{
test: /\.toml$/,
type: "json",
parser: {
parse: toml.parse,
},
},
{
test: /\.yaml$/,
type: "json",
parser: {
parse: yaml.parse,
},
},
{
test: /\.json5$/,
type: "json",
parser: {
parse: json5.parse,
},
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
plugins: [["@babel/plugin-transform-runtime"]],
},
},
},
],
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all",
},
},
},
},
};
config.dev
module.exports = {
output: {
filename: "scripts/[name].js",
},
mode: "development",
devtool: "inline-source-map",
devServer: {
static: "./dist",
},
};
config.prod
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
output: {
filename: "scripts/[name].[contenthash].js",
publicPath: "http://localhost:8080/",
},
mode: "production",
optimization: {
minimizer: [new CssMinimizerWebpackPlugin(), new TerserPlugin()],
},
performance: {
hints: false,
},
};