hse365平台-mobile365官网是多少-英国365网站最近怎么了

设置 Webpack

设置 Webpack

Webpack 5 启动和运行指南(全)

原文:zh.annas-archive.org/md5/D84E54A317E3F5B84C857CD1B0FA20B6

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

当我被要求写这本培训书时,我意识到关于 Webpack 及其用途的了解很少。通常这是开发人员偶然发现并在工作中学习的东西,这可能是一个非常费力的过程。Webpack.js 网站上有一些文档,以及一些可靠的资源,比如 Medium。然而,这些资源往往从专家的角度来与读者交流,而我个人发现这并不理想。

作为一名网页开发讲师,我看到非常有技术和智慧的人可能存在盲点和知识空白。作为一名讲师,我被告知,并且也传达这个信息,那就是“没有愚蠢的问题”。许多没有教学背景的人可能会建议他们不想对你说教,宁愿你不问愚蠢的问题。我们发现,如果学生宁愿保持沉默而不问问题,这是有害的。

我打算尽可能保持简单。也许我已经失败了,使用了“定制”这样的词,尽管如此,前提是我们所有人都会有让人啪啪打脑袋的时刻,我们本应该做某事,后来意识到我们做错了。对吧?这种事发生在我们最聪明的人身上。此外,大多数讲师可能不愿意对你进行详尽的解释,因为他们担心冒犯你。问题在于,总会有一些平凡的细节,开发人员认为显而易见,但可能有多种解释。当我讲课时的规则是:“没有愚蠢的问题”,所以我希望证明这个理论的必要性。

这本书适合谁

这本书是为希望通过学习 Webpack 来开始他们的 Web 项目依赖管理的 Web 开发人员而写的。假定读者具有 JavaScript 的工作知识。

本书涵盖的内容

第一章,“Webpack 5 简介”,将向您介绍 Webpack——具体来说,是 Webpack 5 版本。它将概述围绕 Webpack 的核心概念以及它的使用方式。

第二章,“使用模块和代码拆分”,将详细介绍模块和代码拆分,以及 Webpack 5 的一些突出和有趣的方面,这些方面对于理解 Webpack 至关重要。

第三章,“使用配置和选项”,将探讨配置的世界,了解其局限性和能力,以及选项在其中的作用。

第四章,“API、插件和加载器”,将深入探讨 API、加载器和插件的世界。这些 Webpack 的特性阐述了平台的能力,从配置和选项出发。

第五章,“库和框架”,将讨论库和框架。我们对插件、API 和加载器的研究表明,有时我们不想使用诸如库之类的远程代码,但有时我们确实需要。Webpack 通常处理本地托管的代码,但有时我们可能需要使用库。这为我们引入了这个话题。

第六章,“生产、集成和联合模块”,将深入介绍这个主题,并希望解决开发人员可能存在的任何疑虑。

第七章,“调试和迁移”,将讨论热模块替换和实时编码,并深入了解一些严肃的教程。

第八章,编写教程和实时编码技巧,将向您展示 Webpack 5 的工作示例,特别是 Webpack 5 相对于早期版本的差异。将有纯 JavaScript 教程以及常见的框架,Vue.js 将是一个不错的选择。

为了充分利用本书

您可以在github.com/PacktPublishing/Webpack-5-Up-and-Running找到本书所有章节中使用的代码。为了充分利用本书,您需要以下内容:

JavaScript 的基本知识。

确保您已安装最新版本的 Webpack 5。

您需要使用命令行界面,如命令提示符或其他您选择的命令行实用程序。

您将需要 Node.js,JavaScript 运行环境。

确保您已安装最新版本的 Node.js(webpack 5 至少需要 Node.js 10.13.0(LTS));否则,您可能会遇到许多问题。

您需要在本地计算机上安装具有管理员级别权限的npm。Webpack 和 Webpack 5 在 Node.js 环境中运行,这就是为什么我们需要它的包管理器——NPM。

截至撰写本文时,最新版本是 Webpack 5。访问webpack.js.org查找适合您的最新版本。

下载示例代码文件

您可以从www.packt.com的帐户中下载本书的示例代码文件。如果您在其他地方购买了本书,可以访问www.packtpub.com/support并注册,以便文件直接发送到您的邮箱。

您可以按照以下步骤下载代码文件:

登录或注册www.packt.com。

选择“支持”选项卡。

点击“代码下载”。

在搜索框中输入书名,并按照屏幕上的说明操作。

下载文件后,请确保使用以下最新版本的解压缩或提取文件夹:

Windows 使用 WinRAR/7-Zip

Mac 使用 Zipeg/iZip/UnRarX

Linux 使用 7-Zip/PeaZip

该书的代码包也托管在 GitHub 上,网址为github.com/PacktPublishing/Webpack-5-Up-and-Running。如果代码有更新,将在现有的 GitHub 存储库中更新。

我们还有其他代码包来自我们丰富的图书和视频目录,可在github.com/PacktPublishing/找到。快去看看吧!

使用的约定

本书中使用了许多文本约定。

CodeInText:表示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄。以下是一个示例:“以下行是package.json文件中的代码片段。”

代码块设置如下:

"scripts": {

"build": "webpack --config webpack.config.js"

}

当我们希望引起您对代码块的特定部分的注意时,相关行或项目将以粗体显示:

Webpack - Test

任何命令行输入或输出都以以下形式编写:

npm install --save-dev webpack-cli

粗体:表示新术语、重要单词或屏幕上看到的单词。例如,菜单或对话框中的单词会以这种形式出现在文本中。以下是一个示例:“从管理面板中选择系统信息。”

警告或重要说明会以这种形式出现。

提示和技巧会出现在这样的形式中。

第一章:Webpack 5 简介

本书面向有经验的 JavaScript 开发人员,旨在通过逐步的过程带您完成一个特定示例项目的开发和生产。当您完成本指南时,您应该能够完全设置和部署一个可工作的捆绑应用程序。

本章将向您介绍 Webpack——具体来说,是 Webpack 5 版本。它将包括对 Webpack 周围的核心概念以及其用法的概述。

本章面向对 Webpack 和 Webpack 5 新手程序员。本章将涵盖初始设置,以及对该过程的概述,并将向您展示如何部署您的第一个捆绑应用程序。

本章将涵盖以下主题:

Webpack 5 的基础知识

设置 Webpack

创建一个示例项目

技术要求

您可以在本书的所有章节中找到使用的代码github.com/PacktPublishing/Webpack-5-Up-and-Running:

要使用本指南,您需要对 JavaScript 有基本的了解。

确保您已安装了 Webpack 5 的最新版本。

您将需要使用命令行,如命令提示符或您选择的其他命令行实用程序。

您将需要 Node.js,JavaScript 运行环境。

确保你已经安装了最新版本的 Node.js;否则,你可能会遇到很多问题。

您需要在本地计算机上安装npm并具有管理员级别的权限。Webpack 和 Webpack 5 在 Node.js 环境中运行,这就是为什么我们需要它的包管理器 npm。

截至撰写本文时,最新版本是 Webpack 5。访问webpack.js.org找到适合您的最新版本。

Webpack 5 的基础知识

基本上,Webpack 是一个用于 JavaScript 应用程序的模块打包工具。Webpack 接受一系列 JavaScript 文件,以及构成应用程序的图像文件等依赖项,并构建所谓的依赖图。依赖图是这些文件和依赖项在应用程序中如何排序和链接的表示,并显示文件之间的交互方式。

然后,这个依赖图形成了一个模板,捆绑器在将所有依赖项和文件压缩成更小的集合时会遵循这个模板。然后 Webpack 能够将这些文件捆绑成更大、但通常更少的文件集。这消除了未使用的代码、重复的代码以及重写的需要。在某种程度上,代码可以更简洁地格式化。

