本章将包括配置和选项的实际使用,以及它们在任何给定的构建中是如何相互关联和发挥作用的。它还将详细说明输出管理,也就是说,捆绑过程的输出和资产管理是依赖图的一部分。这将涵盖诸如文件放置和文件结构等副主题。
模块被用来对抗 JavaScript 具有全局功能的特性。Webpack 与这些模块一起工作,并隔离变量和函数的隐含全局性质。
配置和选项是充分利用网络包的必要条件。每个项目都是定制的,因此每个项目都需要特定的参数定制。本章将详细探讨这两个主题的确切性质、各自的局限性以及何时利用它们。
本章将讨论以下主题:
- 了解配置
- 了解资产管理
- 理解输出管理
- 探索网络包 5 选项
通过使用配置文件(通常为webpack.config.js
)在 Webpack 中完成配置,除非在特殊情况下可以有多个(或另一个)文件分配给该任务。在webpack.config.js
的情况下,它是一个 JavaScript 文件,应该被修改以改变任何特定项目的配置设置。
启动时,Webpack 和 Webpack 5 不需要配置文件,但软件会将src/index
识别为默认项目输入。它还会将构建的结果输出到名为dist/main.js
的位置。该输出将被“缩小”并针对生产进行优化。
Minified, or minification, simply refers to one of Webpack's main functions: to reduce the amount of code used to a minimal amount. This is done by eliminating duplicate, erroneous, or surplus code.
但是,通常情况下,Webpack 项目需要更改其默认配置。默认配置是网络包在没有任何加载器或特殊参数分配的情况下如何工作,如第 1 章、网络包 5 简介中网络包如何工作小节所述。这是通过使用配置文件来完成的。开发人员应该创建一个名为webpack.config.js
的文件,并将其放在项目的根文件夹中。该文件将被 Webpack 自动检测和读取。
让我们从探索多个配置文件的使用开始讨论。
Webpack 5 根据情况提供了使用不同配置文件的选项。不仅如此,正在使用的文件也可以使用命令行工具进行修改。您可能会这样做的一种典型情况是在一个项目中使用多个包,这将在本指南后面的主题中详细介绍。下面的代码片段显示了开发人员如何更改正在使用的配置文件。在这个例子中,一个文件被定向到一个名为package.json
的文件,这是 Webpack 经常使用的一个公共文件。这种技术被称为配置标志:
"scripts": {
"build": "webpack --config example.config.js" }
请注意,网络包 5 还允许自定义配置,并且,如第 1 章、介绍网络包 5 中所述,这是使用网络包 5 的一个显著优势。这是通过使用自定义配置文件来完成的。这与选项不同,因为这些变量不是使用命令行界面 ( 命令行界面设置的。
网络包中的术语选项是指从命令行而不是配置中进行的设置,这是通过更改配置脚本来完成的。
在下面的例子中,我们将从修改配置文件开始,只是为我们的选项教程打下基础。
在以下配置中,节点的路径模块被使用,并以_dirname
全局变量作为前缀。节点的路径模块只是节点用来处理文件或目录路径的实用程序。在操作系统之间工作时,可能会出现文件路径问题,这可以防止这些问题的发生,并确保相对路径正确工作。
示例中涉及的文件称为webpack.config.js
。我们将使用它来设置项目的模式,在我们进入选项之前,我们需要这样做:
const path = require('path');
module.exports = {
mode: "production", // "production" | "development" | "none"
entry: "./app/entry", // string | object | array
在前面的代码块中,所选的 mod e 指示网络包相应地使用其内置的优化。条目路径将默认为./src
。这是应用开始执行和捆绑的地方。
以下代码块将显示同一文件的其余部分:
output: {
path: path.resolve(__dirname, "dist"), // string
filename: "bundle.js", // string
publicPath: "/img/", // string
library: "MyLibrary", // string,
libraryTarget: "umd", // universal module definition
},
这段代码片段显示了与 Webpack 如何发出结果相关的选项。
The target directory for all output files must be an absolute path (use the Node.js path module).
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 压缩。当遇到任何 404 页面加载错误时,historyApiFallback: true
部分为真。hot: true
文本指允许或不允许热模块更换;这以先安装HotModuleReplacementPlugin
为准。对于自签名对象或证书授权对象,https
应设置为true
。如果noInfo
键设置为true
,你只会在热重新加载时得到错误和警告。
配置完成,我们现在可以运行构建了。为此,请使用以下命令:
npx webpack-cli init
一旦前面的代码在命令行环境中运行,如果项目中还没有安装@webpack-cli/init
,用户可能会被提示安装。
运行npx webpack-cli init
后,根据配置生成过程中所做的选择,项目中可能会安装更多的包。以下代码块显示了运行 NPX 网络包的命令行界面初始化的打印输出:
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 中的输出看起来像前面的代码块,那么您的配置已经成功。它本质上是命令行的自动读出,应该表示在前面代码块中设置的所有选项都已被记录。
我们已经了解了配置和选项,现在您应该知道它们的区别以及各自的使用范围。现在转向资产管理是一个自然的过程。
资产主要通过依赖图进行管理,我们在网络包 5 的第 1 章中介绍了依赖图。
在 Webpack 出现之前,开发人员会使用工具,如咕噜和大口来处理这些资产,并将它们从源文件夹移动到生产目录或开发目录(通常分别命名为/build
和/dist
)。
同样的原则被用于 JavaScript 模块,但是 Webpack 5 动态地捆绑了所有的依赖项。因为每个模块都明确声明了它的依赖关系,所以不用的模块不会被捆绑。
在网络包 5 中,除了使用加载器的 JavaScript 之外,现在还可以包含任何其他类型的文件。这种方法意味着使用 JavaScript 时所有可能的特性都可以被利用。
在下一小节中,我们将探讨实用的资产管理。将涵盖以下主题:
- 为资产管理配置设置项目
- 加载级联样式表 ( CSS )文件
- 加载图像
- 加载字体
- 正在加载数据
- 添加全球资产
然后,将有一个关于总结的小节。
每个小节都有步骤和指导内容。这可能会成为一个相当大的话题,所以抓紧了!我们将从准备您项目的配置开始。
为了在您的项目中设置资产管理配置,我们需要通过执行以下步骤来准备项目索引和配置文件:
- 首先使用
dist/index.html
文件对示例项目进行小的更改,如下所示:
<!doctype html>
<html>
<head>
<title>Asset Management</title>
</head>
<body>
<script src="./bundle.js"></script>
</body>
</html>
- 现在,使用
webpack.config.js
,写下以下内容:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
前面两个代码块只是显示了一个占位符索引文件,我们将使用它来实验资产管理。后一个代码块显示了一个标准的配置文件,索引文件集作为输出包集的第一个入口点和名称。一旦我们完成了资产管理实验,这将为捆绑我们的项目做好准备。
现在将为资产管理配置设置您的项目。本指南现在将向您展示如何加载 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
。为了不出现任何错误,您应该确保您的代码反映了该示例。
The difference between style-loader
and css-loader
is that the former determines how styles will be injected into a document—such as with style tags, whereas the latter will interpret @import
and require
statements, and then resolve them.
建议两个加载器一起使用,因为几乎所有的 CSS 操作都在项目开发的某个时候涉及到这些方法的组合。
在 Webpack 中,正则表达式用于确定应该查找哪些文件并将其提供给特定的加载程序。这允许将样式表导入到依赖它进行样式设置的文件中。当该模块运行时,带有字符串化 CSS 的<style>
标签将被插入到 HTML 文件的<head>
中。
- 现在,导航到目录结构,我们可以在下面的示例中看到:
webpack5-demo
package.json
webpack.config.js
/dist
bundle.js
index.html
/src
style.css
index.js
/node_modules
从这个结构中我们看到有一个名为style.css
的样式表。我们将用这个来演示style-loader
的用法。
- 在
src/style.css
中输入以下代码:
.hello {
color: blue;
}
前面的代码只是创建了一个颜色类样式,我们将使用它来将样式附加到前端,并展示 CSS 加载是如何工作的。
- 同样,在
src/index.js
后添加以下内容:
import _ from 'lodash';
import './style.css';
function component() {
const element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'Webpack'], ' ');
element.classList.add('hello');
return element;
}
document.body.appendChild(component());
前面的代码都发生在index.js
文件中。它本质上创建了一个 JavaScript 函数,该函数在浏览器调用的任何文件中附加一个<div>
元素。在这个例子中,它将是index.html
文件,在目录结构图中提到过。然后,前面的代码将把一个 HTML 元素“连接”到网页上,并显示文本“Hello, Webpack
”。我们将用此测试style-loader
和css-loader
是否使用正确。正如脚本的注释部分所述,这个元素附加将自动导入lodash
用于 Webpack。
- 最后,运行
build
命令,如下所示:
npm run build
...
Asset Size Chunks Chunk Names
bundle.js 76.4 KiB 0 [emitted] main
Entrypoint main = bundle.js
...
当index.html
文件在浏览器窗口中打开时,您应该会看到“Hello Webpack
”现在是蓝色样式。
要查看发生了什么,请检查页面(不是页面源,因为它不会显示结果)并查看页面的标题标签。最好使用谷歌的 Chrome 浏览器。它应该包含我们在index.js
中导入的样式块。
You can—and in most cases, should—minimize CSS for better load times in production.
下一个自然的步骤是添加图像。图像可以像任何网站应用一样添加到项目中。将这些图像以任何所需的格式放在图像文件夹中。这必须在/src
文件夹中,但是它们可以位于那里的任何地方。下一个步骤是用 Webpack 加载图像,我们现在将完成这个步骤。
现在,让我们尝试使用文件加载器加载图像和图标,它可以很容易地集成到我们的系统中。
为此,请执行以下步骤:
- 使用命令行,安装
file-loader
,如下所示:
npm install --save-dev file-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'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
};
现在,由于上一个块中的代码,当您导入一个图像时,该图像将被处理到输出目录,并且与该图像相关联的变量将包含处理后该图像的最终 URL 。使用css-loader
时,你的 CSS 文件中的图像文件的 URL 也会发生类似的过程。加载程序将识别这是一个本地文件,并用输出目录中图像的最终路径替换本地路径。 html-loader
以同样的方式处理<img src="./my-image.png" />
。
- 接下来,要开始添加图像,您需要导航到项目文件结构,如下所示:
webpack5-demo
|- package.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
|- icon.png
|- style.css
|- index.js
|- /node_modules
除了增加了icon.png
图像文件之外,这个结构似乎与之前直接用于加载 CSS 文件教程的项目非常相似。
- 然后,导航到 JavaScript 前端文件
src/index.js
。以下代码块显示了内容:
import _ from 'lodash'; import './style.css';
import Icon from './icon.png';
function component() {
const element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'Webpack'], ' ');
element.classList.add('hello');
// Add the image to our existing div.
const myIcon = new Image(); myIcon.src = Icon;
element.appendChild(myIcon);
return element;
}
document.body.appendChild(component());
从前面的这个块中可以看出 lodash 的导入将允许您页面的 HTML 被添加Hello Webpack
文本。除此之外,这段代码只是使用一些巧妙的 JavaScript,用我们的图像来设置我们的网页。它首先创建一个名为Icon
的变量,并给出图像文件的网址的值。随后在代码中,它会将其分配给一个名为myIcon
的元素的源。
- 在这里,我们想要设置一些非常基本的样式来处理样式表中的图像。在
src/style.css
文件中,追加以下代码:
.hello {
color: red;
background: url('./icon.png');
}
当然,它会显示您的图像图标作为我们在 HTML 中指定代码的背景,无论应用.hello
类的地方,文本都变成红色。
- 运行新的构建并打开
index.html
文件,如下所示:
npm run build
...
Asset Size Chunks Chunk Names
da4574bb234ddc4bb47cbe1ca4b20303.png 3.01 MiB [emitted] [big]
bundle.js 76.7 KiB 0 [emitted] main
Entrypoint main = bundle.js
...
这将创建图标作为背景图像重复的效果。在Hello Webpack
文本旁边还会有一个img
元素。
通常,这个命令会出错,即使对于有经验的开发人员也是如此。例如,图像可能根本无法加载、太大或无法正确捆绑。这可能是由多种因素造成的,包括以不寻常的方式使用装载机。当使用长文件名时,Webpack 也可能遇到代码跳过。
如果是这种情况,只需重复以下步骤:
- 使用命令行安装
file-loader
。 - 如前例所述,更改
webpack.config.js
文件。 - 检查项目文件结构和索引文件的格式是否正确,以加载图像文件。
- 检查 CSS 是否也按照您想要的方式格式化。
- 然后,使用
npm
和命令行运行构建。 - 检查索引文件是否正确加载了图像。
如果检查该元素,可以看到实际的文件名已经更改为类似于da4574bb234ddc4bb47cbe1ca4b20303.png
的内容。这意味着 Webpack 在源文件夹中找到了我们的文件并对其进行了处理。
这为您管理图像提供了坚实的框架。在下一小节中,我们将讨论作为 Webpack 资产的字体管理。
现在,我们将在资产的上下文中检查字体。文件和网址加载器将接受您通过它们加载的任何文件,并将其输出到您的构建目录。这意味着我们可以将它们用于任何类型的文件,包括字体。
我们将从更新处理字体所需的 Webpack 配置 JavaScript 文件开始,如下所示:
- 确保对配置文件进行了更新。我们正在这里更新我们通常的
webpack.config.js
配置文件,但是您会注意到在接近末尾时,添加了一些字体类型,如.woff
、.woff2
、.eot
、.ttf
和.otf
,如以下代码块所示:
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'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
]
}
};
这个配置允许 Webpack 的file-loader
合并字体类型,但是我们仍然需要在我们的项目中添加一些字体文件。
- 我们现在可以执行将字体添加到源目录的基本任务。下面的代码块说明了一个文件结构,指出了可以添加新字体文件的位置:
webpack5-demo
|- package.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
|- sample-font.woff
|- sample-font.woff2
|- icon.png
|- style.css
|- index.js
|- /node_modules
注意src
目录和sample-font.woff
和sample-font.woff2
文件。这两个文件应该替换为您选择的任何字体文件。通常建议将网络开放字体 ( WOFF )格式用于网络包项目。
通过使用@font-face
声明,可以将字体合并到项目的样式中。Webpack 将以处理图像的相同方式找到本地 URL 指令。
- 使用
src/style.css
文件更新样式表,在我们的主页上包括示例字体。这是通过使用代码块顶部的字体声明和下面的类定义来完成的,如下面的代码块所示:
@font-face {
font-family: 'SampleFont';
src: url('./sample-font.woff2') format('woff2'),
url('./sample-font.woff') format('woff');
font-weight: 600;
font-style: normal;
}
.hello {
color: blue;
font-family: 'SampleFont';
background: url('./icon.png');
}
请注意,您必须将'SampleFont'
文本更改为与您选择的字体文件相对应的文本。前面的代码显示了通过 CSS 加载字体和设置自定义值,如font-weight
和font-style
。然后 CSS 代码使用.hello
类将该字体分配给任何预期的 HTML 元素。请注意,我们已经在前面的两个教程中为此准备了index.html
文件,加载 CSS 文件和加载图像。
- 现在,像往常一样使用命令行工具在开发模式下运行
npm
构建,如下所示:
npm run build
...
Asset Size Chunks Chunk Names
5439466351d432b73fdb518c6ae9654a.woff2 19.5 KiB [emitted]
387c65cc923ad19790469cfb5b7cb583.woff 23.4 KiB [emitted]
da4574bb234ddc4bb47cbe1ca4b20303.png 3.01 MiB [emitted] [big]
bundle.js 77 KiB 0 [emitted] main
Entrypoint main = bundle.js
...
再次打开index.html
,看看我们正在使用的Hello Webpack
示例文本是否已经更改为新字体。如果一切顺利,你应该看到变化。
这应该是一个理解字体管理的简单教程。下一节将介绍文件的数据管理,如可扩展标记语言 ( XML )和 JavaScript 对象符号 ( JSON )文件。
另一个可以加载的有用资产是数据。数据是非常重要的资产。这将包括诸如 JSON 、逗号分隔值 ( CSV )、制表符分隔值 ( TSV )和 XML 文件等文件。默认情况下,使用import Data from './data.json'
等命令会起作用,这意味着 JSON 支持内置于 Webpack 5 中。
要导入其他格式,必须使用加载器。下面的小节演示了处理这三者的方法。应采取以下步骤:
- 首先,您必须使用命令行安装
csv-loader
和xml-loader
加载器,如下所示:
npm install --save-dev csv-loader xml-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'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
},
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader'
]
},
{
test: /\.xml$/,
use: [
'xml-loader'
]
}
]
}
};
在前面的代码块中,下部显示了csv-loader
和xml-loader
的用法。这一次将需要这个修改来将数据加载到我们的项目中。
- 接下来,我们必须向源目录添加一个数据文件。我们将向我们的项目添加一个 XML 数据文件,在下面的代码块中以粗体文本显示:
webpack5-demo
|- package.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
|- data.xml
|- samplefont.woff
|- sample-font.woff2
|- icon.png
|- style.css
|- index.js
|- /node_modules
看看你的项目 等文件夹的src
目录中前面的data.xml
文件。让我们仔细看看这个文件,看看数据是什么,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tim</to>
<from>Jakob</from>
<heading>Reminder</heading>
<body>Call me tomorrow</body>
</note>
从前面的代码块中可以看到,内容是一个非常基本的 XML 数据集。我们将使用它来将 XML 数据导入到我们项目的index.html
页面中,我们将需要它被正确格式化以确保它能够工作。
这四种类型的数据( JSON 、 CSV 、 **TSV、**和 XML )中的任何一种都可以导入,导入到其中的数据变量将包含解析后的 JSON。
- 一定要修改
src/index.js
文件,露出数据文件。注意./data.xml
的导入,如下代码块所示:
import _ from 'lodash';
import './style.css';
import Icon from './icon.png';
import Data from './data.xml';
function component() {
const element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'Webpack'], ' ');
element.classList.add('hello');
// Add the image to our existing div.
const myIcon = new Image();
myIcon.src = Icon;
element.appendChild(myIcon);
console.log(Data);
return element;
}
document.body.appendChild(component());
这次我们只需要增加import
功能,其他的就可以演示用法了。任何对 JavaScript 足够熟悉的人都会知道如何利用它来非常容易地运行他们的特定项目。
- 运行构建并检查数据加载是否正确,如下所示:
npm run build
一旦运行了npm
构建,就可以打开index.html
文件。检查控制台(如使用 Chrome 时在开发工具下)会显示导入后记录的数据。
与项目架构相关但更相关的是项目消费的全球资产安排。让我们在下一小节中探讨这一点。
以上述方式加载资产允许模块以更直观、实用和可用的方式组合在一起。
不是使用包含每个资产的全局资产目录,而是可以用使用它们的代码对资产进行分组。下面的归档结构或树展示了一个非常实用的例子:
|- /assets
|– /components
| |– /my-component | | |– index.jsx
| | |– index.css
| | |– icon.svg
| | |– img.png
前面的例子让你的代码更容易移植。如果您想将一个组件放在另一个目录中,只需将其复制或移动到那里。或者,如果您的开发遵循传统路线,可以使用基础目录。此外,混叠也是一种选择。
这是一个很长的教程,你的一些代码可能会误入歧途。清理这段代码并检查是否有任何错误是一个很好的做法。
打扫卫生是一个好习惯。在下一节理解输出管理中,我们不会使用大量的资产,所以让我们从这里开始。
- 我们开始总结项目目录,项目树。让我们检查一下他们是否正确。它应该如下所示:
webpack5-demo
|- package.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
|- data.xml
|- sample-font.woff
|- sample-font.woff2
|- icon.png
|- style.css
|- index.js
|- /node_modules
当我们结束时,您应该删除对应于前面代码块中加粗文本的文件。
这应该会让您对项目文件和文件夹的外观有一个很好的了解。确保我们一直使用的所有文件都在那里,并且在适当的文件夹中。
- 让我们检查一下配置的格式。
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'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
},
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader'
]
},
{
test: /\.xml$/,
use: [
'xml-loader'
]
}
]
}
};
请注意在单独的处理程序如.csv
和.xml
中对 CSS、图像文件、字体如.woff
和数据文件的大量引用。所有这些都很重要,您应该花时间确保脚本是准确的,因为这是一个广泛的主题和实践练习,所以很多事情可能被忽略了。
- 接下来,我们需要检查
src/index.js
文件的脚本,如下所示:
import _ from 'lodash';
import './style.css';
import Icon from './icon.png';
import Data from './data.xml';
function component() {
const element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'Webpack'], ' ');
element.classList.add('hello');
// Add the image to our existing div.
const myIcon = new Image();
myIcon.src = Icon;
element.appendChild(sampleIcon);
console.log(Data);
return element;
}
document.body.appendChild(component());
再一次,我们在这里总结,这样代码在遵循了使用它的多个教程之后就可以重用了,所以一定要删除版本中的加粗文本。
我们已经浏览了资产管理操作的广泛列表,并以项目整理过程结束。您的所有代码应该看起来像总结部分中的前面的代码块,这样才能正确运行。
现在,您应该对 Webpack 如何管理这些资产,以及在使用 Webpack 时如何管理它们有了很好的理解。随着文件结构和代码的清理和整理,我们现在最适合开始输出管理。
输出是指从源文件创建的包。源文件在网络包中被称为输入。输出管理是指管理这些新捆绑的文件。根据构建开始时 Webpack 运行的模式,这些包将是开发包或生产包。
Webpack 从源文件生成输出或包的过程称为编译。编译是 Webpack 5 组装信息的过程,包括资产、文件和文件夹。配置的主题与 Webpack 中可能的各种选项和配置有关,这将改变编译的风格和方法。
开发捆绑包允许一些定制(比如本地测试),但是生产捆绑包是已经完成并完全压缩的版本,准备发布。
在本章中,资产已经被手动添加到索引 HTML 文件中。随着项目的增长,手动处理将变得困难,尤其是在使用多个包时。也就是说,有一些插件可以让这个过程变得更容易。
我们现在将讨论这些选项,但是从准备您现在非常繁忙的项目结构开始,随着项目的发展,这将成为一个越来越重要的实践。
首先,让我们稍微调整一下我们的项目文件结构树,让事情变得更容易。该过程遵循以下步骤:
- 首先在项目文件夹中定位
print.js
文件,如下所示:
webpack5-demo
|- package.json
|- webpack.config.js
|- /dist
|- /src
|- index.js |- print.js |- /node_modules
请注意我们的项目结构中增加的内容——特别是print.js
文件。
- 通过向
src/print.js
文件添加一些逻辑来追加代码,如下所示:
export default function printIt() {
console.log('This is called from print.js!');
}
您应该在src/index.js
文件中使用printIt()
JavaScript 函数,如前面的代码块所示。
- 准备
src/index.js
文件导入需要的外部文件,并在里面写一个简单的函数允许交互,如下:
import _ from 'lodash';
import printMe from './print.js';
function component() {
const element = document.createElement('div');
const btn = document.createElement('button');
element.innerHTML = _.join(['Hello', 'Webpack'], ' ');
btn.innerHTML = 'Click here then check the console!';
btn.onclick = printIt();
element.appendChild(btn);
return element;
}
document.body.appendChild(component());
我们更新了我们的index.js
文件,在顶部导入了print.js
文件,在底部有一个新的printIt();
功能按钮。
- 我们必须更新
dist/index.html
文件。此更新是在准备将条目拆分出来时完成的,如以下代码块所示:
<!doctype html>
<html>
<head>
<title>Output Management</title>
<script src="./print.bundle.js"></script>
</head>
<body>
<script src="./app.bundle.js"></script>
</body>
</html>
前面的 HTML 脚本将加载到print.bundle.js
文件中,下面的bundle.js
和app.bundle.js
文件中。
- 接下来,确保项目的配置符合动态入口点。将添加
src/print.js
文件作为新的入口点。输出也将被更改,以便基于入口点名称动态生成包的名称。在webpack.config.js
中,由于这个自动过程,不需要更改目录名。以下代码块显示了webpack.config.js
的内容:
const path = require('path');
module.exports = {
entry: './src/index.js',
entry: {
app: './src/index.js',
print: './src/print.js'
},
output: {
filename: 'bundle.js',
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
配置只是为我们正在处理的新文件index.js
和print.js
设置新的入口点。
- 确保您执行了构建。运行
npm
构建后,您将看到以下内容:
...
Asset Size Chunks Chunk Names
app.bundle.js 545 kB 0, 1 [emitted] [big] app
print.bundle.js 2.74 kB 1 [emitted] print
...
在浏览器中打开index.html
文件后,你会看到 Webpack 生成了print.bundle.js
和app.bundle.js
文件。我们现在应该检查它是否有效!如果入口点名称被更改或增加新名称,则索引 HTML 仍会引用旧名称。这可以用HtmlWebpackPlugin
来纠正。
例如,HtmlWebpackPlugin
将允许网络包处理包含 JavaScript 的 HTML 文件。要开始使用它,我们需要使用命令行安装它,然后正确设置配置,如下所示:
- 首先,使用命令行工具安装插件,然后调整
webpack.config.js
文件,如下所示:
npm install --save-dev html-webpack-plugin
前面的代码块显示了用于我们项目的HtmlWebpackPlugin
的安装。
- 接下来,我们必须将插件合并到我们的配置中。我们来看看
webpack.config.js
文件与这个插件关联时的情况,如下:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'Output Management'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
请注意require
表达式和plugins:
选项键的使用,这两个键都用于允许插件的使用。
运行构建之前,请注意HtmlWebpackPlugin
将默认生成其index.html
文件,即使dist/
文件夹中已经有一个文件。因此,现有文件将被覆盖。
For best practice, make a copy of the existing index file and name it something like index2.html
.Place this new file next to the original, and then run the build.
- 现在,使用命令行实用程序运行构建。完成此操作后,您将在命令行实用程序窗口中看到以下结果,表明绑定成功:
...
Asset Size Chunks Chunk Names
print.bundle.js 544 kB 0 [emitted] [big] print
app.bundle.js 2.81 kB 1 [emitted] app
index.html 249 bytes [emitted]
...
在你的代码编辑器或记事本中打开index.html
文件,会显示插件已经创建了一个新文件,所有的包都被自动添加。
Also, why not look at html-webpack-template
, which provides a few extra features on top of the default template?
我们的网络包教程HtmlWebpackPlugin
到此结束。在下面的小节中,我们将再次开始整理您的项目目录。
在这个项目开发过程中,/dist
文件夹会变得相当混乱。良好的实践需要良好的组织,这需要在每次构建之前清理/dist
文件夹。有一个clean-webpack-plugin
插件可以帮你做到这一点,如下所示:
- 首先安装
clean-webpack-plugin
。以下示例向您展示了如何做到这一点:
npm install --save-dev clean-webpack-plugin
一旦插件安装完毕,我们就可以重新研究配置文件了。
- 使用
webpack.config.js
,在文件中做如下条目:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'Output Management'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
注意CleanWebpackPlugin
的使用,继续const
限定词。这将增加module.export
插件选项,该选项创建一个与插件相关联的新功能,并使该插件在编译期间可由网络包使用。
- 您现在应该运行一个
npm
构建,它将输出一个包到/dist
分发文件夹。
运行npm
构建后,可以检查/dist
文件夹。假设流程运行正常,您应该只看到新生成的文件,而不再看到旧文件。
我们已经生成了很多文件,为了帮助我们保持跟踪,有一种叫做清单的东西,我们将在下一部分介绍它。
由于清单,Webpack 可以知道正在生成哪些文件。这允许软件跟踪所有输出包并映射模块。要以其他方式管理输出,最好使用清单。
Webpack 本质上按照三种类型对代码进行分类:由开发人员编写的源代码;由第三方编写的供应商代码;和 Webpack 的运行时清单,它指导所有模块的交互。
运行时和清单数据是 Webpack 在浏览器中运行时连接模块化应用所需要的。
如果您决定通过使用浏览器缓存来提高性能,这个过程将成为一个需要处理的重要事情。
通过在包文件名中使用内容哈希,您可以向浏览器指示文件内容何时发生了更改,从而使缓存失效。这是由运行时和清单的注入引起的,它们随着每次构建而变化。
网络包有WebpackManifestPlugin
可以将清单数据提取到 JSON 文件中。
现在,您已经了解了如何向 HTML 动态添加包,让我们来深入了解一下开发指南。或者,如果您想深入更高级的主题,我们建议您重读上一章中本指南的 C 代码拆分部分、第 2 章、使用模块和代码拆分。
选项是一组可以使用命令行界面更改的变量。另一方面,配置是通过改变文件内容来完成的。但是,可以使用配置文件调整选项的设置。以下是 Webpack 5 当前支持的选项列表:
- 异步模块定义 ( AMD )
- 保释
- 隐藏物
- 装货设备
- 平行
- 轮廓
- 记录路径
- 记录输入路径
- 记录输出路径
- 名字
下面的部分描述和说明了每个选项的更多细节。我们将从一些东西开始,在粗略检查网络包的配置后,可能会发现你挠头:AMD 选项。
AMD 是一个object bool: false
选项。它也是异步模块定义的缩写。本质上,它是一种为开发人员提供模块化 JavaScript 解决方案的格式。该格式本身是一个定义模块的建议,其中模块和依赖项都可以异步加载。
这允许您设置require.amd
或define.amd
的值。将amd
设置为false
将禁用 AMD 支持。
查看webpack.config.js
文件内部,如下:
module.exports = {
amd: {
jQuery: true
}
};
适用于 AMD 的流行模块,如 jQuery 版本 1.7.0 至 1.9.1,只有在加载器指示允许在一个页面上使用多个版本时,才会注册为 AMD 模块。另一个类似的选项,作为布尔变量,是贝尔。让我们仔细看看。
保释是一个bool
值。这将迫使 Webpack 退出捆绑过程。这将导致 Webpack 在第一个错误上失败,而不是容忍它。默认情况下,网络包会在终端(也是浏览器控制台,使用 HMR 时)以红色文本记录这些错误,但会继续捆绑。
要启用该选项,请打开webpack.config.js
,如下所示:
module.exports = {
bail: true
};
如果您希望 Webpack 在某些情况下退出捆绑过程,这将非常有帮助。也许你只想捆绑项目的一部分。这真的取决于你。接下来是缓存。
缓存是指bool
对象的术语。它将缓存生成的网络包模块和块;这提高了构建的速度。它通过在可以共享的编译器调用之间保持对该对象的引用来实现这一点。在观看模式和开发模式下,默认情况下启用缓存。
In watch mode, after the initial build, Webpack will continue to watch for changes in any of the processed files. Essentially, the Webpack configuration JavaScript file should include the watch: true
operand inside the module.export
operator.
要启用缓存,请使用 webpack.config.js 将其手动设置为true
,如下例所示:
module.exports = {
cache: false
};
webpack.config.js
文件显示了允许共享缓存所需的配置,如下所示:
let SharedCache = {};
module.exports = {
cache: SharedCache
};
前面两个示例显示了设置为false
和sharedCache
的缓存配置。这是可以在网络包中设置的两个布尔值。
Warning: The cache should NOT be shared between calls with different options.
在网络包中还可以设置几个选项:加载器、并行度、配置文件、记录路径、记录输入路径、记录输出路径和名称。让我们现在一次一个地看完每一个。
这表示为loader
,并在加载器上下文中公开自定义值,如以下代码块所示:
use: [
{
loader: worker-loader
}
]
从前面的代码示例中,您可以看到如何在配置文件中使用该选项。遵循本指南并配置加载器的任何人都应该熟悉这个示例。本例仅通过举例的方式使用worker-loader
。其中一些选项是布尔值或二进制值,如下面描述的profile
选项。
profile
选项将捕获应用的概要文件,然后可以使用分析工具对其进行分析,如以下代码片段所示:
profile: true,
请注意,这是一个布尔值。您可以使用StatsPlugin
对配置文件进行更多控制。这也可以与parallelism
选项结合使用,以获得更好的效果。
并行性将限制并行处理模块的数量。这可用于微调性能或更可靠的分析。下面的例子给出了极限数1
,但是你可以随意修改:
parallelism: 1
Webpack 5 允许使用并行处理的模块以及并行捆绑。这可能会消耗内存,因此在大型项目中应该注意这个选项。
随着项目变得越来越复杂,您可能希望记录编译过程,这有助于跟踪 bug 和错误。记录路径会帮你做到这一点,我们现在就来仔细看看。
记录路径选项表示为字符串。该选项应该用于生成包含记录的 JSON 文件。这些是用于跨多个构建存储模块标识符的数据。这可以用来跟踪模块如何在构建之间改变。要生成一个,只需使用webpack.config.js
文件指定一个位置,如下例所示:
module.exports = {
recordsPath: path.join(__dirname, 'records.json')
};
如果您有一个使用代码拆分的复杂项目,记录会很有用。这些记录的数据可以用来确保在使用拆分包时缓存行为正确。
即使编译器生成了这个文件,也应该使用源代码控制来跟踪它,并保留它随时间的使用历史。
设置recordsPath
也会将recordsInputPath
和recordsOutputPath
设置到同一位置。
该选项表示为一个字符串,recordsInputPath
,如下面的代码块所示:
module.exports = {
recordsInputPath: path.join(__dirname, 'records.json'),
};
它将指定从中读取最后一组记录的文件,并可用于重命名记录文件。相关的是记录输出路径选项,我们现在将讨论它。
记录输出路径是一个字符串,指定记录应该被写入的位置。下面的代码示例显示了在重命名记录文件时,如何将此选项与recordsInputPath
结合使用。我们将使用webpack.config.js
来做到这一点:
module.exports = {
recordsInputPath: path.join(__dirname, 'records.json'),
recordsOutputPath: path.join(__dirname, 'outRecords.json')
};
前面的代码将设置记录的写入位置。如果是输入记录,会写入__dirname/records.json
。如果是输出记录,会写入__dirname/newRecords.json
。
我们需要讨论的下一个选项是名称选项。
名称选项表示为一个字符串,表示配置的名称。它应该在加载多个配置时使用。以下示例显示了应构成webpack.config.js
文件一部分的代码:
module.exports = {
name: 'admin-app'
};
当使用多个配置文件时,前面的代码很有用。代码将该配置文件命名为admin-app
。这给了你一个选项和如何使用它们的长纲要。现在让我们看一下本章中我们已经讲述的内容。
本章遵循了配置文件、资产管理和选项的实践。本章首先向读者介绍网络包和配置的各种功能,并探讨如何管理这些资产和相应地控制内容。指导您完成输入和输出管理,以及字体和图像等外部内容的加载。从那里,本章带我们了解了选项和两者之间的区别,向读者解释了使用可以通过配置简单设置的选项可以实现什么。
然后,您将被引导学习常用的选项方法以及如何使用它们。您现在完全精通选项和配置。现在,您应该知道这两种方法之间的区别以及要采用的最佳方法,因为任何一种方法都有多种可能性。
在下一章中,我们将探究 API 加载器和插件的世界。Webpack 的这些特性阐述了平台的功能、配置的回弹和选项。
您将了解加载器和插件之间的区别,以及加载器使用默认不支持的语言和脚本的本质。这些加载器大多由第三方开发人员提供,因此插件填补了加载器无法使用的功能空白,反之亦然。
类似的主题将在以后展开。API 本质上用于将应用连接到网络上的远程应用。这赋予了它们与加载器相似的特性,并且它们经常在本地脚本不可用的地方使用。
为了帮助您学习,这里有一组关于本章所涵盖主题的问题(您可以在本指南的后面找到答案):
- Webpack 5 的配置和选项有什么不同?
- 什么是配置标志?
- 将图像加载到 Webpack 项目中需要哪个加载器?
- Webpack 不使用加载程序就允许导入什么类型的数据文件?
- Webpack 的清单记录表明了什么?
- 保释选项有什么作用?
- 并行选项有什么作用?
- “记录输入路径”选项有什么作用?
- 将 AMD 设置为
false
会有什么作用? - 什么是编译?