模块与依赖的概念
在如今的模块化开发时代,我们的应用程序都是由一个个 模块 组装而成,每个模块都拥有小于完整程序的体积,使得验证、调试及测试变得轻而易举,同时提供了可靠的抽象和封装界限,使得应用程序中每个模块都具备了条理清晰的设计和明确的目的。简单点说,模块就是应用程序中的 最小不可分割 的单元,就像线程对于cpu一样,而我们每天所做的工作就是不断写各种模块来完成 最小的 功能单元
这些模块也不是孤立的,而是会互相依赖,最终形成如同 蜘蛛网 一般的复杂依赖网,这些复杂的依赖关系肯定不是我们人为来维护,而是通过类似webpack这种模块打包工具来管理。在webpack中,模块依赖的实现方式分为如下几种
- ES2015 import 语句
- CommonJS require() 语句
- AMD define 和 require 语句
- css/sass/less 文件中的 @import 语句。
- stylesheet url(…) 或者 HTML文件中的图片链接
这么多的依赖方式,那么在webpack中是如何进行模块解析的呢,请往下看
webpack模块解析的流程
在webpack中,使用一个叫做 enhanced-resolve 的库来进行模块解析,通过这个库,webpack可以处理三种形式的路径:
- 绝对路径
import '/root/to/file'
,这种方式不需要解析,直接拿来就用,不多说 - 相对路径
import './to/file'
,这种方式使用 import 或 require 的资源文件所处的目录,被认为是上下文目录,在 import/require 中给定的相对路径,会 拼接 此上下文路径,来生成模块的绝对路径 - 模块路径
import 'lodash'
,这种方式流程稍微复杂一点,讲解如下- 在 resolve.modules 中指定的所有目录检索模块
- resolver将会检查路径是指向文件还是文件夹
- 文件: 如果具有扩展名,则直接将文件打包,否则将使用 resolve.extensions 选项作为文件扩展名来解析,此选项会告诉解析器在解析中能够接受哪些扩展名(例如 .js,.jsx)
- 文件夹: 如果包含 package.json 文件,那么会根据 resolve.mainFields 配置中的字段顺序查找,其实也就是找入口文件,如果没有 package.json 文件或 resolve.mainFields 没有返回有效路径,那么就会根据 resolve.mainFiles 配置选项中指定的文件名顺序查找,看是否能在 import/require 的目录下匹配到一个存在的文件名,其实也是去找入口文件。当匹配到文件名后,就会用 resolve.extensions 选项进行解析
上述就是webpack中模块解析的具体规则与流程,看似很繁杂,其实本质都是去找一个对应的文件,找的过程中如果提供了完整的信息就直接用,不完整就用一些辅助信息来查找,都是殊途同归的
结语
我认为webpack的强大之处在于让我们能感受不到它的强大,因为很多事情背后都帮我们做完了,久而久之让我们觉得很多事情是理所当然的,当然这也是webpack的成功之处,牢牢地把控住了我们开发者,从而不会转战其他工具,因此webpack的学习之路还很漫长,需要一点耐心,需要一点毅力,需要一点热情~