Webpack 递归地构建应用程序中的每个模块,然后将所有这些模块打包成少量的捆绑包。在大多数情况下,捆绑的应用程序将包含一个脚本,非常适合被程序(如 Web 浏览器)读取,但对程序员来说太复杂了。因此,开发人员将会拿一组源文件并对程序的这一部分进行更改,然后将这些源文件捆绑成一个输出——一个捆绑的应用程序。

捆绑最初是为了提高浏览器的阅读性能,但它还有许多其他优点。一旦 Webpack 捆绑了一组源文件,它通常会遵循一种系统化和常规的文件结构。代码中的错误可能会中断捆绑操作;本书将指导您如何克服这些问题。

现在,让我们探索 Webpack 5 周围的一般概念。

Webpack 5 背后的一般概念

在这里,我们将开始理解 Webpack 的关键概念和目的,而不是期望您有任何先前的了解。捆绑通常在桌面上使用 Node.js 或npm和命令行界面(CLI)(通常是命令提示符)上进行。

Webpack 是一个构建工具,将所有资产放入一个依赖图中。这包括 JavaScript 文件、图像、字体和层叠样式表(CSS)。它将Sassy CSS(SCSS)和 TypeScript 文件分别放入 CSS 和 JavaScript 文件中。只有当代码与后者格式兼容时,Webpack 才能做到这一点。

在 JavaScript 和其他语言编程时,源代码通常会使用诸如require()的语句,将一个文件指向另一个文件。Webpack 将检测这个语句,并确定所需的文件作为依赖项。这将决定最终 JavaScript 捆绑包中的文件如何处理。这还包括将 URL 路径替换为内容传送网络(CDN)——这实质上是一组代理服务器网络——与本地文件。

以下图表是 Webpack 的一般目的的表示,即获取一组文件或依赖项并以优化的形式输出内容:

现在,让我们更仔细地看一些您可能不熟悉但在使用 Webpack 时可以被视为常用术语的术语。

术语

本节将涵盖 Webpack 5 中使用的术语。这将包括本地术语,以及一些更不寻常的缩写词。

资产:这是 Webpack 中经常使用的一个术语,用于防止概念的混淆。它指的是软件在生成捆绑应用程序时收集的图像文件,甚至是数据或脚本文件。

捆绑:这指的是 Webpack 编译应用程序后输出的应用程序。这是原始或源应用程序的优化版本——这将在后面的章节中详细讨论原因。捆绑器将这些文件合并成一个文件,这使得解包和破解变得非常困难。它还提高了浏览器的性能。它通过确保处理器保持在最佳水平,并删除任何不符合标准的编码结构来实现这一点。这也鼓励开发人员更加认真地采用惯例。如果存在任何不安全的编程,这些位置更容易被识别、隔离和纠正。

SASS:CSS 的增强版本。Webpack 处理这段代码就像处理 CSS 一样;然而,这可能是一个让你感到困惑的短语,所以了解一下是值得的。

SCSS:这只是用于给 SASS 增加额外功能的语法版本的名称。值得知道的是,Webpack 能够转译这两种语法。

转译:这是 Webpack 5 将一组输入源代码转换为更优化的输出分发代码的过程。这是通过删除未使用或重复的代码来完成的。转译用于将一组文件转换为更简单的一组文件。例如,SCSS 通常包含可以轻松存储在 CSS 文件中的脚本。您还可以将 SCSS 转译为 CSS,或将 TypeScript 转译为 JavaScript。

TypeScript:对于未经训练的人来说,TypeScript 是一种在许多方面类似于 JavaScript 的代码类型。例如,浏览器最常运行 JavaScript,因此在可能的情况下使用 JavaScript 可能更合适。当前,Webpack 5 将在前者允许时将 TypeScript 转译为 JavaScript。

CDN:CDN 是一组代理服务器网络,提供高可用性和高性能。一些例子是谷歌 API,如谷歌字体,以及其他类似的工具,所有 JavaScript 开发人员无疑都很熟悉。

依赖图:在 Webpack 5 中,依赖图是表示多个资产相互依赖的有向图。Webpack 5 将映射资产和依赖项的列表,并记录它们在应用程序中如何相互依赖。它使用这个来推导出一个适当的输出文件结构。

尽管 JavaScript 是入口点,但 Webpack 意识到您的其他资产类型(如 HTML、CSS 和 SVG)都有自己的依赖关系,这些依赖关系应该作为构建过程的一部分进行考虑。

Webpack 由输入和输出组成。输出可以由一个或多个文件组成。除了捆绑模块外,Webpack 还可以对您的文件执行许多功能。输入是指在捆绑之前,原始文件的原始结构。输出是指捆绑后的文件在其新的和优化的文件结构中的结果。因此,输入由源文件组成,输出可以由开发文件或生产文件组成。

输入和输出以及源代码和开发代码之间经常混淆。

源代码指的是捆绑之前的原始应用程序。开发代码指的是将应用程序放入 Node.js 环境并以开发模式捆绑后的应用程序。在生产模式下会产生一个更“紧凑”的捆绑版本,但这个版本很难进行工作。因此,在捆绑后可以在一定程度上修改开发代码,这非常有用,例如在您修改数据库连接配置的情况下。

在使用 Webpack 5 时,这些短语可能会出现,重要的是您不要对它们感到太困惑。

大多数其他术语将在我们遇到它时进行解释,或者如果您熟悉 JavaScript,它是如此常见,我们假设您了解这些术语。

这总结了您在使用 Webpack 时会遇到的大部分术语。现在,我们将探讨软件的工作原理。

Webpack 的工作原理

Webpack 通过生成一组源文件中资产的依赖图来工作,然后从中转换出一组优化的分发文件。这些源和分发文件分别包含源代码和分发代码。这些分发代码形成了输出。分发只是输出或捆绑的另一个名称。

Webpack 首先在源文件中找到一个入口点,然后构建一个依赖图。在 Webpack 5 中,选择入口点是可选的,选择的方式将改变构建过程的性质,无论是速度还是输出优化。

Webpack 5 能够转换、捆绑或打包几乎任何资源或资产。

我们已经对软件的工作原理进行了良好的概述;之前使用过 Webpack 的有经验的用户可能会认为这个概述很基础,所以让我们来看看这个当前版本中有什么新东西。

Webpack 5 中有什么新功能?

备受欢迎的 Webpack 模块捆绑器已经经历了一次大规模更新,发布了第 5 版。Webpack 5 提供了巨大的性能改进、更动态的可扩展性和基本的向后兼容性。

Webpack 5 接替了第 4 版,第 4 版并非总是与许多可用的各种加载器向后兼容,这些加载器通常更兼容第 2 版,这意味着如果不使用第 2 版,开发人员通常会在命令行中遇到弃用警告。Webpack 5 现在已经解决了这个问题。

第 5 版的另一个重要卖点是联邦模块。我们将在稍后的第六章中更详细地讨论这一点,生产、集成和联邦模块。然而,总结一下,联邦模块本质上是捆绑应用程序以利用和与远程存储的单独捆绑中的模块和资产进行交互的一种方式。

Webpack 5 的优点总结如下:

Webpack 5 提供了对 HTTP 请求的控制,这提高了速度和性能,也减轻了安全问题。

Webpack 5 相对于竞争对手 Browserify 和 systemjs 有一些优势,特别是速度。构建时间直接取决于配置,但比最近的竞争对手更快。

使用 Webpack 5 几乎不需要任何配置,但您始终可以选择配置。

与其他替代方案相比,使用起来可能更复杂,但这主要是由于其多功能和范围,值得克服。

Webpack 5 具有优化插件,可以很好地删除未使用的代码。它还具有许多相关功能,例如树摇动,我们将在本书后面更详细地讨论。

