likes
comments
collection
share

一篇搞懂webpack原理

作者站长头像
站长
· 阅读数 21

概述

  • 本文主要介绍webpack的诞生的原因,webpack解决了什么问题。
  • webpack中的loader、plugin是什么?如何工作的?能否自己构建loader或plugin
  • webpack怎么打包文件的?AST抽象语法树是什么?
  • webpack如何管理打包后模块之间的交互?webpack的runtime和manifest是什么?
  • 实际开发中我们修改某个文件后页面也随之发生变化,这个热更新过程是如何做到的?
  • webpack有哪些不足?

webpack诞生的原因

  • 早期如何开发复杂功能

    1. 回忆我们最开始学习JS时,浏览器运行JS文件需要通过script标签加载,复杂功能就需要分离到不同的JS文件中,那么就需要加载很多个JS文件,会导致网络瓶颈问题PS:chrome一个任务周期内最多能并发6个网络请求
    2. 如果将所有功能写在一个JS文件中,那么维护成本和开发成本必然会越来越高

webpack诞生后,解决了什么?

  1. webpack的诞生是在Node.js发布之后,提出了CommonJS用以解决功能模块化的问题,但浏览器并不直接支持CommonJS语法,因此有了require、Browserify来转译。
  2. webpack会提供node环境,支持CommonJS和ESM规范,并支持任何模块格式。使开发人员只注重业务开发,不关心模块在浏览器的兼容问题。PS:只要提供不同模块对应的loader,webpack就能转换成浏览器能直接运行的JS文件
  3. ESM是JS官方提出了一种解决模块化问题的方案,在今天大部分高版本的浏览器都能支持,Vite构建工具的核心理念也是ESM。其核心主旨是可以不用加载整个项目的JS文件,当页面内容需要哪个模块的JS文件才会发起JS文件加载请求,并且会缓存。这种方式能极大提高项目加载速度。

webpack中的loader、plugin是什么?

  • 上面提到webpack能打包不同文件格式的代码,通过webpack处理后能直接在浏览器运行,但不能增强功能,这就是loader的作用,如解析sass文件的sass-loader。
  • loader可以理解成学校,不管你哪个地方来的学生,出去后给你发一套相同的校服。这套校服就是浏览器运行的JS。
  • plugin就是我们常说的插件,用于增强功能,弥补loader的不足,如axios。好比游戏中的装备,游戏人物配备不同的装备,伤害会不同,技能也更酷炫。
  • loader会在生成AST抽象语法树的过程中加载,用于解析不同格式的内容;plugin的加载时间不定,因为webpack构建过程中,在特定时机广播,并制定某些plugin。特定时间是webpack自动识别的,所以plugin的加载时间不一定。

webpack怎么打包文件的?AST抽象语法树是什么?

  • 在webpack.config.js这个配置文件中,entry就是webpack打包的入口,但有些脚手架的高版本中会隐藏这个文件,若要配置先创建这个文件。
  • webpack的入口文件可以配置多个,具体见官网:webpack打包入口起点

    module.exports = {
      entry: './path/to/my/entry/file.js'
    };
  • webpack打包过程是什么?AST抽象语法树是什么?loader与其有什么关系?

    1. 得到特定的关键字: webpack从entry读取入口文件后会读取文件内容(PS:这里进行的是只读过程),会在读取过程中进行词法分析,如某些关键字let、var、impotant......
    2. 词法分析:得到特定的词法后,如何确定对应所表达的意义,这里就会使用loader,给得到的词法分析赋予意义。如该赋值的赋值、该引如文件的就根据文件路径读取文件。
    3. 生成AST抽象语法树:。词法分析结束后,生成AST抽象语法树。也就是说,从入口文件开始读取,经loader加工,最后会得到一个反应文件之间依赖的树状结构。
    4. 生成chuck: AST抽象语法树完成后,webpack会根据依赖关系生成多个chunk,将每个chunk生成文件,生成的文件就是webpack打包后能直接在浏览器运行的文件。根据output设置的出口,把文件输出。
  • PS:【你应该了解的】抽象语法树AST

webpack如何管理打包后模块之间的交互?

  • 上面提到webpack打包过程中会生成chunk,那么这些chunk的依赖关系,交互是如何实现呢?

    1. runtime:其作用就是管理和确定chunk或打包后文件之间的依赖关系;相当于地图功能,知道chunk和chunk间的关系。
    2. manifest:经过webpack打包后的文件发送到浏览器时,runtime 会通过 manifest 来解析和加载模块。通过使用 manifest 中的数据,runtime 将能够检索这些标识符,找出每个标识符背后对应的模块。
  • 好比runtime的功能是地图检索,manifest的功能就是一个个地名,用于检索对应的chunk或文件。
  • PS:官方给出的相关解释

webpack的热更新原理是什么?

  • 如果不知道什么是热更新,请到官网阅读相关解释。

    #### 如何检查代码发生了变化?

  • 应用程序要求 HMR runtime 检查更新。
  • HMR runtime 异步地下载更新,然后通知应用程序。
  • 应用程序要求 HMR runtime 应用更新。
  • HMR runtime 同步地应用更新。
  • 打个比方:

    1. 应用程序要webpack检查有没有哪个地名的内容发生了改变
    2. webpack如果发现有,则记录变化并同时通知应用程序。“喂~,应用程序!这里发生了点状况,和之前不一样了,这是异步过程。如果没有,就没有后续动作。
    1. 应用程序收到消息后说: “我知道了,你把出状况那里更新下,然后给我”
    2. webpack接收后,开始同步更新,并将结果新的结果发送给应用程序。
  • PS: webpack模块热替换

webpack有哪些不足?

  • 读到这而相信你对webapck打包原理有了大概的认识,但是在实际开发过程中为什么我们启动一个用webapck构建的大型项目启动这么慢呢?更新某快代码热更新速度也很慢?
  • 这是因为webpack是先将项目文件打包后,再发送到浏览器,打包过程耗时。当修改代码后,并不是只更新这一个地方,而是会更新该文件,如果有引用到该文件的地方,也会重新打包更新。这就是运行慢,更新慢的原因。比如我修改A,但是B、C、D、F都引用了A,那么他们也都会重新打包和更新。
  • PS:Vite构建工具的核心思想是ESM,构建速度和更新简直是快得一P。webpack开发兴许还能逛逛朋友圈,Vite的话就是个兢兢业业的职业人!后续会介绍Vite,敬请期待。