Webpack初学者指南
如今,我们被迫使用许多辅助工具来促进、加速和优化我们的web开发工作流程。但是,这类工具通常会在堆栈中增加额外的复杂性。因此,我们需要利用额外的时间和精力来正确地学习、理解和使用这些工具。同样适用于webpack.
第一次使用webpack时,可能很难理解它是如何工作的以及应该如何使用它。尽管它有很好的文档,但对于新手来说可能会令人生畏,而且它有一个陡峭的学习曲线。然而,webpack是值得学习的,从长远来看可以节省大量的时间和精力。在本教程中,我将介绍所有的核心概念来帮助您入门。
注意:在本教程中,我使用的是webpack 5.9.0。
什么是Webpack?
webpack的核心是一个静态模块捆绑器。在一个特定的项目中,webpack将所有文件和资产视为模块。在底层,它依赖于一个依赖关系图。依赖关系图描述了模块如何使用引用(需要而且进口语句)之间的文件。通过这种方式,webpack静态地遍历所有模块来构建图形,并使用它来生成一个包(或几个包)——一个JavaScript文件,其中包含所有模块以正确顺序组合的代码。“静态”的意思是,当webpack构建它的依赖关系图时,它不执行源代码,而是将模块和它们的依赖关系拼接成一个包。然后可以将其包含在HTML文件中。
现在,为了扩展上述粗略的概述,让我们来探索webpack使用的主要概念。
Webpack主要概念
Webpack有一些主要的概念,在深入研究它的实际实现之前,我们需要清楚地了解这些概念。让我们来逐一分析一下:
- 条目:入口点是webpack用来开始构建内部依赖关系图的模块。从那里,它确定入口点(直接或间接)依赖于哪些其他模块和库,并将它们包含在图中,直到没有依赖关系。默认情况下,条目属性设置为
/ src / index.js
,但是我们可以在webpack配置文件中指定一个不同的模块(甚至多个模块)。 - 输出: output属性指示webpack在哪里发出bundle,以及为文件使用什么名称。此属性的默认值为
/ dist / main.js
对于主包和/ dist。
对于其他生成的文件,例如图像。当然,我们可以根据需要在配置中指定不同的值。 - 加载器:默认情况下,webpack只理解JavaScript和JSON文件。为了处理其他类型的文件并将它们转换为有效的模块,webpack使用了加载器。加载器转换非javascript模块的源代码,允许我们在将这些文件添加到依赖关系图之前对它们进行预处理。例如,加载器可以将文件从CoffeeScript语言转换为JavaScript,或将内联图像转换为数据url。使用加载器,我们甚至可以直接从JavaScript模块导入CSS文件。
- 插件:插件用于加载器不能做的任何其他任务。他们为我们提供了关于资产管理、捆绑包最小化和优化等广泛的解决方案。
- 模式:通常,当我们开发应用程序时,我们使用两种类型的源代码——一种用于开发版本,另一种用于生产版本。Webpack允许我们通过改变mode参数来设置我们想要生产哪一个发展,生产或没有一个.这允许webpack使用相应于每个环境的内置优化。默认值为生产.的没有一个模式意味着不使用默认优化选项。以了解更多关于webpack在发展而且生产模式,访问模式配置页面.
Webpack如何工作
在本节中,我们将研究webpack是如何工作的。即使是一个简单的项目也包含HTML、CSS和JavaScript文件。此外,它还可以包含字体、图像等资产。所以,一个典型的webpack工作流将包括设置一个index . html
文件和适当的CSS和JS链接,以及必要的资产。此外,如果你有许多相互依赖的CSS和JS模块,它们需要被优化并适当地组合在一个单元中,以便生产。
要做到这一切,webpack依赖于配置。从版本4及以上开始,webpack提供了合理的开箱即用的默认值,因此不需要创建配置文件。然而,对于任何重要的项目,你需要提供一个特殊的webpack.config.js
文件,它描述了应该如何转换文件和资产,以及应该生成什么样的输出。这个文件很快就会变成一个整体,这使得你很难理解webpack是如何工作的,除非你知道它工作背后的主要概念。
基于提供的配置,webpack从入口点开始,解析它在构建依赖关系图时遇到的每个模块。如果模块包含依赖项,则对每个依赖项递归执行该过程,直到遍历完成。然后webpack将项目的所有模块捆绑成少量的包——通常只有一个——由浏览器加载。
Webpack 5有什么新功能
webpack 5发行版是在2020年10月宣布的.这篇文章很长,探讨了webpack的所有变化。不可能提到所有的变化,对于这样的初学者指南来说,这是不必要的。相反,我将试着列出一个小列表,其中有一些一般的亮点:
- 使用持久缓存可以提高构建性能。开发人员现在可以启用基于文件系统的缓存,这将加快开发构建的速度。
- 长期缓存也得到了改进。在webpack 5中,对不影响最小化bundle版本(注释,变量名)的代码所做的更改不会导致缓存失效。此外,还添加了新的算法,以确定的方式将短数字id分配给模块和块,并将短名称分配给导出。在webpack 5中,它们在生产模式下默认启用。
- 改进了包的大小,这要归功于更好的摇树和代码生成。多亏了新的嵌套摇树特性,webpack现在能够跟踪对导出的嵌套属性的访问。CommonJs树摇动允许我们消除未使用的CommonJs导出。
- 支持的Node.js最低版本从6增加到10.13.0 (LTS)。
- 代码库被清理。所有在webpack 4中标记为弃用的项目都被移除。
- 自动Node.js填充被移除。之前版本的webpack包含了本地Node.js库的腻子
加密
.在许多情况下,它们是不必要的,并且会极大地增加包的大小。这就是为什么webpack 5不再自动填充这些核心模块,而是专注于前端兼容模块。 - 作为开发的一个改进,webpack 5允许我们传递一个目标列表,也支持目标的版本。它提供了公共路径的自动确定。此外,它提供了自动的、唯一的命名,这可以防止多个webpack运行时使用相同的全局变量进行块加载之间的冲突。
- 的
webpack-dev-server
命令就是现在webpack服务
. - 资产模块分别介绍一下,哪些替代的用途
file-loader
,raw-loader
,url-loader
.
请打开上面的公告链接,以查找有关所有更新的更完整和详细信息。
最后,如果你来自webpack 4,这里是迁移向导.
开始
注意:您可以在GitHub回购.
既然我们有了坚实的理论基础,我们就把它付诸实践吧。
首先,我们将创建一个新目录并切换到它。然后我们将初始化一个新项目:
mkdirlearn-webpackcdlearn-webpacknpminit - y
接下来,我们需要在本地安装webpack和webpack CLI(命令行接口):
npm安装Webpack -cli—save-dev
现在,内容生成了package.json
应类似于以下内容:
{“名称”:“learn-webpack”,“版本”:“1.0.0”,“描述”:"",“主要”:“index.js”,“脚本”:{“测试”:"echo \"错误:没有指定测试\" && exit 1"},“关键词”:[],“作者”:"",“许可证”:“ISC”,“devDependencies”:{“webpack”:“^ 5.9.0”,“webpack-cli”:“^ 4.2.0”}}
除了作为一个包装经理,npm
可以用作简单的任务运行器。创建webpack任务的方法是在脚本
部份package.json
文件。让我们现在试试这个。开放package.json
然后改变脚本
反对以下内容:
“脚本”:{“测试”:"echo \"错误:没有指定测试\" && exit 1",“开发”:webpack模式开发,“构建”:webpack模式生产},
在脚本
财产,npm
允许我们通过名称引用本地安装的Node.js包。我们用它和——模式
要定义的标志dev
而且构建
任务,将在开发中运行webpack (运行开发
)和生产(NPM运行构建
)模式。
在测试刚刚创建的任务之前,让我们先创建一个src
目录,并将index.js
文件,以便它包含console.log(“你好,Webpack !”);
.现在我们已经可以运行dev
以开发模式启动webpack的任务:
$npm运行开发>learn-webpack@1.0.0 dev C:\WEBDEV\learn-webpack>Webpack模式开发[webpack-cli]编译完成的资产main.js874字节[发出](名称:主要)/ src / index.js31字节[建][生成的代码]webpack5.9.0编译成功在122女士
正如我前面提到的,webpack将默认入口点设置为/ src / index.js
和默认输出到/ dist / main.js
.webpack在运行dev
任务是获取源代码index.js
文件并将最终代码打包到main.js
文件。
太棒了!它像预期的那样工作。但是为了验证我们得到了正确的输出,我们需要在浏览器中显示结果。要做到这一点,让我们创建一个index . html
在经销
目录:
<!文档类型超文本标记语言><超文本标记语言><头><标题>Webpack入门标题>头><身体><脚本src="main.js">脚本>身体>超文本标记语言>
现在,如果我们在浏览器中打开该文件,我们应该会看到你好,Webpack !消息。
到目前为止,一切顺利。但是写我们index . html
手动文件在某些情况下可能会有问题。例如,如果我们改变了入口点的名称,生成的bundle将被重命名,但是我们的index . html
文件仍将引用旧名称。因此,每次重命名入口点或添加新入口点时,我们都需要手动更新HTML文件。幸运的是,我们可以使用html-webpack-plugin
.让我们现在安装它:
npm安装html-webpack-plugin@next——save-dev
注意:注意我已经输入了html-webpack-plugin@next
而不仅仅是html-webpack-plugin
.在撰写本文时,前者是webpack 5的合适版本,后者是webpack 4的合适版本。这在将来可能会更改,因此对于实际版本,请检查html-webpack-plugin回购.
此时,要激活插件,我们需要创建一个webpack.config.js
根目录下的文件,内容如下:
常量HtmlWebpackPlugin=需要(“html-webpack-plugin”);常量路径=需要(“路径”);模块.出口={插件:[新HtmlWebpackPlugin({标题:“Webpack输出”,}),],};
如您所见,要激活webpack插件,我们需要将其包含在文件中,然后将其添加到插件
数组中。如果需要,我们还将选项传递给插件。看到html-webpack-plugin
回购的所有可用选项还有能力编写并使用自己的模板.
现在让我们运行webpack看看会发生什么:
$npm运行开发>learn-webpack@1.0.0 dev C:\WEBDEV\learn-webpack>Webpack模式开发[webpack-cli]编译完成的资产main.js874字节[相比为发出](名称:主要)资产index . html234字节[发出]/ src / index.js31字节[建][生成的代码]webpack5.9.0编译成功在151女士
让我们打开index . html
.正如我们所看到的,插件自动创建了一个updatedindex . html
文件,它使用标题
选项从配置:
<!文档类型超文本标记语言><超文本标记语言><头><元字符集="utf - 8"><标题>Webpack输出标题><元的名字="视窗"内容="宽度=设备宽度,初始= 1"><脚本推迟src="main.js">脚本>头><身体>身体>超文本标记语言>
对象的自定义名称条目
而且输出
属性。在webpack.config.js
的前面添加了以下内容插件
属性:
条目:{主要:路径.解决(__dirname,“/ src / app.js。”),},输出:{文件名:“[名字].bundle.js”,路径:路径.解决(__dirname,“部署”)},
在这里,我们将条目文件更改为app.js
和输出文件夹到部署
.我们还稍微调整了一下生成的包文件的名称。现在,它将以条目的名称(“main”)开头,后面跟着单词“bundle”和. js
文件扩展名。
现在,我们要创建一个src / component.js
文件:
出口默认的(文本=“你好,Webpack !”)= >{常量元素=文档.createElement(“标题”);元素.innerHTML=文本;返回元素;};
接下来,我们重命名index.js
来app.js
为反映我们的变化,将其内容替换为以下内容:
进口组件从”。/组件的;文档.身体.列表末尾(组件());
现在,让我们再次运行webpack:
$npm运行开发>learn-webpack@1.0.0 dev C:\WEBDEV\learn-webpack>Webpack模式开发[webpack-cli]编译完成的资产main.bundle.js4.67简约[发出](名称:主要)资产index . html241字节[发出]运行时模块668字节3.可缓存模块230字节。/ src / app.js79字节[建][生成的代码]/ src / component.js151字节[建][生成的代码]webpack5.9.0编译成功在194女士
让我们检查并澄清来自webpack输出的信息。在“编译完成”消息之后,您可以看到在部署
目录(main.bundle.js
而且index . html
).在它们下面,您可以看到源文件:app.js
)及其依赖项(component.js
).
现在,在部署
文件夹中,我们有新生成的bundle文件main.bundle.js
.如果我们打开index . html
文件在浏览器中,我们应该看到你好,Webpack !显示在页面中。
还有,如果我们查一下来源index . html
的值src
的财产脚本
标签被更新为main.bundle.js
.
此时,我们可以删除经销
文件夹,webpack最初生成的,因为我们不再需要它了。
将现代JavaScript翻译到ES5
在本节中,我们将了解如何将ES6转换为兼容es5的代码,并在所有浏览器中都能运行。让我们首先运行以下命令:
npm执行命令dev -- --devtool inline-source-map
这里,我运行webpackdevtool
选项设置为inline-source-map
为了使代码更具可读性。这样我可以更清楚地演示从ES6到ES5的代码转换。
接下来,让我们打开main.bundle.js
:
/ * * * /”。/ src / component.js ": /*!**************************!*** ./src/component.js ***!\**************************// * !命名空间导出*// * !导出默认[已提供][无使用信息][缺少使用信息防止重命名]*// * !其他导出[未提供][无使用信息]*// * !运行时要求:__webpack_exports__, __webpack_require__。r, __webpack_require__。d, __webpack_require__。* * //***/ ((__ unused_webpack_module __webpack_exports__ __webpack_require__) = >{__webpack_require__.r (__webpack_exports__);/* harmony export */__webpack_require__.d(__webpack_exports__,{/* harmony export */“默认”:()= >__WEBPACK_DEFAULT_EXPORT__/* harmony export */});/* harmony默认输出*/常量__WEBPACK_DEFAULT_EXPORT__=((文本=“你好,Webpack !”)= >{常量元素=文档.createElement(“标题”);元素.innerHTML=文本;返回元素;});/ * * * /})
如您所见,现代ES6特性(箭头函数和常量
声明)component.js
模块默认情况下不会转换为符合es5的代码。为了让我们的代码在旧的浏览器中工作,我们必须添加Babel加载器:
npm安装babel loader @babel/core @babel/preset-env——save-dev
然后,在webpack.config.js
添加模块
后输出
属性:
模块:{规则:[{测验:/美元\ . js/,排除:/node_modules/,使用:{加载程序:“babel-loader”,选项:{预设:[“@babel / preset-env”]}}},]},
当我们为webpack加载器定义规则时,通常需要定义三个主要属性:
测验
,它描述了应该转换什么类型的文件。排除
,它定义了不应该从加载器处理的文件(如果我们有的话)。使用
,它告诉应该对匹配的模块使用哪个加载器。在这里,我们还可以设置加载器选项,就像我们刚刚对预设
选择。
重新执行如下命令:
npm执行命令dev -- --devtool inline-source-map
这一次,代码在main.bundle.js
编译:
/ * * * /”。/ src / component.js ": /*!**************************!*** ./src/component.js ***!\**************************// * !命名空间导出*// * !导出默认[已提供][无使用信息][缺少使用信息防止重命名]*// * !其他导出[未提供][无使用信息]*// * !运行时要求:__webpack_exports__, __webpack_require__。r, __webpack_require__。d, __webpack_require__。* * //***/ ((__ unused_webpack_module __webpack_exports__ __webpack_require__) = >{__webpack_require__.r (__webpack_exports__);/* harmony export */__webpack_require__.d(__webpack_exports__,{/* harmony export */“默认”:()= >__WEBPACK_DEFAULT_EXPORT__/* harmony export */});/* harmony默认输出*/常量__WEBPACK_DEFAULT_EXPORT__=(函数(){var文本=参数.长度>0& &参数[0]= = !未定义的?参数[0]:“你好,Webpack !”;var元素=文档.createElement(“标题”);元素.innerHTML=文本;返回元素;});/ * * * /})
完美的。现在我们可以使用现代的JS特性,webpack将转换我们的代码,以便它可以在旧的浏览器上执行。
使用样式
在本节中,我们将看到如何向项目添加一些样式。要做到这一点,我们需要安装两个加载器:
npm安装Css-loader style-loader——save-dev
css-loader
将CSS解析为JavaScript并解析任何依赖项style-loader
输出我们的CSS到<时尚>
标签在HTML文档中。
让我们添加必要的配置webpack.config.js
:
模块:{规则:[...{测验:/美元\ . css/,使用:[“style-loader”,“css-loader”]},]},
这里,装载机的顺序很重要。它们以相反的顺序计算——即从右到左,从下到上。在我们的例子中css-loader
首先计算,然后是style-loader
.
现在,让我们创建一个文件src / style.css
:
h1{颜色:红色的;}
然后我们把它导入app.js
:
进口”。/ style.css ';
当我们运行webpack (运行开发
),然后打开index . html
,我们应该看看你好,Webpack !红色的信息。
资产管理
大多数情况下,您的项目将包含图像、字体等资产。在webpack 4中,要使用资产,我们必须安装一个或多个以下加载器:file-loader
,raw-loader
,url-loader
.在webpack 5中,正如我们前面看到的,这不再需要了,因为新版本带有内置的资产模块.
在这里,我们将探讨一个带有图像的示例。中添加新规则webpack.config.js
:
模块:{规则:[...{测验:/gif \。(?:ico | | png | jpg | jpeg)美元/我,类型:“资产/资源”,},]},
这里是类型资产/资源
用来代替file-loader
.
现在,为了测试加载器,我们将创建一个image-component.js
文件,在src
目录,内容如下:
进口图像从”。/ image.png”;常量img=文档.createElement(“img”);img.src=图像;文档.身体.列表末尾(img);
在这里,我们将图像作为模块导入,并使用它创建一个< img / >
标签。要使上面的代码工作,您需要下载图片然后重命名为image.png
然后把它放在src
目录中。
下一步是导入我们的图像组件app.js
:
进口“。/图片组件”;
瞧。现在,当我们运行webpack (运行开发
),然后打开页面,我们应该会看到上图你好,Webpack !消息。
如果你看一下部署
文件夹现在,你会发现其中生成了三个文件:a1af828b4e65d37668e1.png
,main.bundle.js
,index.js
.下面是webpack在幕后所做的工作:将图像添加到部署
文件夹,并分配了唯一的散列,然后是图像扩展名。然后将图像包含在新生成的图像中main.bundle.js
文件作为模块。最后,一个index . html
的引用生成文件main.bundle.js
文件。
加速开发过程webpack-dev-server
目前,每次进行更改时,我们都需要重新构建代码。幸运的是,webpack提供了一个实时重新加载的web服务器,可以自动构建和刷新页面。要安装它,请执行以下命令:
npm安装webpack-dev-server——save-dev
我们需要更新我们的dev
脚本,在package.json
,以使用该服务器:
“开发”:webpack服务模式开发
现在让我们配置服务器webpack.config.js
属性之后添加以下属性输出
:
devServer:{contentBase:”。/部署的,开放:真正的},
这告诉webpack-dev-server
来提供文件部署
目录,并自动打开入口页面。
现在,如果运行webpack (运行开发
),便可看到网页如何在浏览器上自动打开http://localhost:8080.
注意:运行webpack-dev-server后,您将在部署
文件夹(它将为空),因为服务器在编译后不写入任何输出文件。相反,它将包文件保存在内存中,并将它们作为挂载在服务器根路径上的真实文件提供服务。看到webpack开发指南获取更多信息。但是,当您运行构建
命令,部署
文件夹将按预期填充生成的文件。
如果我们现在更改任何源文件并保存它们,web服务器将在代码编译后自动重新加载页面。例如,尝试将CSS文件中的color属性更改为绿色,您应该会看到页面中的颜色是如何适当更新的。
清理输出
随着我们项目的进展,部署
文件夹可能会变得非常混乱。在每次构建时,webpack都会生成包并将它们放在部署
文件夹,但它不能跟踪项目实际使用的文件。所以这是一个很好的练习部署
文件夹,以便只生成正在使用的文件。为此,我们需要安装和配置clean-webpack-plugin
:
npm安装clean-webpack-plugin——save-dev
在webpack.config.js
:
常量{CleanWebpackPlugin}=需要(“clean-webpack-plugin”);...插件:[...新CleanWebpackPlugin()],
现在,运行webpack (NPM运行构建
),并检查部署
文件夹中。您现在应该只看到从构建生成的文件,而没有旧的和未使用的文件。要测试它,请创建一个项目中未使用的简单文本文件,并运行构建
脚本了。编译后文件将被删除。
结论
Webpack是一个有用而强大的工具。本教程只介绍了核心概念,但是webpack提供了更多的特性、插件和不同的技术来应用它们,随着知识的增长,你可以采用它们。下面是我建议进一步探索webpack功能的资源列表:
- 官方webpack文档.该文档提供了关于webpack的主要概念和配置的结构化信息,以及您可以在项目中使用的插件和加载器,以及基本指南和API参考。
- Webpack 5:从学徒到大师.一个完整的手册,深入每个webpack方面。作者:Juho Vepsäläinen, webpack的核心开发者。
- Webpack:核心概念.webpack的维护者之一Sean Larkin的一个很好的入门视频课程。