浅探 webpack 的 module
本文主要说的是 webpack 编译中的 make 阶段,或者说 webpack 生成 modules 的整个流程。webpack 的 make 过程还是比较复杂的,主要流程如下:
1.核心
我认为 make 阶段的核心是依赖,实际上,make 阶段的一切模块都由依赖构建出来。
首先是 entry。我们在 webpack 的配置文件中可以指定 entry,entry 中指定的文件可以是单个、也可以是多个(字符串),举个 entry 给多个文件的例子(伪代码):
指定配置:: { entry: { main: ['./src/a', './src/b'], } } webpack:: const entryMainModule = { dependencies: { './src/a': Dep('./src/a'), './src/b':Dep('./src/b') }, // webpack的source是在make结束之后才被调用的 source() { return ` __webpack_require__(${this.dependencies['./src/a'].id}); module.exports = __webpack_require__(${this.dependencies['./src/b'].id}); `; } }
可以看出,webpack 会把 entry 转换成一个新增的 MultipleModule,entry数组里的模块被指定为依赖。当然如果是指定的单个文件,则 entry 直接转化为 NormalModule。不过还是会有转化为 Dependency 的过程。总结如下:
entry --> 是否单文件 --是--> entry设定为为SingleModuleDependency --> 生成NormalModule(会执行loader)
|
否--> entry设定为MultipleModuleDependency --> 生成MultipleModule(无loader, parse)
2. 对引用路径的处理
造过构建工具轮子的人都知道,引用路径的处理是一块很麻烦的事情。webpack 没有像 babel 他们,使用 node 的核心模块 module
、path
等来简化一些处理,而是自己造了一个类 Resolver
, 这个类是支持插件的。不管是 loader 还是 contextModule 还是 normalModule 都是他处理,最后处理的结果都是把相对路径转化为绝对路径。(比较常规)
由于 loader 也是 Resolver 解析的,所以loader的路径也就可以很灵活了,不一定非要放到node_modules里面(好像没人提这点)。
另外,resolve是比较蠢的,比如引用./a
, 这货会同时找文件夹和文件,文件还会带上extension
找。
此外,每个 module 都会独立地匹配 loader,并不存在什么缓存。
3. 对 loader 的处理
webpack 的 loader 有 pitch 特性 所以
['style', 'picth-enabled', 'css']
加载 loader 的顺序是从左到右的,虽然执行的顺序是相反的。
loader 可以指定 raw 属性,选择传过来的 source 是否是 buffer。
loader 具有一些很实用的方法可以调用,尤其是 emitFile
。emitFile
的作用是给当前 module 附加一个 assets(正常情况下 assets 其实是很后面的阶段才生成的),有没有一种钦定的赶脚。在我们常用的 file-loader
中就是用了这个特性。
4. loader 之后的 parse
很少有文章会提到 webpack 的 parse,实际上这个才是真正意义上的“编译”嘛。在 loader 执行完之后,webpack 会使用 acorn 将模块解析成 ast,然后去遍历 ast。
Parser 模块支持插件,在遍历大多数语句的时候,都存在钩子。实际上给模块添加依赖就是遍历到 call commonjs:require 这种语句的时候,插件完成的,并且也将依赖模块的名字改为动态的了。
webpack 的 Parser 相比 babel 还是很弱的。模块自身处理完了之后,都会去处理自身的依赖,也就是把依赖转化为模块。
5. module 的大致结构
module: {
request: './src/a',
context: 'xxxx',
loaders: [],
id: 0, // entry的id为0
source() {return xxxx},
dependencies: {
'./b': {
request: './src/a',
context: 'xxxx',
module: module,
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: Webpack 开发者指南
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论