重构Webpack系列之一 ---- 概念篇

重构Webpack系列之一 ---- 概念篇

webpack

一、概念

本质上,Webpack是一个用于现代JavaScript应用程序的静态模块打包工具。当Webpack处理应用程序时,它会从内部一个或多个入口点构建一个依赖图,然后将项目中所需的每一个模块组合成一个或多个bundle,这些bundle均为静态资源,用于展示你的内容。

二、概念分支——模块

什么是模块?

模块就是在前端领域的模块化编程中,开发者将程序分解为功能离散的chunk(翻译为,块),并称之为模块。

每个模块都拥有小于完整程序的体积,使得验证、调试以及测试变得轻而易举。精心编写的模块提供了可靠的抽象和封装界限,使得应用程序中每一个模块都具备了条理清晰的设计和明确的目的。

前端领域中Node.js从一开始就支持模块化编程。

那么何为Webpack的模块?

  • ES2015 import语句
  • CommonJS require()语句
  • AMD define、require语句
  • css/sass/less中的@import语句
  • stylesheet url(…)
  • HTML <img src=…>

Webpack支持的模块类型

  • ECMAScript模块
  • CommonJS模块
  • AMD模块
  • Assets静态资源
  • WebAssembly模块

通过loader可以使Webpack支持多种语言和预处理器语法编写的模块。loader向Webpack描述了如何处理非原生模块,并将相关依赖引入到你的bundles中。一些非原生或预处理器编写的模块例如:

  • CoffeeScript
  • TypeScript
  • ESNext(Babel)
  • Sass
  • Less
  • Stylus
  • Elm

以上仅是Webpack一小部分loader可处理的展示。但Webpack还提供了可定制,强大且丰富的API,允许在任何技术栈中使用,并同时支持在开发、测试和生产环境的工作流中做到无侵入性。

三、概念分支——依赖图

什么是依赖关系?

每当一个文件依赖于另一个文件时,Webpack都会将这两个文件视为直接存在的依赖关系。这使得Webpack可以直接获取非代码资源,例如images或web字体。并会将他们作为依赖提供给应用程序。

当Webpack处理应用程序时,它会根据命令行参数中或配置文件中定义的模块列表开始处理。从入口开始,Webpack会递归的构建一个依赖关系图,这个依赖图包含着应用程内需中所需的每个模块,然后将所有模块打包为少量(体积远少于应用程序本身)的bundle——通常只有一个——且可由浏览器加载。

这里官方解释的有点抽象,让我们在网上冲一下浪把。以下敲黑板~~

Webpack处理应用程序的时候,代码转译全靠loader进行字符串处理。比如一个index.js有可能要经历loaderA -> 到loaderB -> 到loaderC,这些loader完全不知道彼此的存在,虽说有依赖关系,但彼此之间也仅仅是通过依赖图之中的依赖关系接过来一个字符串自己处理,然后再根据递归形成的依赖关系移交给下一个loader。

如果最后再uglify(翻译为丑陋,这里指丑化,就是压缩代码的意思)一下,还需要把字符串parse为AST(抽象语法树)再进行进一步的压缩(compress)。单单是这一步就非常耗时间的,这也就是为什么我们用Webpack打包的时候经常要等许久的原因。

可以用简单的公式来描述这个打包的过程:

webpack的打包过程 = parse string\*n + transform*n + parse to AST + compress

Webpack不比其他可以快速打包的工具,每一款模块打包工具都有它的优缺点,例如另外一款打包工具parcel

parcel的主要卖点就是快,原因是多核(通过worker平行构建)和文件系统缓存(二次构建会快,和webpack的dll有异曲同工之处)。

webpack也有多核处理loader和压缩的插件。parcel中很多特性在 webpackl中都可以利用一些相关的loader搞定,但单从代码转译这一点来讲,parcel确实比webpack先进。

parcel和Webpack的最主要差别有两点:一是入口文件;二是打包过程。