它比 Browserify 更灵活,允许用户选择更多的入口点并使用不同类型的资产。在捆绑大型 Web 应用程序和单页面 Web 应用程序时,它在速度和灵活性方面也更好。

Webpack 现在被认为是应用程序开发和 Web 开发中非常重要的工具,它可以改变结构并优化所有 Web 资产的加载时间,例如 HTML、JS、CSS 和图像。现在让我们实际使用 Webpack。为了做到这一点,我们将首先看一下可能对您来说是新的东西——如果您到目前为止只使用原生 JavaScript——模式。

模式

一旦您理解了一般概念,运行构建时需要了解的第一件事就是模式。模式对于 Webpack 的工作和编译项目至关重要,因此最好在继续之前简要但重要地介绍一下这个主题。

模式使用 CLI,这是我们稍后将更详细介绍的一个过程。如果您习惯使用原生 JavaScript,这可能对您来说是新的。但是,请放心,这不是一个难以理解的复杂主题。

Webpack 附带两个配置文件,如下所示:

开发配置:这使用webpack-dev-server(热重载)、启用调试等。

生产配置:这将生成一个在生产环境中使用的优化、最小化(uglify JS)、源映射的捆绑包。

自从发布第 5 版以来,Webpack 默认通过简单地向命令添加mode参数来处理模式功能。Webpack 不能仅使用package.json来查找模式以确定正确的构建路径。

现在我们已经掌握了基本原理,是时候进入实际设置了。

设置 Webpack

本书将逐步介绍一个示例项目的开发,我相信您会发现这是学习如何使用 Webpack 5 的简单方法。

Webpack 5 在本地机器上打包所有依赖项。理论上,这可以远程完成,但为了避免给第一次使用者带来任何困惑,我将强调使用本地机器。

对于大多数项目,建议在本地安装软件包。当引入升级或破坏性更改时,这样做会更容易。

我们将从npm安装开始。npm 是您将与 Webpack 5 一起使用的软件包管理器。一旦在本地机器上安装了它,您就可以使用 CLI,例如命令提示符,来使用npm命令。

安装了npm后,您可以继续下一步,即打开 CLI。有很多选择,但为了本教程的缘故,我们将使用命令提示符。

让我们一步一步地分解这个过程,这样您就可以跟上:

安装npm软件包管理器,您将与 Wepback 5 一起使用它。

打开 CLI(在本教程中,我们将使用命令提示符)并输入以下内容:

mkdir webpack4 && cd webpack5

npm init -y

npm install webpack webpack-cli --save-dev

让我们分解一下代码块。前面的命令首先会在您的本地计算机上创建一个名为webpack5的新目录。然后,它将把当前目录(cd)标识为webpack5。这意味着通过 CLI 进行的任何进一步的命令都将是相对于该目录进行的。接下来的命令是初始化npm。这些基本命令及其含义的完整列表可以在本章末尾的进一步阅读部分找到。这部分内容很有趣,我相信您会学到一些新东西。然后,我们在本地安装 Webpack 并安装webpack-cli——这是用于在命令行上运行 Webpack 的工具。

接下来,安装最新版本或特定版本的 Webpack,并运行以下命令。但是,在第二行,用您选择的版本替换,例如5.00:

npm install --save-dev webpack

npm install --save-dev webpack@

下一个命令是npm install,它将在目录中安装 Webpack 5,并将项目保存在开发环境中。重要的是要注意开发环境和生产环境(或模式)之间的区别:

npm install --save-dev webpack-cli

以下行是package.json文件中的代码片段。我们需要这些输入文件来生成webpack.config.js文件,其中包含 Webpack 捆绑的配置信息。

我们必须确保package.json文件的编码如下:

"scripts": {

"build": "webpack --config webpack.config.js"

}

在使用 Webpack 5 时,您可以通过在 CLI 中运行npx webpack来访问其二进制版本。

我们还应该决定我们需要哪种类型的安装;任何重新安装都会覆盖先前的安装,所以如果您已经按照前面的步骤进行了操作,就不用担心了。

如果适用,现在让我们进行安装。

有两种类型的安装:

全局:全局安装将锁定您的安装到特定版本的 Webpack。

以下npm安装将使 Webpack 全局可用:

npm install --global webpack

本地:本地安装将允许您在项目目录中运行 Webpack。这需要通过npm脚本完成:

npm install webpack --save-dev

每次在新的本地计算机上开始新项目时,您都需要执行所有前面的步骤。完成安装后,是时候把注意力转回到构建项目上了。

创建一个示例项目

现在,我们将创建一个实验项目,具有以下目录结构、文件及其内容。

以下代码块是指您本地计算机上的一个文件夹。它说明了 Webpack 通常使用的格式和命名约定。您应该遵循此格式,以确保您的项目与本教程保持一致,如下所示:

首先设置项目树:

webpack5-demo

|- package.json

|- index.html

|- /src

|- index.js

项目树向我们展示了我们将要处理的文件。

现在让我们仔细看一下索引文件,因为它们将成为我们前端的关键,从src/index.js开始:

function component() {

let element = document.createElement('div');

// Lodash, currently included via a script, is required for this

// line to work

element.innerHTML = _.join(['Testing', 'webpack'], ' ');

return element;

}

document.body.appendChild(component());

index.js包含我们的 JS。接下来的index.html文件是我们用户的前端。

它还需要设置,所以让我们打开并编辑index.html:

Webpack - Test

请注意前面的

//If you see the above line, please remove it.

接下来,我们将使用命令行运行npx webpack。npx命令随 Node 8.2/npm 5.0.0 或更高版本一起提供,并运行 Webpack 二进制文件(./node_modules/.bin/webpack)。这将把我们的脚本src/index.js作为入口点,并生成dist/main.js作为输出:

npx webpack

...

Built at: 14/03/2019 11:50:07

Asset Size Chunks Chunk Names

main.js 70.4 KiB 0 [emitted] main

...

WARNING in configuration

The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.

You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

如果没有错误,构建可以被视为成功。

请注意,警告不被视为错误。警告只是因为尚未设置模式而显示的。

我不会担心这个,因为 Webpack 将默认为生产模式。我们将在本指南的后面处理模式设置。

当你在浏览器中打开index.html时,你应该看到以下文本:

Testing Webpack5

万岁——我们已经完成了我们的第一个应用程序捆绑,我敢打赌你一定为自己感到非常自豪!这是一个开始的基本步骤;我们将在后面的章节中继续学习 Webpack 的更复杂的元素,并开始将它们应用到需要捆绑的现有项目中。

摘要

总之,Webpack 5 是一个非常多才多艺的捆绑工具,几乎使用了每一种可想象的方法来优化应用程序的大小并提高整体性能。了解它是非常值得的,本指南将向你展示你需要了解的一切。

现在,你应该了解 Webpack 背后的基本概念,以及基本术语。你现在也应该知道如何安装先决条件,比如 Node.js,并设置和部署——以及制作——你的第一个捆绑使用命令行。

在下一章中,我们将详细介绍模块和代码拆分,以及 Webpack 5 的一些更显著和有趣的方面,这些方面对理解 Webpack 至关重要。

问题

以下是与本章相关的一系列问题,您应该尝试回答以帮助您的学习。答案可以在本书的评估部分中找到:

什么是 Webpack?

Webpack 中的捆绑包是什么?

根据本指南,Webpack 的最新版本是多少?

Webpack 在哪个环境中工作?

什么是依赖图?

在捆绑时,以下命令缺少哪个入口?

npm --save lodash

我们在 Webpack 5 中使用的包管理器的名称是什么?

如何使用命令行删除lodash库?

在使用 Webpack 5 时,源代码和分发代码之间有什么区别?

在设置项目时,为什么要调整package.json文件?

第二章:使用模块和代码拆分

