在某个时候,可能很多年后,像这样的针对初学者的 webpack 教程将是完全没有必要的。但是目前需要webpack这样的工具来实现良好的代码维护和高性能。
在此站点上的先前教程中,我介绍了 Parcel,它是 JavaScript 打包程序场景中最近添加的一个。然而,在本文中,我将介绍许多人认为前端捆绑的行业标准:webpack(通常用小写字母“w”书写)。

即使您目前正在使用另一种捆绑解决方案,了解 webpack 也会有所帮助,因为您很可能会继承一个使用它的项目,或者您将申请一份需要它的工作。无论哪种情况,本 webpack 教程都可以让您快速上手。
📚 目录:
- 什么是网页包?#
- 安装网络包#
- 设置要捆绑的项目#
- 将脚本安装到 bundle #
- 创建一个包#
- 配置 webpack 生成 HTML #
- 在 webpack 中启用开发模式#
- 清理dist文件夹#
- 使用 npm 脚本运行 webpack #
- 使用热重载安装和运行服务器#
- webpack 实现的最终示例#
什么是网页包?

简而言之,webpack是一个开源的 JavaScript 模块打包器。在 GitHub 上有超过 5 万颗星,它是这个领域的领导者。
Webpack 允许您在开发中将 JavaScript 拆分为单独的模块(更好地维护),同时允许您将这些模块编译为生产中的单个包(更好地提高性能)。
从历史上看,许多新手或经验不足的开发人员由于 webpack 的复杂性而回避它。这在某种程度上可能仍然是正确的,但是 webpack 继续接收定期更新并且每个版本都变得更好。webpack 团队于 2020 年 10 月发布了5.0.0 版本,此后进行了多次增量更新。
值得注意的是,webpack 4.0.0是第一个不需要webpack.config.js文件来捆绑项目的 webpack 版本。仅这一点就使新开发人员更容易开始使用它。
安装网页包
安装 webpack 5 需要 Node 10.13.0 或更高版本,因此如果您有一段时间没有更新 Node,则必须在安装 webpack 之前更新。
webpack 文档强烈建议在本地而不是全局安装 webpack。这意味着您将在每个项目上单独安装它,而不是在每个项目上使用一个全局安装。对于单独的本地安装,您将能够根据需要升级(或不升级)每个安装。
为了跟随这个 webpack 教程,创建一个项目目录,你将使用它来运行我将要介绍的各种命令。一旦项目目录准备就绪,您将运行以下两个命令(第一个确保您在目录中):
cd webpack-example
npm init -y
在本例中,我将示例项目的根文件夹命名为webpack-example。您可以随意命名。该npm init -y命令使用 npm 的默认设置初始化目录,这会创建一个package.json文件。
接下来,我将安装 webpack 和 webpack CLI
npm install webpack webpack-cli --save-dev
一旦我将这两个包安装为项目的依赖项,我的package.json文件将如下所示:
{
"name": "webpack-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.27.2",
"webpack-cli": "^4.5.0"
}
}
代码语言: JSON / JSON with Comments ( json )
请注意,两个包 (webpack和webpack-cli) 现在列为靠近底部的依赖项。这个项目现在或多或少准备好开始使用 webpack 作为它的打包器,所以让我们在这个 webpack 教程中付诸实践。
设置要捆绑的项目
在目前的状态下,这个项目还没有什么可以捆绑的。因此,让我们向其中添加一些内容来演示一个简单的捆绑过程是如何发生的。仅此一项就足以让您开始使用 webpack,但之后我将介绍您可以添加的一些配置,以使 webpack 更加强大。
在与我的文件相同的位置package.json,我将添加以下内容:
- 一个文件夹叫
src - 里面的一个
index.html文件src - 里面的一个
index.js文件src dist文件夹
如果您想按照本 webpack 教程中的步骤进行操作,请继续添加这些内容。webpack 文档很好地解释了src(source) 和dist(distribution) 文件夹的用途(虽然这不是特定于 webpack,但更多关于一般的捆绑和构建过程):
“源”代码是我们将编写和编辑的代码。“分发”代码是浏览器将显示的构建过程的最小化和优化输出。
理想情况下,我的捆绑包设置会在dist我每次创建捆绑包时清空该文件夹。稍后我将对此进行更多介绍,但现在我将专注于编辑文件夹中的文件src(编辑总是在此处进行)。
首先,我需要向index.html和中添加一些内容index.js。该index.html文件自然可以包含任何内容。我通常会将所有网站内容包含在src目录中,包括样式表、图像等,但这个简单的示例是为了演示 webpack 的功能。
index.html传统上,当您想要在项目中添加一个或多个库作为依赖项时,您会使用单独的<script>元素一个接一个地将它们列在页面底部。您还将包括使用那些其他依赖项的自定义 JavaScript。这就是像 webpack 这样的工具可以提供帮助的地方,因为您不仅可以避免手动将脚本添加到您的页面,还可以添加它们、捆绑它们以进行优化,有时甚至可以按需加载它们。
安装脚本以捆绑
我将不再使用传统的非最佳方法来添加和合并脚本,而是使用 npm 安装我的依赖项,然后使用 webpack 来捆绑它们。出于演示目的,我将使用两个 JavaScript 实用程序库:
- Flicking——一个 JavaScript 轮播
- Panzoom – 一个平移/缩放框架
需要明确的是:webpack 不需要这些;它们是我随机选择的一些示例实用程序,用于演示 webpack 的捆绑功能。您的项目将包括不同的库和实用程序,可能是更大的工具,如React、Vue或用于跨浏览器JavaScript 的 Babel.js。
要使用我选择的实用程序,我必须安装它们,所以我要先安装它们:
npm install panzoom --save
npm install @egjs/flicking --save
代码语言: CSS (css )
在这种情况下,我使用--save标志而不是--save-dev因为我希望将它们作为我的生产构建的一部分。当我安装 webpack 时,我将它安装为开发人员依赖项,因此 webpack 不会成为我的生产构建的一部分。
现在我的部分package.json下面附加了以下内容devDependencies:
"dependencies": {
"@egjs/flicking": "^3.8.1",
"panzoom": "^9.4.1"
}
代码语言: JavaScript (javascript )
然后我可以在我的index.html文件中包含我的两个实用程序将与之交互的元素。例如,旋转木马需要 HTML 中的包装器和“面板”元素,而缩放实用程序需要一个或多个该实用程序的 API 所针对的 HTML 元素。
为了证明这些实用程序已成功捆绑,我将在文件夹index.js中的文件中添加以下内容src:
import panzoom from 'panzoom';
import flicking from '@egjs/flicking';
console.log(panzoom);
console.log(flicking);
代码语言: JavaScript (javascript )
在幕后,webpack 将识别这两个import语句并在我的文件夹中查找这两个依赖项node_modules。这些console()命令只是为了证明捆绑成功并且两个导入都按预期工作。
创建一个包
Webpack 使用一个名为 in 的特定 JavaScript 文件package.json作为入口点。入口点向 webpack 指示使用哪个模块来构建项目的依赖关系图。依赖图本质上是应用程序所需的每个模块的映射。
如果我愿意,我可以指定一个自定义入口点,但我更喜欢使用 webpack 并根据需要进行尽可能少的配置,所以我将使用默认入口点:./src/index.js。有关更改入口点的信息,请参阅文档。
现在我已经安装了一些依赖项,我可以使用 webpack 构建我的包。我可以通过在我的项目目录中运行以下命令来完成此操作:
npx webpack
运行此命令告诉 webpack 使用指定的入口点捆绑我的 JavaScript 依赖项,dist文件夹将生成输出。在这种情况下,main.js是我的应用程序将使用的唯一生成文件。尽管我index.html在文件夹中包含了一个文件src,但 webpack 还没有对它做任何事情,所以 webpackmain.js到目前为止只生成了。
main.js如果我在文件夹中打开dist,我会找到一个缩小的文件,其中包含我的项目中指定的所有依赖项(在本例中,是两个实用程序以及这两个依赖的任何实用程序)。
⚠️ 注意:如果您在 CLI 中收到有关未设置选项的警告mode,请暂时不要担心。稍后我将向您展示如何更正该错误。
配置 webpack 生成 HTML
如前所述,我的文件在捆绑过程中index.html没有出现在目录中。dist如果我愿意,我可以手动执行此操作,但这违背了使用像 webpack 这样的工具来简化我的构建的目的。
为了解决这个问题,我将安装一个名为HtmlWebpackPlugin的插件:
npm install html-webpack-plugin --save-dev
我的 devDependencies 中将package.json反映更改:
"devDependencies": {
"html-webpack-plugin": "^5.3.1",
"webpack": "^5.27.2",
"webpack-cli": "^4.5.0"
},
代码语言: JavaScript (javascript )
虽然我可以在没有任何手动配置的情况下使用 webpack,但它在一些配置下效果最好。要添加该手动配置,我将webpack.config.js在项目的根文件夹中创建一个文件。在此文件中,我将添加以下内容以利用这个新安装的插件:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
plugins: [
new HtmlWebpackPlugin()
]
};
代码语言: JavaScript (javascript )
有了它,我将npx webpack再次运行以在我的文件夹中获得更好的结果dist。HtmlWebpackPlugin 生成一个缩小的 HTML 文件,其中添加了我的 JavaScript 包,在<script>页面的标记中引用。
问题是,这没有使用index.html我最初在我的src文件夹中创建的文件。让我们将 HtmlWebpackPlugin 配置为使用该文件作为模板,而不是构建自己的文件。
我将对以下内容进行更改src/index.html:
<html lang="en">
<head>
<title><%= htmlWebpackPlugin.options.title %></title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="description" content="<%= htmlWebpackPlugin.options.metaDesc %>" />
</head>
<body>
<h1><%= htmlWebpackPlugin.options.header %></h1>
<div id="wrapper" style="height: 120px">
<div class="panel"></div>
<div class="panel"></div>
<div class="panel"></div>
</div>
<div id="zoom-scene"></div>
</body>
</html>
代码语言: HTML、XML (xml )
请注意,我添加了多个访问值的变量,此处用作占位符。这类似于使用 JavaScript 模板或后端模板语言完成的工作。请注意,没有对 JavaScript 文件的引用。
接下来我要HtmlWebpackPlugin()在我的webpack.config.js文件中添加一些选项。plugins: []我的文件部分现在webpack.config.js如下所示:
plugins: [
new HtmlWebpackPlugin({
hash: true,
title: 'Webpack Example App',
header: 'Webpack Example Title',
metaDesc: 'Webpack Example Description',
template: './src/index.html',
filename: 'index.html',
inject: 'body'
})
]
代码语言: JavaScript (javascript )
在上面的代码中注意:
- 我已经
hash设置true为缓存破坏 - 我已经指定了模板的位置
dist我已经给出了要在文件夹中输出的 HTML 文件的名称
此外,请注意我在模板中指定了三个用作占位符的变量。我可以在这里创建我想要的任何属性,只要它们不与插件允许的任何预定义选项冲突。最后,我将inject选项设置为值以确保脚本出现在我的 HTML 元素body的底部。<body>
在 webpack 中启用开发模式
目前,当 webpack 构建我的dist文件夹时,它正在使用生产模式构建和捆绑它,这是默认的。如果我不断地在本地构建和检查我的工作,如果我的文件没有缩小,它可能会更有用。此外,我指定了一种模式,我将避免前面提到的警告。
为了启用开发模式,我将在我的文件中添加一行webpack.config.js,这样完整的文件现在看起来像这样:
const path = require('path');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
hash: true,
title: 'Webpack Example App',
header: 'Webpack Example Title',
metaDesc: 'Webpack Example Description',
template: './src/index.html',
filename: 'index.html',
inject: 'body'
})
],
mode: 'development'
};
代码语言: JavaScript (javascript )
注意mode现在在我的对象中指定的module.exports(不要忘记方括号后面的逗号)。当我准备好发布我的作品时,我可以将其切换为mode: production. 现在我的构建将干净利落地进行,没有我之前提到的警告消息。
清理dist文件夹
使用此设置,每当我在我的项目上运行 webpack 时,dist文件夹保持不变,webpack 创建一些文件并覆盖其他文件。这还不错,但理想情况下我希望每个构建都输出到一个空dist文件夹。
这是有道理的,因为某些构建可能有新目录、要构建的新文件、重命名的文件等等。我不希望旧文件四处流传,我只想要每次运行时 webpack 构建和捆绑的任何内容。
我要在我的webpack.config.js文件中添加另一行,现在看起来像这样(再次注意额外的逗号以确保语法正确):
const path = require('path');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
hash: true,
title: 'Webpack Example App',
header: 'Webpack Example Title',
metaDesc: 'Webpack Example Description',
template: './src/index.html',
filename: 'index.html',
inject: 'body'
})
],
mode: 'development',
output: {
clean: true
}
};
代码语言: JavaScript (javascript )
现在module.export包含一个output具有单个属性/值对的对象:clean: true。这确保 webpack 在每次构建之前清理我的dist文件夹。
使用 npm 脚本运行 webpack
到目前为止,我一直在使用npx webpack命令来捆绑我的资源。这是一种方法,但是在使用 npm 脚本执行命令时,使用 webpack 会更高效。当我想在构建过程中添加其他命令时,这会派上用场。
在我的package.json文件中,有一个“脚本”部分。我要添加一行,所以它看起来像这样(再次注意额外的逗号):
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
代码语言: JavaScript (javascript )
现在我可以在项目的根目录中使用以下命令运行 webpack:
npm run build
这与命令的结果相同npx webpack:Webpack 将使用内部的入口点src开始我的构建,它将捆绑我的依赖项,并将在dist文件夹中生成输出。
或者,如果我想使用脚本来区分开发构建和生产构建,我可以执行以下操作:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack --mode development",
"build": "webpack --mode production"
},
代码语言: JavaScript (javascript )
现在我可以运行npm run dev或npm run build,这取决于我想对我的项目做什么。
使用热重载安装和运行服务器
使用像 webpack 这样的工具时,最好在本地模拟真实的服务器环境,而不是处理协议file://。您可能已经为此设置了一些东西(例如,我使用XAMPP,因为我经常使用 PHP 和WordPress)。但是 webpack 为您提供了一个选项,可以在需要时轻松地安装带有实时重新加载的服务器。
要将服务器安装为开发人员依赖项,我将在项目的根目录中运行以下命令:
npm install webpack-dev-server --save-dev
安装完成后,我将在我的webpack.config.js文件中添加几行:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
hash: true,
title: 'Webpack Example App',
header: 'Webpack Example Title',
metaDesc: 'Webpack Example Description',
template: './src/index.html',
filename: 'index.html',
inject: 'body'
})
],
mode: 'development',
output: {
clean: true
},
devServer: {
contentBase: './dist',
open: true
}
};
代码语言: JavaScript (javascript )
请注意,我添加了一个module.exports名为devServer. 在那里,我指定了我希望从何处提供我的页面,并且我正在使用该open选项在浏览器中自动打开我的项目。浏览器使用默认端口为页面提供服务8080,因此我可以使用 URL: 来查看我的页面http://localhost:8080/。
我需要做的最后一件事是将服务器添加为我的构建脚本的一部分package.json:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack serve --mode development",
"build": "webpack --mode production"
},
代码语言: JavaScript (javascript )
请注意,我已经添加serve到脚本中dev。build如果我愿意,我可以对生产脚本做同样的事情。有了这个,我可以运行以下命令来构建我的包并从以下位置提供我的页面localhost:8080:
npm run dev
这将打开浏览器,以便我可以查看我的页面。这也将实时重新加载,因此如果我对文件src夹中的内容进行任何更改,将再次构建捆绑包dist,浏览器将自动重新加载页面。
webpack 实现的最终示例
完成上述所有操作后,该npm run dev命令将在每次执行时生成我的构建。然后我可以使用以下命令构建我的生产项目:
npm run build
这将build在生产模式下执行脚本(如我的 中所述package.json)。index.html在我的例子中,这会在文件夹中生成以下内容的缩小版本dist:
<html lang="en">
<head>
<title>Webpack Example App</title>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="description" content="Webpack Example Description"/>
</head>
<body>
<h1>Webpack Example Title</h1>
<div id="wrapper" style="height: 120px">
<div class="panel"></div>
<div class="panel"></div>
<div class="panel"></div>
</div>
<div id="zoom-scene"></div>
<script defer="defer" src="main.js?097d8b8eda8ecc97a023"></script>
</body>
</html>
代码语言: HTML、XML (xml )
Webpack 已使用 HtmlWebpackPlugin 生成的信息更新了我的占位符,我的模板的其余部分保持不变,而且——最重要的是——webpack 已将我的 JavaScript 模块捆绑到一个文件中main.js。文件引用使用查询字符串值来确保浏览器加载新版本而不是缓存版本。
如果我在浏览器中查看我的页面,我会看到两个控制台日志,确认 webpack 正确地捆绑了我的依赖项。如果您按照这个 webpack 教程进行操作,您应该会得到相同的结果。
总结这个 webpack 教程
这应该足以让你开始使用 webpack!
我已经在这个面向初学者的 webpack 教程中介绍了很多内容,但我只触及了一些可能的表面。例如,我没有合并任何使用 CSS或图像的功能。官方 webpack 文档在技术上相当繁重,但您应该能够找到很多内容来扩展我在本教程中介绍的内容,特别是对于前端开发。
您会注意到,在本 webpack 教程中,我没有使用我之前安装的两个实用程序执行任何操作。如前所述,这些用于演示捆绑包。如果我包含一些 JavaScript 来处理这些工具,webpack 将以与我添加的两个控制台日志相同的方式捆绑所有这些。
如果您按照我上面概述的步骤进行操作,您应该不会遇到任何重大问题。如果您这样做,请随时将它们张贴在此处的评论中,或者尝试在线搜索您收到的任何错误消息。Webpack 非常大,所以您可能不是唯一遇到问题的人!