Webpack的入口文件必须是JavaScript文件,只有JS是一等公民(webpack@4以上会增加CSS为一等公民),所以必须是JS为入口去组织其他文件。

而parcel的入口文件类型是assets。parcel是以assets方式组织的。即你的入口文件可以是任意类型的文件(但最好还是HTML或JavaScript),如果在HTML中使用相对路径引入主要的JavaScript文件,parcel会将它进行处理,替换为相对于输出文件的URL地址。这就让web前端编程有点类似于回归本源,一切都从HTML开始,应该会有不少人喜欢这种打包方式。

二是打包过程

parcel编译代码打包的过程是先将入口文件转换为AST,然后再进行transform处理。即便有多步转译流程,最后再加上uglify,相比于webpack的parse两次,parcel全部也只需要parse一次。这就大大的缩短了打包的时间。可以用简单的公式理解为:

parcel打包过程 = parse to AST + transform*n + compress

因此,parcel是开辟了一个比较超前的思路:多步转译+压缩时,每一步都可以使用解析过后的AST,只需要完成各自的transform即可。

其次parcel也是0配置的,即parcel内置了一个当你改变文件时能够自动重新构建应用的开发服务器,而且为了实现快速开发,该服务器支持热模块替换,只需要在入口文件指出:parcel index.html即可。

但parcel的0配置也不完全是0。因为HTML、JS和CSS分别是通过posthtml、babel和postcss处理的,所以一般开发的时候还需要配置posthtmlrc、babelrc和postcssrc。这点相比较webpack有内置的loader则是相反的,对于开发者而言如果没有熟悉这几类配置文件,也会增加学习的成本,这是一个弊端。

最后,我们从webpack的依赖关系图延申出来了其一些优缺点的探讨。webpack有的一些功能parcel还不具备。例如sourcemap、publicPath、公共文件提取、Tree Shake和Scope Hoist等。

综上所述,parcel是一门比较年轻的技术,对于地位稳定的webpack来讲,parcel还有很多地方需要学习改善。就目前而言,webpack至少在未来两年内都会是开发者的首选打包工具。而parcel则是有一个好的开头,如果持续维护的话应该不缺用户的。

四、概念分支——模块解析

前面分析了模块以及依赖关系图,但那时基础的,你必须要懂的。

所谓模块解析(Module Resolution),就是打包过程中,webpack根据配置文件的以来顺序进行递归操作形成依赖关系图的期间,通过resolver库来处理引入的文件,其中使用的是enhanced-resolve来解析文件路径。

使用enhanced-resolve,webpack可以解析三种文件路径:

1、绝对路径

例如:import ‘/home/me/file’;

由于已经获得文件的绝对路径,因此不需要再做进一步的解析。

2、相对路径

例如:import ‘…/src/file’;

在这种情况下,使用import或require的资源文件所处的目录,会被认为是上下文目录。在import/require中给定的相对路路径,会拼接此上下文的路径,来生成模块的绝对路径。

比如在src目录下,有两个文件夹,一个是home存放着home.js。另外一个是detail存放这detail.js。

如果在home.js中用相对路径引入detail.js(例如:import ‘…/detail/detail.js’),那么webpack就会用enhanced-resolve在home文件夹目录下形成上下文目录,去寻找detail.js。完整的文件路径就是:import ‘/home/…/detail/detail.js’。

3、模块路径

通过resolve.alias配置别名,可以通过这种方式来替换初始模块路径。

以上是解析依赖文件webpack所使用的方法,接下来是解析loader的说明。

4、解析loader

loader的解析规则也遵循特定的规范,但是resolveLoader配置项可以为loader设置独立的解析规则。

webpack还有模块解析时候的一些智能操作:缓存。

5、缓存

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

五、概念分支——Module Federation(模块联合)

这块内容比较多,这里不进行展开官方文档

以上就是对Webpack的概念的一个理解,如果有帮助到你或者是觉得不错的话,就点点赞把!谢谢各位看官~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值