浅探 webpack 的 module

发布于 2022-08-21 15:14:15 字数 3271 浏览 228 评论 0

本文主要说的是 webpack 编译中的 make 阶段,或者说 webpack 生成 modules 的整个流程。webpack 的 make 过程还是比较复杂的,主要流程如下:

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 的核心模块 modulepath 等来简化一些处理,而是自己造了一个类 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 具有一些很实用的方法可以调用,尤其是 emitFileemitFile 的作用是给当前 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

蓬勃野心

暂无简介

0 文章
0 评论
22 人气
更多

推荐作者

linfzu01

文章 0 评论 0

可遇━不可求

文章 0 评论 0

枕梦

文章 0 评论 0

qq_3LFa8Q

文章 0 评论 0

JP

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文