entry与output
入口是 Webpack 开始构建依赖图的起点,Webpack 会从入口文件开始,递归地分析项目的依赖图。输出指定 Webpack 打包后的文件存放位置和文件名。
javascript
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
},
};
依赖图如下所示 :

loader
Webpack 支持使用 loader 对文件进行预处理。这允许你bundle JavaScript 之外的任何静态资源。
css-loader与style-loader
css-loader
是 Webpack 中的一个加载器(loader),它允许你在 JavaScript 中直接导入 CSS 文件,并将这些 CSS 文件打包到最终的 bundle 中。这种方式与传统的通过 <link>
标签在 HTML 中引入 CSS 文件的方式不同。
实验结构如下:

如果只是单纯的在index.js中引入style.css:
css
#header {
color: blue;
}
.button {
background-color: yellow;
}
javascript
import _ from "lodash";
import "./style.css";
document.getElementById("button1").addEventListener("click", function () {
const el = document.getElementById("header");
el.innerHTML = "Hey i have updated the code !";
const listItems = ["Apple", "orange", "Banana"];
const ul = document.getElementById("shoppingList");
_.forEach(listItems, function (item) {
const tempEl = document.createElement("li");
tempEl.innerHTML = item;
ul.appendChild(tempEl);
});
});
会报错如下:

首先下载npm install --save-dev css-loader style-loader,并且在webpack.config.js中进行配置:
javascript
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.css$/,
use: ["css-loader", "style-loader"],
},
],
},
};
module
是一个关键配置项,用于定义 如何处理项目中不同类型的模块(如 JavaScript、CSS、图片、字体等),其中rules可以设置多种资源的loader,test匹配文件名,use调用对应loader。
为了匹配文件名使用正则表达式,其中/
正表示则表达式的开始和结束符号,\.
表示匹配字符 .
(因为 .
在正则中有特殊含义,所以需要用 \
转义),css表示匹配字符串 css,``$
表示匹配字符串的结尾。)
成功bundle如下:

webpack会隐式插入:

但以上内容还存在问题
我们接着引入clearButton.js与clearButton.css,如下:
javascript
import "./clearButton.css";
const el = document.createElement("button");
el.innerHTML = "Clear";
el.classList.add("button");
el.onclick = function () {
alert("Clear clicked");
};
document.body.appendChild(el);
css
.button {
background-color: red;
}
index.js与index.html如下:
javascript
import _ from "lodash";
import "./style.css";
import "./clearButton";
document.getElementById("button1").addEventListener("click", function () {
console.log("-----------");
const el = document.getElementById("header");
el.innerHTML = "Hey i have updated the code !";
const listItems = ["Apple", "orange", "Banana"];
const ul = document.getElementById("shoppingList");
_.forEach(listItems, function (item) {
const tempEl = document.createElement("li");
tempEl.innerHTML = item;
ul.appendChild(tempEl);
});
});
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1 id="header">Hey this is my first webpack application !!</h1>
<ul id="shoppingList"></ul>
<button id="button1" class="button">Click me</button>
</body>
<script src="/dist/bundle.js"></script>
</html>
会存在以下问题
后面.button覆盖了前面的 !
要解决这个问题修改webpack.config.js, 在 css-loader
中启用了 modules: true
,这会将 CSS 文件中的类名局部化。如下:
javascript
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader", options: { modules: true } },
],
},
],
},
};
如此类名将会发生变化
但是这样仍然存在问题------直接import "xxx".css将会找不到类名。
需要用 这种方式导入css,
javascript
import { button } from "./index.css";
javascript
import { button } from "./clearButton.css";
并且以此种方式对元素进行添加。
javascript
btn1.classList.add([button]);
javascript
el.classList.add([button]);
另外,还能将css类名定义为全局类名,保持其原有的名称。
css
:global(.button) {
background: yellow;
}
img-loader
webpack.config.js中设置如下,在 Webpack 中,type: "asset/resource"
是一种用于处理静态资源(如图片、字体等)的配置方式。如下所示:

javascript
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
assetModuleFilename: "images/[hash][ext]",
clean: true,
},
module: {
rules: [
{
test: /\.(css)$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader", options: { modules: true } },
],
},
{
test: /.(png|jpeg|gif|svg)$/,
type: "asset/resource",
},
],
},
};
图片生成如下:

在代码中,导入这些文件时会返回文件的 URL。
javascript
import logo from "./assets/webpack_logo.png";
javascript
logoEl.src = logo;

补充:
1.assetModuleFilename
:资源文件输出路径
-
作用
全局定义通过资源模块(Asset Modules)处理的文件(如图片、字体、视频等)的输出路径和文件名格式。
-
配置位置
位于
output
配置对象中。
路径格式说明
-
[hash]
: 文件内容的哈希值(避免缓存问题) -
[ext]
: 原始文件扩展名(如.png
)
2.clean
:清理输出目录
-
作用
在每次构建前自动清理
output.path
目录(默认是dist
),删除旧文件,避免残留文件干扰。 -
配置位置
直接作为顶级配置项。
font-loader
webpack.config.js配置如下:
javascript
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
assetModuleFilename: "images/[hash][ext]",
clean: true,
},
module: {
rules: [
{
test: /\.(css)$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader", options: { modules: true } },
],
},
{
test: /.(png|jpeg|gif|svg)$/,
type: "asset/resource",
},
{
test: /.(ttf|woff|woff2)$/,
type: "asset/resource",
},
],
},
};
其中字体文件可以放置于asset/font目录下

引入字体文件
javascript
import "./assets/fonts/Redressed-Regular.ttf";
这样就可以使用该字体了
css
.header {
text-decoration: underline;
color: blue;
font-family: 'Redressed', cursive;
}
其余loader可在官网查看!
plugin
multiple entry
在 Webpack 中,多入口允许你定义多个入口文件,Webpack 会分别处理这些入口,并为每个入口生成独立的打包文件。
javascript
module.exports = {
entry: {
index: "./src/index.js",
product: "./src/products.js",
},
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "dist"),
},
}
1. 多入口 (entry
对象)
-
作用:允许将代码拆分为多个独立的入口文件,每个入口生成一个独立的依赖关系图和打包结果。
-
适用场景:
-
多页面应用(MPA):每个页面有独立的入口和资源。
-
按功能拆分代码:如管理后台和用户端分离。
-
2. 输出占位符 [name]
-
动态替换 :
[name]
会被替换为入口对象的键名(如index
和product
)。 -
生成的文件:
-
dist/index.bundle.js
-
dist/product.bundle.js
-

有问题:现在还需再html中手动链接bundle.js:


Plugin有什么作用
增强webpack

HTML WebpackPlugin
HtmlWebpackPlugin
是 Webpack 生态中一个核心插件,用于 自动化生成 HTML 文件 并 自动注入打包后的 JavaScript/CSS 资源路径。
核心功能
-
自动生成 HTML 文件
基于模板(或默认模板)生成 HTML,自动插入
<script>
和<link>
标签。 -
多入口适配
为每个入口生成独立的 HTML 文件,并精准注入对应的资源。
-
资源路径管理
自动处理带哈希的文件名(如
bundle.[contenthash].js
),避免缓存问题。 -
HTML 优化
支持压缩 HTML、移除注释、排序属性等优化操作。
基础用法
先下载插件
javascript
npm install --save-dev html-webpack-plugin
引入插件
javascript
const htmlWebpackPlugin = require("html-webpack-plugin");
基本配置
javascript
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
plugins: [
new HtmlWebpackPlugin()
]
};
高级配置
多页面应用
javascript
module.exports = {
entry: {
index: './src/index.js',
product: './src/product.js'
},
plugins: [
// 首页
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
chunks: ['index'] // 只注入 index 入口的 JS
}),
// 商品页
new HtmlWebpackPlugin({
template: './src/product.html',
filename: 'product.html',
chunks: ['product'] // 只注入 product 入口的 JS
})
]
};
- template : 用于 指定生成 HTML 文件的模板
- chunks : 用于 控制哪些 chunk 会被注入到生成的 HTML 文件中。
- filename : 指定生成的 HTML 文件名。
产物如下所示:

这样还存在问题:
css和其他资源文件都不在生成的dist中。 我们当然可以手动的移动这些文件到dist目录下,但是我们也可以配置服务器热更新。
首先安装
javascript
npm i --save-dev webpack-dev-server
进行配置
javascript
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
// 确保资源文件路径正确(可选)
assetModuleFilename: "assets/[hash][ext][query]",
},
module: {
rules: [
// 处理 CSS 文件
{
test: /\.css$/,
use: ["style-loader", "css-loader"], // 顺序从右到左执行
},
// 处理图片、字体等资源文件
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|eot|ttf|otf)$/,
type: "asset/resource", // Webpack 5+ 原生资源模块
// 或使用 file-loader(Webpack 4)
// use: "file-loader",
},
],
},
// 配置开发服务器(热更新)
devServer: {
static: {
directory: path.join(__dirname, "dist"), // 服务 dist 目录
},
hot: true, // 启用热更新
open: true, // 自动打开浏览器
},
};
在node脚本中进行配置
javascript
"scripts": {
"build": "webpack --config webpack.config.js --mode development",
"dev": "webpack serve --mode development --open"
},
代码拆分
1. 提取公共代码(SplitChunksPlugin)
javascript
module.exports = {
optimization: {
splitChunks: {
chunks: 'all', // 提取所有类型的 chunk(包括异步和同步)
minSize: 20000, // 文件大于 20KB 才提取
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/, // 提取 node_modules 中的代码
name: 'vendors', // 输出文件名
priority: 10 // 优先级
},
default: {
minChunks: 2, // 至少被引用 2 次才提取
name: 'common',
priority: 5
}
}
}
}
};
生成的文件:

2. 动态导入(Dynamic Imports)
使用 import()
语法动态加载模块,Webpack 会自动将其拆分为单独的 chunk,它不会在初始加载时立即请求模块,而是延迟到实际需要时才加载。其饭返回一个promise:
javascript
// 动态加载模块
button.addEventListener('click', () => {
import('./module.js').then(module => {
module.default();
});
});
生成的文件 :
自定义 chunk 名称 :
使用 webpackChunkName
注释:
javascript
import(/* webpackChunkName: "my-chunk" */ './module.js');
这段代码是 Webpack 的动态导入语法 ,结合了 魔法注释(Magic Comments) ,用于实现 代码拆分(Code Splitting) 。它的核心作用是将 module.js
文件单独打包成一个独立的代码块(chunk),并赋予其一个自定义名称 my-chunk
。
魔法注释:

应用场景 :
在用户交互时加载特定组件:
javascript
button.addEventListener('click', () => {
import('./Modal.js').then(module => {
const Modal = module.default;
Modal.show();
});
});
路由懒加载:
在单页面应用(SPA)中,按需加载路由组件:
javascript
const Home = () => import(/* webpackChunkName: "home" */ './Home.vue');
const About = () => import(/* webpackChunkName: "about" */ './About.vue');
为bundle添加hash
在 Webpack 中,为打包后的文件(如 JavaScript、CSS、图片等)添加 哈希值(Hash) 是一种常见的优化策略。
1. 哈希类型
Webpack 支持以下几种哈希类型:

2. 配置哈希文件名
在 webpack.config.js
中,通过 output.filename
和 output.chunkFilename
配置哈希文件名。
javascript
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: '[name].[contenthash].js', // 入口文件使用 contenthash
chunkFilename: '[name].[contenthash].js', // 动态导入的 chunk 使用 contenthash
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
type: 'asset/resource',
generator: {
filename: 'assets/[name].[contenthash][ext]', // 图片文件使用 contenthash
},
},
],
},
};
3. 生成的文件结构