本章将探讨 Webpack 5 中的模块和代码拆分。模块是一种按功能将代码分组的方式。代码拆分是 Webpack 用来自动构建这些模块的方法;它将项目中的代码分割成最适合完成项目的功能和结构的模块。

本章涵盖的主题如下:

解释模块

理解代码拆分

预取和预加载模块

最佳实践

解释模块

Webpack 使用称为模块的元素。它使用这些模块来构建依赖图。

模块是处理相关功能的代码部分;根据模块化构建项目将提高功能。例如,与未使用模块构建的项目相比,只有与相关操作相关的代码需要运行。

说到这里,下一件要理解的事情是模块的具体功能,这将在接下来的部分中讨论。

模块的功能

模块是一组代码片段:例如,相似语言的代码具有共同的功能——也就是说,它是应用程序中相同功能或操作的一部分。

通常,Webpack 5 中的模块根据使用的脚本语言进行分组,如下所示:

前面的图表应该有助于说明大多数人在探索 Webpack 构建内容时看到的内容。

然后将应用程序分成模块和资产。正如我们在第一章中所解释的那样,资产基本上是开发人员不认为是脚本的图像和视频。然后,目录结构通常被细分为这些模块,通常在它们自己的目录中。

将应用程序分成模块将自然使调试过程更容易。这也将有助于我们进行验证和测试。

以这种方式构建应用程序可以确保在良好编写的代码和更加可疑的代码之间建立边界。当然,这有助于目录导航,因为每个模块都有一个明确定义的目的。

许多平台使用模块,这是一个您在一般的 Web 开发中肯定会习惯的术语。然而,每个平台略有不同。

Webpack 5 根据模块的依赖关系表达方式来形成这些模块。以下是 Webpack 5 表达它们的一些示例:

通过2015 ECMAScript的import语句

通过**CommonJS **的require()语句

通过异步模块定义 (ASM)的define和require语句

通过样式表中的 imageURL

通过样式表中的@import语句

总之,模块化的代码使事情变得更容易,了解 Webpack 如何表达依赖关系将帮助您了解应该如何编译代码。从这里开始,自然的下一步是查看支持的模块类型以及加载器如何与它们一起工作。

支持的模块语言和加载器

为了确保 Webpack 5 支持这些模块,它们必须用可以理解和处理的编程语言编写。Webpack 5 通过使用称为加载器的东西来实现这一点。

加载器使 Webpack 在竞争对手捆绑器中真正脱颖而出。简单来说,加载器告诉 Webpack 如何处理不是 JavaScript 或其他 Webpack 自动理解的预定义代码(如 JSON 或 HTML)的代码。Webpack 5 将会将这些处理过的代码作为依赖项包含在您的捆绑包中。

Webpack 5 拥有一个开发者社区,称为 Webpack 社区,他们构建了这些加载器。这些加载器目前支持大量的语言和处理器;一些例子如下:

TypeScript

SASS

LESS

**C++ **

Babel

Bootstrap

有关可用加载器的完整列表,请参阅本章末尾的“进一步阅读”部分。

成为 Webpack 社区的一部分意味着您可以编写自己的加载器!这是值得考虑的事情,因为这可能是满足项目要求的最佳方式。

有许多更多的加载器可用于 Webpack 社区。使用加载器意味着 Webpack 5 可以被描述为一个动态平台,允许定制几乎任何技术堆栈。在本章中,我们将开始积极地使用加载器作为一些示例用例的一部分,您可以练习自己编码。

在开发过程中,您可能会遇到“封装”一词,特别是在处理模块和加载器时。

要理解封装,您首先需要了解软件有时可以独立开发,直到需要互动才会出现。为了使软件在项目中一起工作,必须在两个技术堆栈之间创建一个依赖关系。这就是“封装”一词的含义。

封装是一个简单的主题,但模块化编码的下一个领域是解析。这是一个更广泛的主题,因此已经作为自己的子部分进行了详细说明。

启用新的资产模块类型是 v5 的一个实验性功能。资产模块类型类似于file-loader、url-loader或raw-loader(自 alpha.19 以来的experiments.asset)数据 URL 和相关选项自 beta.8 以来得到支持。

模块解析

模块解析是通过解析器进行的。解析器帮助您通过其绝对路径找到一个模块——在整个项目中通用的模块路径。

请注意,一个模块可以作为另一个模块的依赖项,例如以下情况:

import example from 'path/to/module';

无论依赖模块是来自另一个库(而不是解析器本身)还是应用程序本身,解析器都将帮助找到所需的模块代码以包含在捆绑包中。Webpack 5 也可以在捆绑时使用enhance-resolve来解析路径。

Webpack 5 的解析规则意味着,使用enhanced-resolve方法,Webpack 5 可以解析三种文件路径:

绝对路径

相对路径

模块路径

以下部分将详细说明每个文件路径的含义,并且每个部分都将有一个示例。随着我们开始构建项目捆绑包,这将变得更加重要。

绝对路径

对于初学者来说,绝对路径是指文件路径和项目使用的所有文件和资产的位置。这个共同的位置有时被称为home或root目录。以下是一个命令行位置的示例:

import 'C:\\Users\\project\\file';

前一行是绝对路径的一个示例。术语“绝对”是每个 JavaScript 开发人员都应该熟悉的内容。它涉及到系统中普遍存在的对象文件或目录的位置。

如果我们已经有了绝对路径,就像前一行一样,就不需要进一步解析了。

相对路径

相对路径是指一个对象文件或目录到另一个位置的位置。在这种情况下,它是“上下文”目录的位置——开发进行的当前工作位置:

import '../src/file';

在前面的示例中,资源文件的目录被认为是“上下文”目录。资源文件是指import()语句、require()语句或对外部文件的调用发生的文件。

在这种情况下,相对路径与上下文目录路径相结合,然后产生绝对路径。

模块路径

模块路径是并非所有 JavaScript 开发人员都习惯的东西。在 Webpack 中,它指的是相对于模块的位置。在下面的代码片段中,module将被用于你希望使用的任何特定模块名称的名称——例如你项目中现有模块的名称:

import 'module/sub-directory/file';

Webpack 5 搜索所有在resolve.module指令中指定的模块的目录。可以使用resolve.alias配置为每个原始模块文件路径创建别名。使用这种方法,Webpack 5 会检查文件路径以及它指向文件还是目录。

Webpack 5 有一个名为resolve.extension的选项。如果路径没有文件扩展名,这个解析器将指示 Webpack 可以用于解析的扩展名。这些可能包括.js、.jsx或类似的扩展名。

如果文件路径不指向文件而只指向目录,Webpack 5 会搜索该目录中的package.json文件。然后 Webpack 5 使用resove.main字段配置中指定的字段来搜索package.json中包含的字段,并从中确定要使用的正确上下文文件路径。

如果目录中没有package.json文件,或者主字段没有返回有效路径,Webpack 5 会简单地搜索resolve.main配置中指定的文件名。

文件扩展名的解析方式类似,但使用resolve.extension选项。

到目前为止,我们已经涵盖了模块、路径解析、支持的语言和加载程序。下一个重要的理解是代码拆分——它是什么,以及 Webpack 如何利用它来形成它的模块和一般输出。

理解代码拆分

代码拆分允许用户将代码拆分成各种捆绑包,然后按需或并行加载。Webpack 的开发人员认为这是 Webpack 的“最引人注目的功能之一”(Webpack.js.org)。

代码拆分有两个关键优势——这个过程可以用来实现更小的捆绑包,并控制资源加载的优先级。这可以导致加载时间的改善。

Webpack 5 中有三种通用的代码拆分方法:

入口点:这是使用入口点配置手动拆分代码。

防止重复:这种方法使用SplitChunksPlugin来运行一个称为dedupe的过程,将代码拆分成称为chunks的模块组。

