备战-webpack篇

259 阅读5分钟

前言

小编之前有总结过两篇关于webpack相关配置的文章,但究其细节没有提及到webpack的一些实现原理。所以这边在补上一篇备战篇,想看webpack搭建的可以点击这里

webpack工作流程

核心

webpack核心组成就是下面这四个点

  • 入口文件配置 (enpty)

  • 出口文件配置 (output)

  • 模块转换器 (loader)

  • 插件 (plugins)

工作流程

  • 初始化参数

    从配置文件和 Shell 语句中读取与合并参数,得出最终的参数。

  • 开始编译

    根据我们的webpack配置注册好对应的插件调用 compile.run 进入编译阶段,在编译的第一阶段是 compilation,他会注册好不同类型的module对应的 factory,不然后面碰到了就不知道如何处理了。

  • 编译模块

    进入 make 阶段,会从 entry 开始进行两步操作:第一步是调用 loaders 对模块的原始代码进行编译,转换成标准的JS代码, 第二步是调用 acorn 对JS代码进行语法分析,然后收集其中的依赖关系。每个模块都会记录自己的依赖关系,从而形成一颗关系树。

  • 输出资源

    根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会。

  • 输出完成

    最后执行 Compiler 的 emitAssets 方法把生成的文件输出到 output 的目录中。

上面所描述的是一个比较详细的一个过程那么简单来讲就是

参数解析 --> 找到入口文件注册插件事件 --> 调用Loader编译文件 --> 遍历 AST,收集依赖
--> 生成 Chunk --> 输出文件

loader

Loader是一个node模块,可以处理任意类型的文件,转换成 webpack 可以处理的模块。然后在将模块交给webpack内部去转换生成输出文件,关于怎么配置webpack.config文件使用loader这边就不做描述啦,

webpack 项目中引入模块时,会去匹配rule规则例如test: /\.(le|c)ss$/,然后就会启用对应的loader,然后会导出一个函数,函数参数接受内容就是源文件内容的字符串。他的工作流程如下:

  • loader(webpack)的默认配置
  • 使用loaderResolver解析loader模块路径
  • 根据rule.modules创建RulesSet规则集
  • 使用loader-runner运行loader

plugin

插件也是webpack很重要的一个部分,我们可以通过插件,扩展webpack,加入自定义的构建行为,使 webpack 可以执行更广泛的任务,拥有更强的构建能力。

webpack 在编译过代码程中,会触发一系列 Tapable 钩子事件,插件所做的,就是找到相应的钩子,往上面挂上自己的任务,也就是注册事件,这样,当 webpack 构建的时候,插件注册的事件就会随着钩子的触发而执行了。 一个基本的 plugin 代码结构大致长这个样子:

class MyPlugin {
  apply(compiler) {
    compiler.hooks.done.tap('My Plugin', (stats) => {
      console.log('Bravo!');
    });
  }
}
module.exports = MyPlugin;

如何实现热更新

关于热更新配置相信大家都知道只需要修改一个对象的参数,小编这边分享一下热更新的实现原理

devServer: {
    hot: true
},

究其根本webpack在每次编译运行的时候内部生成了一个hash值,hash值代表每一次编译的标识,我们如果有代码修改那么随之就会根据这个生成的hash值去命名我们新生成的输出的js文件以及json文件index.[hash].hot-update.js。每次修改代码,紧接着触发重新编译,然后浏览器就会发出 2 次请求。请求的便是本次新生成的 2 个文件。

当我们没有修改代码直接保存时webpack就不会生成index.[hash].hot-update.js这个文件只会生成一个新的新的json文件(其实按照我们的理解没有修改代码的话应该不需要生成新的hash做标记以前确实是这样,但后来webpack热更新就算代码没变还是会有一个新的hash值,只是不生成.js文件),浏览器请求不到新的js文件那么就知道不需要更新

常见优化方式

缓存

我们自身在本地用到webpack的时候每一次build或者run肯定是要将代码全部重新编译一遍的,我们可以通过缓存的方式让webpack的重复编译缓存到本地其实大部分 Loader 都提供了 cache 配置项可以通过设置cacheDirectory(这个参数不知道的同学可以查一下)来开启缓存。

我们的代码压缩也有很多的缓存内容可以去down也是开启

多核

多核是指在一枚处理抄器(processor)中集成两个或多个完整的计算引擎,就是让我们的webpack能同时做很多事情 happypack 就已经成为了众多 webpack 工程项目接入多核编译

抽离

对于一些不常变更的静态依赖,我们不希望这些依赖被集成进每一次构建逻辑中,因为它们真的太少时候会被变更了,所以每次的构建的输入输出都应该是相同的。因此,我们会设法将这些静态依赖从每一次的构建逻辑中抽离出去,以提升我们每次构建的构建效率。

本文使用 mdnice 排版