4. 哈希值的稳定性
-
[hash]
:每次构建都会变化,即使文件内容没有变化。 -
[chunkhash]
:只有 chunk 内容变化时才会变化。 -
[contenthash]
:只有文件内容变化时才会变化。
推荐使用 [contenthash]
,因为它更精确地反映了文件内容的变化。
从js中提取css
将CSS从JavaScript中提取出来并单独作为CSS文件,可以对浏览器加载HTML带来以下好处:
-
缓存和性能改善:
- 当HTML、CSS和JavaScript分离时,浏览器可以缓存CSS文件,从而在访问其他页面时减少加载时间,提高性能。
-
渲染速度提升:
-
CSS文件是渲染阻塞资源,浏览器必须下载并解析CSS后才能渲染页面。
-
通过提取关键CSS(critical CSS)并内联到HTML头部,可以减少初始渲染时间,特别是在网络条件较差的情况下3。
-
1. 核心思路
-
提取 CSS :将 CSS 从 JavaScript 中分离,生成独立的
.css
文件。 -
自动注入 :在 HTML 中自动插入
<link>
标签引用生成的 CSS 文件。
2. 安装依赖
npm install --save-dev mini-css-extract-plugin html-webpack-plugin
3. 配置 Webpack
在 webpack.config.js
中配置以下内容:
javascript
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true, // 自动清理 dist 目录
},
module: {
rules: [
// 处理 CSS 文件
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // 提取 CSS 到独立文件
'css-loader', // 解析 CSS 语法
],
},
// 处理图片、字体等资源文件(可选)
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource', // Webpack 5+ 原生资源模块
generator: {
filename: 'assets/[name].[contenthash][ext]', // 资源文件输出路径
},
},
],
},
plugins: [
// 提取 CSS 到独立文件
new MiniCssExtractPlugin({
filename: 'styles.[contenthash].css', // 输出的 CSS 文件名(带哈希)
}),
// 自动生成 HTML 并注入 CSS/JS
new HtmlWebpackPlugin({
template: './src/index.html', // HTML 模板文件
}),
],
};
4. 项目结构示例

src/index.js
javascript
import './styles.css'; // 导入 CSS 文件
src/styles.css
css
body {
background: #f0f0f0;
font-family: Arial;
}
src/index.html
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My App</title>
<!-- 不需要手动写 <link>,HtmlWebpackPlugin 会自动注入 -->
</head>
<body>
<div id="root"></div>
</body>
</html>
5. 构建结果
运行 npm run build
后,生成的 dist
目录如下:

生成的 dist/index.html:
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My App</title>
<link href="styles.5a6b7c8d.css" rel="stylesheet"> <!-- 自动注入 CSS -->
</head>
<body>
<div id="root"></div>
<script src="bundle.3f9a8b7e.js"></script> <!-- 自动注入 JS -->
</body>
</html>
Shimming
Webpack Shimming 是一种在 Webpack 中处理全局依赖或模块兼容性问题的技术。它的核心作用是为代码提供缺失的依赖项,或者修改模块的行为,使其能够在 Webpack 构建的环境中正常运行。
为什么需要 Shimming?
-
处理全局变量 :某些库依赖全局变量(如
jQuery
的$
),但 Webpack 默认不会将这些变量暴露给模块。 -
兼容旧代码:一些老旧的库可能不符合模块化规范(如 CommonJS、ES Module),需要手动处理。
-
提供缺失的依赖:某些模块可能依赖特定的全局变量或模块,但这些依赖在 Webpack 中不存在。
Shimming 的实现方式
Webpack 提供了多种方式来实现 Shimming:
1. 使用 ProvidePlugin
ProvidePlugin
是 Webpack 内置的插件,用于自动加载模块,并将其注入到每个模块中。
示例:自动加载 jQuery
假设项目中使用了 jQuery
,但不想在每个模块中手动 import $ from 'jquery'
,可以通过 ProvidePlugin
自动注入 $
和 jQuery
。
javascript
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.ProvidePlugin({
$: 'jquery', // 当模块中使用 $ 时,自动加载 jquery
jQuery: 'jquery', // 当模块中使用 jQuery 时,自动加载 jquery
}),
],
};
效果
-
在任何模块中使用
$
或jQuery
时,Webpack 会自动引入jquery
模块。 -
例如:
javascript
// 不需要手动 import $ from 'jquery';
$(document).ready(() => {
console.log('jQuery is ready!');
});
2.使用 externals
externals
是 Webpack 的一个配置选项,用于将某些依赖项排除在打包之外。它的核心作用是告诉 Webpack:"这些依赖项不需要打包到最终的输出文件中,因为它们已经在运行环境中存在了。"
1) 使用 CDN 加载库
在 HTML 中引入 jQuery
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My App</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
</head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
</body>
</html>
在 Webpack 中配置 externals
javascript
module.exports = {
externals: {
jquery: 'jQuery', // 将 jquery 映射为全局变量 jQuery
},
};
在代码中使用 jQuery
javascript
import $ from 'jquery'; // 从全局变量中获取 jQuery
$(document).ready(() => {
console.log('jQuery is ready!');
});
效果
-
Webpack 不会将
jQuery
打包到bundle.js
中。 -
代码中通过
import $ from 'jquery'
获取全局变量jQuery
。
2) 排除第三方库
javascript
module.exports = {
externals: {
react: 'React', // 排除 React
'react-dom': 'ReactDOM', // 排除 ReactDOM
lodash: '_', // 排除 Lodash
},
};
**3.**resolve.alias
resolve.alias
是 Webpack 的一个配置选项,用于为模块路径创建别名(Alias)。它的核心作用是简化模块的导入路径,避免在代码中编写冗长的相对路径,同时也可以解决模块路径冲突的问题。
基本配置
在 webpack.config.js
中配置 resolve.alias
:
javascript
const path = require('path');
module.exports = {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'), // 将 @ 映射为 src 目录
components: path.resolve(__dirname, 'src/components'), // 将 components 映射为 src/components 目录
},
},
};
效果
- 在代码中可以使用别名代替完整路径:
javascript
import MyComponent from '@/components/MyComponent'; // 相当于 src/components/MyComponent
import Button from 'components/Button'; // 相当于 src/components/Button
常见使用场景
1. 简化路径
将常用的目录映射为简短的别名:
javascript
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
components: path.resolve(__dirname, 'src/components'),
utils: path.resolve(__dirname, 'src/utils'),
},
}
2. 解决模块冲突
如果项目中安装了多个版本的库(如 lodash
和 lodash-es
),可以通过别名指定使用哪个版本:
javascript
resolve: {
alias: {
lodash: path.resolve(__dirname, 'node_modules/lodash-es'), // 强制使用 lodash-es
},
}
3. 替换模块
如果某个模块需要替换为自定义实现,可以通过别名指定:
javascript
resolve: {
alias: {
'original-module': path.resolve(__dirname, 'src/custom-module'), // 替换为自定义模块
},
}
结合 TypeScript 使用
如果项目使用 TypeScript,需要在 tsconfig.json
中配置路径映射,以确保 TypeScript 能够正确解析别名。
tsconfig.json
配置
javascript
{
"compilerOptions": {
"baseUrl": ".", // 基础路径
"paths": {
"@/*": ["src/*"], // 将 @ 映射为 src 目录
"components/*": ["src/components/*"] // 将 components 映射为 src/components 目录
}
}
}
Webpack 配置
javascript
{
"compilerOptions": {
"baseUrl": ".", // 基础路径
"paths": {
"@/*": ["src/*"], // 将 @ 映射为 src 目录
"components/*": ["src/components/*"] // 将 components 映射为 src/components 目录
}
}
}
Tree shaking
Tree shaking(摇树优化) 是前端构建工具(如 Webpack、Rollup)中的一种优化技术,用于在打包时 移除未被使用的代码(Dead Code),比如不用。它的名字来源于"摇晃一棵树,让枯叶(无用代码)落下"的比喻。
Tree shaking 生效的条件

配置方式
1. 配置生产模式
javascript
// webpack.config.js
module.exports = {
mode: 'production', // 生产模式自动启用 Tree shaking 和代码压缩
};
2. 标记无副作用的模块
在 package.json
中声明:
javascript
{
"sideEffects": false // 所有文件均无副作用(默认值)
}
Tree shaking 的局限性
-
动态导入无法优化
动态导入(如
import('module')
)的代码可能无法被静态分析。 -
第三方库的兼容性
未使用 ES6 模块的库(如 Lodash)需配合插件(如
babel-plugin-lodash
)或按需引入。 -
副作用代码需手动标记
未正确标记副作用的代码可能被误删,导致运行时错误。
Production vs Development Build

webpack配置文件拆分
在大型项目中,Webpack 配置文件可能会变得非常复杂和冗长。为了提升可维护性和灵活性,通常会将 Webpack 配置文件拆分为多个文件,分别用于不同的环境(如开发环境、生产环境)。
webpack-merge
:用于合并多个配置文件。
webpack.common.js
(公共配置)
javascript
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, '../dist'),
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
type: 'asset/resource',
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
};
webpack.dev.js
(开发环境配置)
javascript
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
static: './dist',
hot: true,
},
});
webpack.prod.js
(生产环境配置)
javascript
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map',
optimization: {
splitChunks: {
chunks: 'all',
},
},
});