什么是前端模组化?

2022年2月9日

💎 加入 E+ 成長計畫 如果你喜歡我們的內容,歡迎加入 E+,獲得更多深入的軟體前後端內容

面试中,关于打包工具的相关知识是非常常见的考题,无可避免的可能会被问到,为什么需要使用到打包工具、或前端工程化的实现,而要回答这些问题前,需要先了解的就是前端模组化。所以在本篇笔记中,会让大家了解前端模组化的演进和功用。

什么是模组化?

开发人员将代码或系统分割为不同模组的过程,就称为模组化。每个模组就代表一个完整的小程序或小功能,所有模组组装起来成为一个整体,进而完成整个系统的功能要求。

Node.js 几乎一开始就支持模组化,相比之下 Web 开发,模组化应用进展慢了许多,但到今日也出现了许多支持前端模组化的工具。

为什么需要前端模组化?

我们先来想像如果今天不用打包工具、模组化语法,要如何在浏览器上执行 JavaScript?

  • 方法一:每个功能就是一个 JavaScript script 档案并载入。但此方法会让代码难以扩展,载入太多 script 也会导致网路瓶颈,并且也有载入先后顺序的相依性问题。
  • 方法二:使用一个统一的大 .js 档案,将所有功能都包含在其中,但这会导致维护、易读性方面的问题。

模组化工具出现之前,会透过一些方案来解决上述的做法问题,最常见的就是透过立即执行函式(IIFE),它其实是利用函式的闭包特性来实践数据私有化和共享方法,如下范例

const muduleB = (function () {
  return {
    number: 200,
  };
})();

const moduleA = (function (otherModule) {
  let number = 100;

  function getNumber() {
    console.log(number + otherModule.number);
  }

  return { getNumber };
})(muduleB);

我们可以透过moduleA 拿到getNumber 方法,并且实践number 变数的私有化,防止外部调用,此外moduleA 也可以引入其他module ,通过这种方式,我们就可以在 moduleA 中使用其他模组,进而解决很多问题。

moduleA.getNumber(); // 300
moduleA.number; // undefined

IIFE 的做法也成为现在模组化的概念来源。但随着前端对模组需求越来越大,逐渐出现了一些模组化解决方案、并演变成了通用的规范,从 CommonJS 到现在的 ES Module(ESM)。下个段落会介绍各个通用的模组化规范

延伸阅读:JavaScript 立即调用函式IIFE (Immediately Invoked Function Expression) 是什么?优缺点是什么?

JS 模组化规范

CommonJS

Node.js 发布时,它带来了新的挑战。因为 JavaScript 不是在浏览器中运行,因此没有可以添加到其中的 html 文件和脚本标签,那么 Node 应用程序应该如何加载不同的代码呢? - 透过 CommonJSCommonJS 规范在 2009 年被社群开发出来,引入了requireexport宣告模组的语法,一个文件就是一个模组,是以同步的方式载入模组,因此适合服务器端的开发。

AMD(Async Module Definition)

AMD 在中文是非同步模组定义的意思。它起源于 Dojo 工具箱 (一套 JavaScript Web 应用程式库)。同时,AMD 一开始就是为浏览器而设计的,目前为止,最受欢迎的AMD 实作是{% outerLink href="https://requirejs.org/" text="RequireJS" /% } (一个 JavaScript 模组加载器)。 AMD 可以自动决定相依关系,模组是以非同步方式载入,避免阻塞的问题,并且可以把多个模组定义在同一个档案中。

CMD(Common Module Definition)

CMD 的出现较晚一些, Sea.js 在 2012 年开始推广,它汲取了 CommonJSAMD 规范的优点,也是专门用于浏览器的异步模块加载。在规范中,一个文件就是一个模组。

UMD(Universal Module Definition)

AMDCommonJS 是最受欢迎的两套模组标准,也各有优缺点,通常开发者会根据自己的需求选择不同的标准。但是,我们也有可能会去使用到不同标准所开发出来的代码,这可能就会造成问题。一种解决方案就是 UMD,它可以让 AMDCommonJS 使用同一份档案。

ES Module(ESM)

ES6 发布之后,终于实现了模块的功能,并结合了 CommonJSAMD 的两者优点

  • 类似 CommonJS,引入简单的语法如 exportimport,并且也是一个档案为一个模组
  • 类似于 AMD 也有支援非同步载入

模组打包工具(Module Bundler)的作用

上个段落介绍了不同模组规范,以及RequireJS 等模组加载工具被创建,让我们能在浏览器中使用模组。然而,虽然有这些模组化工具,因为各家浏览器支援度不同等问题,导致有时候如果你想用别人写好的模组 (例如 npm 上的套件),很可能没办法顺利引用。

因为有浏览器模组机制相容性、兼容性的问题,前端业界后来发展出 webpack 等工具,协助开发者打包模组,所以假如你的代码中,有使用某个 npm 的套件,webpack 会协助你打包,让他变得像是你自己写的模组,这有效解决浏览器模组功能支援度的问题。

除此之外, webpack 这类的不只帮助我们加载管理代码的模组。它进一步扩展到可以支援不同的资源载入,让各种不同资源都可以变成一个模组 (如:图像、字体和样式表)。此外,它可以有其他优化,提供更好的使用者和开发者体验。


相关文章

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們