写点什么

构建系列之 webpack 窥探上

作者:江湖修行
  • 2023-04-27
    北京
  • 本文字数:2638 字

    阅读完需:约 9 分钟

构建系列之webpack窥探上

前言

在网页开发的早期只是单纯的静态 html 文件,后来引入了 js,可以做一些简单的交互动作,比如表单验证或动画实现等,那个时候整个网站的代码还是很少的,js 直接写在<script>标签中也不会有什么问题。

前端的转折变迁

2008 年 9 月 2 号,当 Chrome 第一次出现的时候(V8 与 Chrome 同一天宣布开源),它对网页的加载速度让所有人惊叹,是 V8 引擎把 JavaScript 的运行速度提上来了,让前端从蒸汽机机时代正式步入内燃机时代。


2009 年诞生的 Node.js 和 2010 年诞生的 npm,迅速将 JavaScript 变成全球最受欢迎的生态系统之一。前端正式从石器时代进入到了工业化时代。


随着业务复杂度的与日俱增,js 代码越来越多,单个 js 文件已经不能解决问题,于是我们将代码组织在多个 js 文件中,进行维护。但是这种维护方式,依然不能避免一些灾难性的问题。痛点如下:


  • 变量和方法不容易维护,容易污染全局作用域。

  • 加载资源的方式通过 script 标签从上到下。

  • 依赖的环境主观逻辑偏重,代码较多就会比较复杂。

  • 大型项目资源难以维护,特别是多人合作的情况下,资源的引入会让人崩溃。


面对如上问题,我们需要降低复杂度,用分治的思想将原有的代码拆成子模块,模块化的开发方式可以提供代码复用率,方便进行代码的管理。通常来说,一个文件就是一个模块,有自己的作用域,只向外暴露特定的变量和函数。有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。


但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写法,我有我的写法,岂不是乱了套!考虑到 Javascript 模块现在还没有官方规范,这一点就更重要了。目前流行的 js 模块化规范有 CommonJS、AMD、CMD 以及 ES6 的模块系统。


CommonJS


NodeJS 诞生之后,它使用 CommonJS 的模块化规范。从此,js 模块化开始快速发展。它有四个重要的环境变量为模块化的实现提供支持:module、exports、require、global。


ES6


在语言标准的层面上,实现了模块功能,而且实现得相当简单,旨在成为浏览器和服务器通用的模块解决方案。其模块功能主要由两个命令构成:export 和 import。export 命令用于规定模块的对外接口,import 命令用于输入其他模块提供的功能。

Webpack 登场

模块化思想的提出,将复杂的程序分割成更小的文件。前端工程师们还通过不懈的努力,将开发效率进一步提升。这些年优秀的框架层出不穷 react、vue、angular、es6 这种在 javascript 基础上拓展的新的语法规范和 less、sass、css 处理器等等等。但这些框架大大提高开发效率的同时,又为后期维护造成了困扰。因为利用这些工具的文件往往不能直接被浏览器识别,需要手动处理,很影响开发进度。


是否可以有一种方式,不仅可以让我们编写模块,而且还支持任何模块格式(至少在我们到达 ESM 之前),并且可以同时处理资源和资产?所以 webpack 应运而生~这就是 webpack 存在的原因。它是一个工具,可以打包你的 JavaScript 应用程序(支持 ESM 和 CommonJS),可以扩展为支持许多不同的静态资源,例如:images, fonts 和 stylesheets。


webpack 的官方定义:


At its core, webpack is a static module bundler for modern JavaScript applications.


通俗地讲 webpack 是一个传统的 JavaScript 模块打包器。创建的目的是通过有效地将前端应用分割成块,快速地将其传送到用户的浏览器。作为最古老、最成熟的打包工具之一,至今仍在积极地维护中,webpack 拥有一个庞大的插件生态系统,适应任何类型的复杂应用。


webpack 关心性能和加载时间;它始终在改进或添加新功能,例如:异步地加载 chunk 和预取,以便为你的项目和用户提供最佳体验。

Webpack 的原理

核心概念

  • entry:一个可执行模块或者库的入口,webpack 编译的起点

  • chunk:多个文件组成一个代码块。webpack 会将 module 按特定的规则组织成一个一个的 chunk,这是打包。

  • loader:文件转换器。例如把 es6 转为 es5,scss 转为 css 等

  • plugin:扩展 webpack 功能的插件。在 webpack 构建的生命周期节点上加入扩展 hook,添加功能,在特定时间点介入编译过程。

  • Compiler:编译管理器,webpack 启动后会创建 compiler 对象,该对象一直存活直到结束退出。

  • Dependence:依赖对象,webpack 基于该类型记录模块间依赖关系。

  • Module:webpack 内部所有资源都会以“module”对象形式存在,所有关于资源的操作、转译、合并都是以“module”为基本单位进行的。

构建流程

初始化阶段


  • 初始化参数:解析 webpack 配置参数,合并 shell 传入和 webpack.config.js 文件配置的参数,形成最后的配置结果。

  • 开始编译:上一步得到的参数初始化 compiler 对象,注册所有配置的插件,插件监听 webpack 构建生命周期的事件节点,做出相应的反应,执行对象的 run 方法开始执行编译。

  • 确定入口:从配置的 entry 入口,开始解析文件构建 AST 语法树,找出依赖,递归下去。


构建阶段


  • 编译模块:递归中根据文件类型和 loader 配置,调用所有配置的 loader 对文件进行转换,调用 JS 解释器将内容转换为 AST 对象再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理。

  • 完成模块编译:递归完事后,得到每个文件结果,包含每个模块以及他们之间的依赖关系


生成阶段


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

  • 写入文件系统(emitAssets):在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

Webpack 特点

  • 简单易用:支持零配置,接入简单方便

  • 庞大生态:webpack 社区和用户基础庞大****

  • 代码拆分:有两种组织模块依赖的方式,同步和异步

  • Loader:将各种类型的资源转换成 JavaScript 模块

  • 智能解析:有一个智能解析器,几乎可以处理任何第三方库

  • 插件系统:有一个功能丰富的插件系统

  • 快速运行:使用异步 I/O 和多级缓存提高运行效率


总结


webpack 是一个传统且强大的 JavaScript 应用打包工具,致力于解决前端工程化,特别是浏览器端工程化中遇到的问题,让开发者集中注意力编写业务代码,而把工程化过程中的问题全部交给 webpack 来处理。其强大的社区支持和不断的进化支撑着自己在前端的发展过程中能始终有一席之地。webpack 关心性能和加载时间;它始终在改进或添加新功能。webpack 引入 tree shaking 旨在优化构建和线上运行时的性能,异步地加载 chunk 和预取,以便为你的项目和用户提供最佳体验。下篇文章我们会在实战和开发中大家更关注的问题上带来更多的知识详解,敬请关注。

感谢阅读,欢迎关注,也可关注wx公众号:江湖修行,获取更多内容分享,感谢今天努力前行的你。

发布于: 刚刚阅读数: 3
用户头像

江湖修行

关注

还未添加个人签名 2021-12-05 加入

还未添加个人简介

评论

发布
暂无评论
构建系列之webpack窥探上_前端_江湖修行_InfoQ写作社区