动态导入:这种方法使用内联函数在模块内部进行调用以拆分代码。

一个 chunk 指的是一组模块。这是 Webpack 使用的一个术语,在其他平台上并不经常遇到。

dedupe 是一个使用机器学习快速执行匹配、去重和实体解析的 Python 库。它有助于从姓名和地址的电子表格中删除重复条目。

有了这三种方法的概述,我们现在可以在接下来的章节中详细讨论每一种方法。让我们从入口点开始。

入口点

使用入口点可能是执行代码拆分的最简单方法。这是一个手动操作,因此不像其他方法那样自动化。

我们现在将看一下从主捆绑包中拆分一个模块的开发。为此,我们将从一些实际工作开始。然后,我们将讨论重复和动态导入的概念。

我们现在将回到我们在第一章中工作的项目,Webpack 5 简介。这一次,我们将利用到目前为止在本章中学到的知识。

首先,创建一个工作目录。在这种情况下,我们使用了上一章中使用的目录名称。遵循相同的约定可能是一个好主意,这样你就可以在继续阅读本书的过程中跟踪项目的发展。

在下面的例子中,我们将做以下操作:

组织一个项目文件夹结构,以开始一个展示入口点如何工作的项目。您应该在练习项目目录中构建这组目录。这与在桌面上创建文件夹的方式相同。为了本示例,我们将称此文件夹为webpack5-demo(但您可以选择任何您喜欢的名称):

package.json

webpack.config.js

/dist

/src

index.js

/node_modules

/node_modules/another-module.js

如果您使用的代码缺少最后一行文本(用粗体标记),请确保添加。这可以在命令行上完成;如果您决定使用命令行,请参考第一章,Webpack 5 简介,以获取指导。您可能已经注意到了another-module.js的包含。您可能不会认为这是一个典型的构建,但是您需要包含这个示例。

最终,您可以随意命名项目,但是为了遵循此实践项目,您应该使用到目前为止使用的相同命名约定以防混淆。

为了跟踪此项目的开发,使用您的集成开发环境(IDE)或记事本,您应该创建前面提到的每个文件和文件夹。**/**字符表示一个文件夹。请注意another-module.js文件;它位于/node_modules目录中。

现在,我们将编辑并编译一个构建,从another-module.js文件开始。

在您选择的 IDE 或记事本中打开another-module.js:

import _ from 'lodash';

console.log(

_.join(['Another', 'module', 'loaded!'], ' ')

);

// webpack.config.js

const path = require('path');

module.exports = {

mode: 'development',

entry: {

index: './src/index.js',

another: './src/another-module.js'

},

output: {

filename: '[name].bundle.js',

path: path.resolve(__dirname, 'dist')

}

};

该文件基本上导入了lodash,确保加载的模块记录在控制台日志中,将 Webpack 构建模式设置为开发模式,并设置 Webpack 开始映射应用程序中的资产进行捆绑的入口点,并设置输出捆绑名称和位置。

现在,通过在命令行中输入上下文目录的位置(您正在开发的目录)并输入以下内容来使用npm运行构建:

npm run build

这就是您需要产生捆绑输出或开发应用程序的全部内容。

然后,检查是否成功编译。当在命令行中运行构建时,您应该看到以下消息:

...

Asset Size Chunks Chunk Names

another.bundle.js 550 KiB another [emitted] another

index.bundle.js 550 KiB index [emitted] index

Entrypoint index = index.bundle.js

Entrypoint another = another.bundle.js

...

成功!但是,在使用开发人员应该注意的入口点时,可能会出现一些潜在问题:

如果入口块之间存在重复的模块,它们将包含在两个捆绑包中。

对于我们的示例,由于lodash也作为./src/index.js文件的一部分导入到项目目录中,它将在两个捆绑包中重复。通过使用SplitChunksPlugin可以消除此重复。

它们不能用于根据应用程序的编程逻辑动态拆分代码。

现在,我们将介绍如何防止重复。

使用 SplitChunksPlugin 防止重复

SplitChunksPlugin允许将常见依赖项提取到入口块中,无论是现有的还是新的。在以下步骤中,将使用此方法来从前面示例中去重lodash依赖项。

以下是从前面示例的项目目录中找到的webpack.config.js文件中的代码片段。此示例显示了使用该插件所需的配置选项:

我们将首先确保我们的配置与前面示例中的配置相同:

const path = require('path');

module.exports = {

mode: 'development',

entry: {

index: './src/index.js',

another: './src/another-module.js'

},

output: {

filename: '[name].bundle.js',

path: path.resolve(__dirname, 'dist')

},

optimization: {

splitChunks: {

chunks: 'all'

}

}

};

使用optimization.splitChunks配置,重复的依赖项现在应该从index.bundle.js和another.bundle.js中删除。lodash已被分离到一个单独的块和主捆绑包中。

接下来,执行npm run build:

...

Asset Size Chunks Chunk Names

another.bundle.js 5.95 KiB another [emitted] another

index.bundle.js 5.89 KiB index [emitted] index

vendors~another~index.bundle.js 547 KiB vendors~another~index [emitted] vendors~another~index

Entrypoint index = vendors~another~index.bundle.js index.bundle.js

Entrypoint another = vendors~another~index.bundle.js another.bundle.js

...

有其他由社区开发的加载器和插件可用于拆分代码。一些更值得注意的例子如下:

bundle-loader:用于拆分代码和延迟加载生成的捆绑包

promise-loader:类似于bundle-loader,但使用 promises

mini-css-extract-plugin:用于从主应用程序中拆分 CSS

现在,通过对如何防止重复的理解牢固,我们将转向一个更困难的主题——动态导入。

动态导入

动态导入本质上是 Webpack 上的按需导入。如果您已经捆绑了大量代码,但需要对其进行补丁,动态导入方法将会派上用场。这还包括动态代码拆分,即在构建包后拆分代码并优化它。

Webpack 5 支持两种方法来做到这一点:

第一种方法使用了import()语法,符合 ECMAScript 的动态导入提案。

第二种是特定于 webpack的方法,使用require.ensure方法(这是一种传统方法)。

以下是第一种方法的示例;目标是演示使用动态导入的现代方法,这在最近的项目中将更常见。

import()调用是对承诺的内部调用。承诺指的是从加载程序返回的信息。

在与旧版浏览器一起使用import()时,使用polyfill函数,例如es6-promise或promise-polyfill,来模拟承诺。shim-loader是一个在 Webpack 5 环境中转换代码以使其工作的加载程序;这与使用imports-loader和exports-loader手动执行类似。

下一步是删除配置文件中的任何多余条目,其中包括optmization.splitChunks的引用,因为在接下来的演示中将不需要它:

现在,打开webpack.config.js文件并进行以下条目:

const path = require('path');

module.exports = {

mode: 'development',

entry: {

index: './src/index.js'

index: './src/index.js',

},

output: {

filename: '[name].bundle.js',

chunkFilename: '[name].bundle.js',

path: path.resolve(__dirname, 'dist')

},

};

请注意chunkFilename的使用,它确定非入口块文件的名称。

前面的配置是为了准备您的项目使用动态导入。确保删除粗体文本,因为在处理相同代码时可能会看到这些。

回到项目中,我们需要更新它以删除未使用的文件的说明。

您可能已经设置了练习目录;但是,建议您从不包含任何实验代码的新目录集开始。

以下演示将使用动态导入来分离一个块,而不是静态导入lodash。

打开index.js文件,确保进行以下条目:

function getComponent() {

return import(/* webpackChunkName: "lodash" */ 'lodash').then((

{ default: _ }) => {

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);

})

在导入CommonJS模块时,此导入将不会解析module.exports的值;而是将创建一个人工命名空间对象。因此,在导入时我们需要一个默认值。

在注释中使用webpackChunkName将导致我们的单独包被命名为lodash.bundle.js,而不仅仅是[your id here].bundle.js。有关webpackChunkName和其他可用选项的更多信息,请参阅import()文档。

如果现在运行 Webpack,lodash将分离成一个新的包。

可以使用命令行界面(CLI)运行npm run build。在 CLI 实用程序中,键入以下内容:

npm run build

运行构建时,您应该看到以下消息:

...

Asset Size Chunks Chunk Names

index.bundle.js 7.88 KiB index [emitted] index

vendors~lodash.bundle.js 547 KiB vendors~lodash [emitted] vendors~lodash

Entrypoint index = index.bundle.js

...

import()可以与异步函数一起使用,因为它返回一个承诺。这需要使用预处理器,例如syntax-dynamic-import Babel 插件。

使用src/index.js,进行以下修改以显示代码如何可以简化:

async function getComponent() {

'lodash').then(({ default: _ }) => {

const element = document.createElement('div');

const { default: _ } = await import(/* webpackChunkName: "lodash" */ 'lodash');

element.innerHTML = _.join(['Hello', 'webpack'], ' ');

return element;

}

getComponent().then(component => {

document.body.appendChild(component);

});

前面的示例使用了我们在动态导入部分中使用的相同文件。我们将多行代码转换为单行代码,用异步代码替换了返回函数,加快了我们的编码实践。您会发现它现在比以前的代码简单得多——它使用了相同的文件src/index.js,并实现了相同的功能。

我们经常简化代码以帮助加载时间。改善浏览速度的另一个关键方法是缓存。

缓存

在我们完成代码拆分的这一部分之前,我们将介绍缓存。缓存与之前的过程有关,毫无疑问,在编程过程中会遇到。对于初学者来说,缓存是存储先前计算的数据以便更快地提供的方法。它还与下一节关于预取和预加载有关,这些方法控制内存的使用方式。

了解缓存将确保您知道如何更有效地拆分代码。在下一个示例中,我们将看到如何做到这一点。在 Webpack 中,缓存是通过文件名哈希(当计算机递归跟踪文件位置时)完成的,特别是输出包的哈希化:

module.exports = {

entry: './src/index.js',

plugins: [

// new CleanWebpackPlugin(['dist/*']) for < v2 versions

of CleanWebpackPlugin

new CleanWebpackPlugin(),

new HtmlWebpackPlugin({

title: 'Output Management',

title: 'Caching',

}),

],

output: {

filename: 'bundle.js',

filename: '[name].[contenthash].js',

path: path.resolve(__dirname, 'dist'),

},

};

请注意前面的代码块中的output键处理程序;在括号内,您将看到bundle.js文件名,下面是我们称之为哈希的内联元素。您应该用您的偏好替换括号内的术语。这种方法产生了一种替代输出,只有在内容更新时才会更新,并作为我们的缓存资源。

每个文件系统访问都被缓存,以便同一文件的多个并行或串行请求更快。在watch模式下,只有修改的文件才会从缓存中删除。如果关闭watch模式,则在每次编译之前都会清除缓存。

这将引导我们进入下一节,这也与导入有关——预取和预加载。

预取和预加载模块

在声明导入时,Webpack 5 可以输出一个资源提示。它会给浏览器以下命令:

preload(可能在当前导航期间需要)

prefetch(可能在未来的导航中需要)

“当前”和“未来”这些术语可能会令人困惑,但它们基本上指的是prefetch在用户需要之前加载内容,以某种方式提前加载和排队内容。这是一个简单的定义——接下来会有一个完整的解释——但总的来说,您可以从内存使用和用户体验的效率方面看到优缺点。

需要注意的是,在 Webpack 5 中,预取对Web Assembly(WASM)尚不起作用。

这个简单的prefetch示例可以有一个HomePage组件,它渲染一个LoginButton组件,当被点击时加载一个LoginModal组件。

LoginButton文件需要被创建;按照LoginButton.js中的说明进行操作:

import(/* webpackPrefetch: true */ 'LoginModal');

前面的代码将导致以下代码片段被附加到页面的头部:

这将指示浏览器在空闲时预取**login-modal-chunk.js**文件。

与prefetch相比,preload指令有很多不同之处:

使用preload指令的块与其父块并行加载,而预取的块在父块加载完成后开始加载。

当预加载时,块必须由父块立即请求,而预取的块可以随时使用。

使用preload指令的块在调用时立即下载。在浏览器空闲时下载预取的块。

简单的preload指令可以有组件,它们总是依赖应该在单独块中的库。

使用preload或prefetch的选择在很大程度上取决于上下文;随着教程的进行,您将发现这可能如何适用于您。

根据前面的要点,您应该根据您的开发需求选择使用prefetch或preload。这在很大程度上取决于项目的复杂性,最终是开发人员做出的判断。

以下示例提出了一个想象的组件ChartComponent,在ChartComponent.js中需要一个我们称之为ChartingLibrary的库。它会在需要时立即导入库,并在渲染时显示LoadingIndicator:

import(/* webpackPreload: true */ 'ChartingLibrary');

当请求ChartComponent时,也会通过请求charting-library-chunk。

假设page-chunk加载完成得更快,页面将显示为LoadingIndicator,直到charting-library-chunk加载完成。这将提高加载时间,因为它只需要一个循环处理而不是两个。这在高延迟环境中尤其如此(在这些环境中,数据处理网络经常发生延迟)。

使用webpackPreload不正确可能会损害性能,因此在使用时要注意。

版本 5 中添加的一个功能是有用的,并与获取相关,即顶级等待,这是一个使模块可以作为大型异步函数的功能。这意味着它们将被异步处理。使用顶级等待,ECMAScript 模块(ESM)可以等待资源,导致导入它们的其他模块在开始评估主体之前等待。

现在您应该了解了prefetch和preload的目的,以及如果使用不正确会如何影响性能。关于它们的使用决定将在很大程度上取决于您希望应用程序的性能如何。最好的方法是在进行正式捆绑包分析后再决定它们的使用,我们将在下一节中讨论。

最佳实践

与所有编程一样,有最佳实践可以确保最佳交付。这也是结束本章的一个很好的方式。如果遵循最佳实践,开发人员可以保护他们的应用程序免受安全漏洞和黑客攻击、性能不佳以及在团队协作或未来开发需要新开发人员时出现困难,从而使构建具有未来性。这后一点更适用于产品所有者或项目经理,而不是开发团队。

在 Webpack 方面,这里最重要的领域将是捆绑包分析和代码清理。

捆绑包分析

一旦开始拆分代码,分析输出并检查模块的最终位置将是有用的。充分利用捆绑包非常重要,因此捆绑包分析的正式程序可以被视为基本的,以及浏览器和安全性测试。建议使用官方分析工具。还有一些其他选项:

webpack-bundle-analyzer:这是一个插件和 CLI 实用程序,它将捆绑包内容表示为方便的交互式树状图,其中有缩放选项。

webpack-bundle-optimize-helper:这个工具将分析您的捆绑包,并提出减小捆绑包大小的建议。

webpack-visualizer:这用于可视化分析捆绑包,以查看哪些模块占用了太多空间,哪些可能是重复的。

webpack-chart:这提供了一个用于 Webpack 统计的交互式饼图。

树状图是一种用于使用嵌套图形(通常是矩形)显示分层数据的方法。

所有先前提到的工具都将有助于优化,这是 Webpack 的主要目的。

代码清理

另一种改进应用程序的方法是通过删除不需要的代码。当自动化时,这通常被称为树摇,我们将在后面的章节中讨论。当手动进行时,它被称为代码清理。由于这是一个在编程中不经常遇到的短语,可能需要给出一个定义。

代码清理是删除不需要或多余代码的过程,就像从一件西装上除去绒毛一样。这可能包括未使用的编码工件、错误的代码或其他任何不需要的东西。Webpack 在与Gulp等任务运行器集成时使用自动化过程来执行此操作。这将在下一章第六章中讨论,生产、集成和联合模块。

如果您遵循这些步骤,那么毫无疑问,您的应用程序将发挥出最佳性能。代码拆分和模块化编程对于 Webpack 来说至关重要,需要牢固的理解,以防止在捆绑项目的复杂性不断提高时迷失方向。

总结

本章已经介绍了各种代码拆分实践,包括代码块和动态导入。现在,您将拥有扎实的知识基础,可以进行代码拆分和使用模块。这些是 Webpack 的基本特性,因此需要扎实的基础知识。

代码拆分和模块是 Webpack 应用程序结构上的必要性。对于需要大量编程的专业任务来说,代码块和动态导入将更加重要。

我们已经介绍了预取模块和捆绑分析——这些是需要清楚理解下一章内容的重要步骤,我们将在下一章中探讨配置的世界,了解其限制和能力,以及选项在其中发挥作用。

随着配置在 Webpack 开发中的中心地位和日常编程的重要性,这些概念变得更加重要。当涉及到生产环境并且需要项目正常运行时,选项变得更加重要。

为了测试您的技能,请尝试以下测验,看看您对本章涵盖的主题的理解是否达到标准。

问题

我们将以一组问题来结束本章,以测试您的知识。这些问题的答案可以在本书的后面,评估 部分找到。

代码拆分和模块化编程有何不同?

什么是代码块?

动态导入与入口点有何不同?

preload 指令与 prefetch 指令有何优势?

代码清理是什么意思?

术语“promise”是什么意思?

SplitChunksPlugin 如何防止重复?

webpack-bundle-optimize-helper 工具提供了什么?

webpack-chart 插件的作用是什么?

什么是树状映射?

进一步阅读

要查看完整的加载器列表,请转到 github.com/webpack-contrib/awesome-webpack。

第三章:使用配置和选项

本章将包括配置和选项的实际用法,以及它们在任何给定构建中的相互关系和作用。它还将详细说明输出管理,也就是捆绑过程的输出和资产管理,以及作为依赖图的一部分的资产。这将涵盖文件放置和文件结构等子主题。

模块用于解决 JavaScript 具有全局函数的特性。Webpack 与这些模块一起工作,并隔离了变量和函数的暗示全局性质。

配置和选项是必要的,以便充分利用 Webpack。每个项目都是定制的,因此每个项目都需要对其参数进行特定的定制。本章将详细探讨这两个主题的确切性质,每个主题的限制以及何时使用它们。

本章讨论以下主题:

理解配置

理解资产管理

理解输出管理

探索 Webpack 5 的选项

理解配置

通过使用配置文件,在 Webpack 中进行配置通常是webpack.config.js,除非在特殊情况下可以有一个以上的文件分配给这个任务。在webpack.config.js的情况下,它是一个 JavaScript 文件,应该被修改以改变任何特定项目的配置设置。

在启动时,Webpack 和 Webpack 5 不需要配置文件,但软件会将src/index识别为默认项目输入。它还将结果输出到名为dist/main.js的位置。这个输出将被"缩小"并优化为生产环境。

缩小,或最小化,简单地指的是 Webpack 的主要功能之一:将使用的代码量减少到最小。这是通过消除重复、错误或多余的代码来实现的。

然而,一个 Webpack 项目通常需要改变其默认配置。默认配置是 Webpack 在没有任何加载器或特殊参数的情况下运行的方式,比如在第一章中描述的Webpack 5 简介的Webpack 工作原理子部分。这是通过使用配置文件来完成的。开发人员应该创建一个名为webpack.config.js的文件,并将其放在项目的根文件夹中。这个文件将被 Webpack 自动检测和读取。

让我们通过探索使用多个配置文件来开始我们的讨论。

使用不同的配置文件

Webpack 5 提供了使用不同配置文件的选项,具体取决于情况。不仅如此,还可以使用命令行实用程序来更改正在使用的文件。在一个项目中使用多个捆绑包时,可能会遇到这种情况,这个主题将在本指南的后面详细介绍。以下代码片段显示了开发人员如何更改正在使用的配置文件。在这个例子中,一个文件被指向一个名为package.json的文件,这是 Webpack 经常使用的一个常见文件。这种技术被称为config flag:

"scripts": {

"build": "webpack --config example.config.js" }

请注意,Webpack 5 还允许自定义配置,正如在第一章中所解释的Webpack 5 简介,这是使用 Webpack 5 的一个显著优势。这是通过使用自定义配置文件来完成的。这与选项不同,因为这些变量不是使用命令行界面(CLI)设置的。

使用选项

在 Webpack 中,选项指的是通过命令行而不是配置文件进行的设置,这是通过修改配置脚本来完成的。

在下面的例子中,我们将首先修改配置文件,简单地为我们的选项教程奠定基础。

在接下来的配置中,Node 的路径模块被使用,并且前缀是_dirname全局变量。Node 的路径模块只是 Node 用于处理文件或目录路径的实用程序。在操作系统之间工作时可能会出现文件路径问题,这可以防止这些问题发生,并确保相对路径正常工作。

示例中涉及的文件名为webpack.config.js。我们将用它来设置项目的模式,并且我们需要在到达选项之前这样做:

const path = require('path');

module.exports = {

mode: "production", // "production" | "development" | "none"

entry: "./app/entry", // string | object | array

在前面的代码块中,所选择的模式指示 Webpack 相应地使用其内置的优化。entry路径默认为./src。这是应用程序执行开始和捆绑开始的地方。

下面的代码块将显示相同文件的其余部分:

output: {

path: path.resolve(__dirname, "dist"), // string

filename: "bundle.js", // string

publicPath: "/assets/", // string

library: "MyLibrary", // string,

libraryTarget: "umd", // universal module definition

},

代码片段的这一部分显示了与 Webpack 发出结果相关的选项。

所有输出文件的目标目录必须是绝对路径(使用Node.js路径模块)。

filename指示入口块的文件名模板,publicPath是统一资源定位符(URL),指的是相对于相关 HTML 页面解析到输出目录的路径。简而言之,这意味着从您可能使用的 HTML 页面到捆绑项目文件的文件路径。代码的其余部分涉及导出库的名称和导出库的性质。

接下来的主题涉及与模块相关的配置。在处理输出选项之后,这将是项目开发中的下一个逻辑步骤:

module: {

rules: [

{

test: /\.jsx?$/,

include: [

path.resolve(__dirname, "app")

],

exclude: [

path.resolve(__dirname, "app/demo-files")

],

前面的代码块包括了对模块的规则,比如解析器选项和加载器的配置。这些都是匹配条件,每个都接受一个字符串或正则表达式。术语test的行为与include相同。它们都必须匹配,但对于exclude来说并非如此。exclude优先于test和include选项。

为了最佳实践,RegExp应该只在文件名匹配时用于test。在使用路径数组时,应优先使用绝对路径而不是include和exclude选项。include选项应优先于exclude方法:

issuer: { test, include, exclude },

enforce: "pre",

enforce: "post",

loader: "babel-loader",

options: { presets: ["es2015"] },

},

{

test: /\.html$/,

use: [ "htmllint-loader",

{

loader: "html-loader",

options: {

/ *...* /

}

}

]

},

前面的代码块包括了对发行者和导入元素的来源的条件。代码还包括了标记这些规则的应用的选项,即使它们被覆盖了。然而,这是一个高级选项。

对loader的引用指示应用哪个加载器。这是相对于上下文位置解析的。自 Webpack 2 以来,加载器后缀不再是可选的,为了清晰起见。还有空间应用多个其他选项和加载器。

在相同的配置中,我们将探讨可以在同一过程中应用的规则和条件,如下面的代码块所示:

{ oneOf: [ / rules / ] },

{ rules: [ / rules / ] },

{ resource: { and: [ / conditions / ] } },

{ resource: { or: [ / conditions / ] } },

{ resource: [ / conditions / ] },

{ resource: { not: / condition / } }],

/* Advanced module configuration */

},

resolve: {

前面的代码块包括了嵌套规则,所有这些规则都与条件结合在一起是有用的。解释一下,注意以下每个命令及其表示的含义:

and选项只有在所有条件也匹配时才会进行匹配。

or匹配在条件匹配时应用——这是数组的默认值。

not指示条件是否不匹配。

还有一个选项用于解析模块请求;这不适用于解析加载器。以下示例显示了使用此resolve模块请求:

modules: [

"node_modules",

path.resolve(__dirname, "app")

], extensions: [".js", ".json", ".jsx", ".css"],

alias: {

"module": "new-module",

"only-module$": "new-module",

"module": path.resolve(__dirname, "app/third/module.js"),

},

},

performance: {

hints: "warning", // enum

maxAssetSize: 200000, // int (in bytes),

maxEntrypointSize: 400000, // int (in bytes)

assetFilter: function(assetFilename) {

return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');

}

},

前面的代码块显示了我们在本节中一直在遵循的相同配置文件。然而,让我们看一下一些关键元素。在path.resolve处,这指的是要查找模块的目录。直接下面的], extensions:指的是使用的文件扩展名。

在此部分之后是代码,按降序列出模块名称的别名列表。模块的别名是相对于当前位置上下文导入的,如下面的代码块所示:

devtool: "source-map", // enum

context: __dirname, // string (absolute path!)

target: "web", // enum

externals: ["react", /^@angular/],

serve: { //object

port: 1337,

content: './dist',

// ...

},

stats: "errors-only",

devtool配置通过为浏览器添加元数据来增强调试。请注意,source-map选项可能更详细,但这是以构建速度为代价的,web选项指示 Webpack 的主目录。入口和module.rules.loader选项相对于此目录解析,并指的是捆绑包应该运行的环境。serve配置允许您为webpack-serve提供选项,并精确控制显示哪些捆绑信息,例如以下内容:

devServer: { proxy: { // proxy URLs to backend development server '/api': 'http://localhost:3000' },

contentBase: path.join(__dirname, 'public'),

compress: true,

historyApiFallback: true,

hot: true,

https: false,

noInfo: true,

},

plugins: [

],

// list of additional plugins

让我们解释前面的代码块。当它声明compress: true时,这启用了内容的gzip压缩。historyApiFallback: true部分是当遇到任何 404 页面加载错误时为真。hot: true文本指的是是否允许热模块替换;这取决于是否首先安装了HotModuleReplacementPlugin。https应设置为true以用于自签名对象或证书授权对象。如果noInfo键设置为true,则只会在热重新加载时获得错误和警告。

配置完成,现在可以运行构建。要做到这一点,使用以下命令:

npx webpack-cli init

一旦在命令行环境中运行了前面的代码,用户可能会被提示安装@webpack-cli/init,如果它尚未安装在项目中。

运行npx webpack-cli init后,根据配置生成期间所做的选择,可能会在项目中安装更多的包。以下代码块显示了运行 NPX Webpack 的 CLI 初始化时的输出:

npx webpack-cli init

INFO For more information and a detailed description of each question, have a look at https://github.com/webpack/webpack-cli/blob/master/INIT.md

INFO Alternatively, run `webpack(-cli) --help` for usage info.

Will your application have multiple bundles? No

Which module will be the first to enter the application? [default: ./src/index]

Which folder will your generated bundles be in? [default: dist]:

Will you be using ES2015? Yes

Will you use one of the below CSS solutions? No

babel-plugin-syntax-dynamic-import@6.18.0

uglifyjs-webpack-plugin@2.0.1

webpack-cli@3.2.3

@babel/core@7.2.2

babel-loader@8.0.4

@babel/preset-env@7.1.0

webpack@4.29.3

added 124 packages from 39 contributors, updated 4 packages and audited

25221 packages in 7.463s

found 0 vulnerabilities

Congratulations! Your new webpack configuration file has been created!

如果你在 CLI 中的输出看起来像前面的代码块,那么你的配置就成功了。这基本上是从命令行自动读取的,应该表示在前面的代码块中设置的所有选项都已记录。

我们已经通过配置和选项,你现在应该知道每个选项的区别和使用范围。现在自然而然地转向资产管理。

理解资产管理

资产主要通过依赖图进行管理,我们在第一章中已经介绍过,Webpack 5 简介。

在 Webpack 伟大的出现之前,开发人员会使用诸如grunt和gulp之类的工具来处理这些资产,并将它们从源文件夹移动到生产目录或开发目录(通常分别命名为/build和/dist)。

JavaScript 模块也使用了相同的原则,但 Webpack 5 会动态捆绑所有依赖项。由于每个模块都明确声明了它的依赖项,未使用的模块将不会被捆绑。

在 Webpack 5 中,除了 JavaScript 之外,现在还可以包含任何其他类型的文件,使用加载器。这意味着使用 JavaScript 时可能的所有功能也可以被利用。

在接下来的小节中,我们将探讨实际的资产管理。将涵盖以下主题:

为资产管理配置设置项目

加载层叠样式表(CSS)文件

加载图像

加载字体

加载数据

添加全局资产

然后,将有一个小节来总结。

每个小节都将有步骤和指导内容要遵循。这可能是一个相当大的主题,所以紧紧抓住!我们将从准备项目的配置开始。

为资产管理配置设置项目

为了在项目中设置资产管理配置,我们需要通过以下步骤准备我们的项目索引和配置文件:

首先,通过使用dist/index.html文件对示例项目进行微小的更改,如下所示:

Asset Management

现在,使用webpack.config.js编写以下内容:

const path = require('path');

module.exports = {

entry: './src/index.js',

output: {

filename: 'bundle.js',

path: path.resolve(__dirname, 'dist')

}

};

前面的两个代码块只是显示了一个占位符索引文件,我们将用它来进行资产管理的实验。后一个代码块显示了一个标准配置文件,将索引文件设置为第一个入口点,并设置输出捆绑包的名称。这将在我们完成资产管理实验后为我们的项目准备捆绑。

您的项目现在已经设置好了资产管理配置。本指南现在将向您展示如何加载 CSS 文件。

加载 CSS 文件

示例项目现在将显示 CSS 的包含。这是一个非常容易掌握的事情,因为大多数从 Webpack 5 开始的前端开发人员应该对它很熟悉。

要加载 CSS 并运行构建,请执行以下步骤:

首先,使用以下命令行指令将style-loader和css-loader安装并添加到项目的模块配置中:

npm install --save-dev style-loader css-loader

接下来,向webpack.config.js文件添加以下内容:

const path = require('path');

module.exports = {

entry: './src/index.js',

output: {

filename: 'bundle.js',

path: path.resolve(__dirname, 'dist')

},

module: {

rules: [

{

test: /\.css$/,

use: [

'style-loader',

'css-loader'

]

}

]

}

};

从前面的代码块中可以看出,以下添加是指向代码块末尾的style-loader和css-loader的使用。为了避免出现错误,您应该确保您的代码与示例相符。

style-loader和css-loader之间的区别在于前者确定样式将如何被注入到文档中,比如使用样式标签,而后者将解释@import和require语句,然后解析它们。

建议同时使用这两个加载程序,因为几乎所有CSS操作在项目开发的某个阶段都涉及这些方法的组合。

在 Webpack 中,正则表达式用于确定应该查找哪些文件并将其提供给特定的加载程序。这允许将样式表导入到依赖它进行样式设置的文件中。当运行该模块时,一个带有字符串化 CSS 的