1

啃先生(MrKenniu) | 文

网站进化成 Web app 呈现以下特点

  • 使用更多 JavaScript

  • 更多的用户界面通过现代浏览器提供服务

  • 页面在提供服务的过程中,尽可能少地刷新整个页面

所以现在的网站有非常多代码在客户端运行!庞大的代码库需要被有序地管理起来,而模块系统「Module system」提供一种能力,将代码库切分成一个个模块「Module」

模块系统的派别们

定义模块及模块依赖的方法有好几种标准

  • <script>标签「没有使用模块系统」

  • CommonJS

  • AMD

  • ES6 模块系统

  • 还有其他的...

script 标签
这种方式并没有使用任何模块系统

clipboard.png

各个模块向全局对象「例如,window 对象」导出一个接口。其他模块通过全局对象访问这个接口。

缺点:

  • 容易引起冲突

  • 需要很注意模块加载的顺序

  • 模块使用者需要分解模块的依赖

  • 在大项目里,需要管理的模块非常多,管理难度很高

CommonJS:同步的 require 方法
这种方式使用同步的 require 方法加载一个依赖的模块,并且返回一个接口。给导出对象「exports」添加属性 或者给 module.exports 赋值,都可以定义模块的导出对象。

clipboard.png

这种方式通常被使用服务器端 NodeJS

优点

  • 可以利用服务器度的代码

  • npm 已经有许多使用这种风格的模块

  • 非常方便易用

缺点

  • 阻塞的加载方式不适用于网络环境,网络请求是异步的

  • 加载多个模块时,没有平行加载

AMD: 异步的 require方法
其他应用于浏览器环境模块系统,不支持同步的 require ,但提供了异步 require 方法:

clipboard.png

优点

  • 符合网络环境下的异步请求方式

  • 多个模块可以平行加载

缺点

  • 额外的编码开销。可读性比较差

  • 有点像一种临时方案

实现:RequireJS

ES6 模块系统
ECMAScript 2015「第6版本」,为 JavaScript 提供了一些语言结构,形成另一种模块系统

clipboard.png

优点

  • 便于静态分析

  • 面向未来的 ES 标准

缺点

  • 浏览器支持此特性,还需要一些时间

  • 现在还比较少模块是基于这种方式编写的

客观的解决方案
让开发人员选择模块系统,允许现有的代码库运行「即使它们使用了其他的模块系统」。

传输

模块需要从服务器传输到客户端,才能被客户端执行。有两种比较极端的传输方式,这两种方式都被广泛应用,但都不是最佳的

  • 一个模块一次请求

  • 所有的模块都在一次请求

一个模块一次请求

优点:只有需要的模块才会被传输
缺点:过多的请求开销
缺点:请求延迟较大,导致程序开始比较慢

一次请求所有模块

优点:请求开销比较少,延迟较少
缺点:还未使用到的模块,还被下载到客户端了

分片传输
多数场景下,需要一种更灵活的传输方式,它介于以上两种极端情况之间:
当编译所有模块时,将一系列模块分解成一组小的分片「chunk」

  • 相对一次请求所有模块,分片的方式使网络请求变成多个更小,更快的请求。程序启动时,不需要用到的分片,将会在需要时才被加载。

  • 相对于一次请求一个模块,这加快程序的初始化,但仍然可以让你在实际使用时获取更多的代码「减少网络请求开销」。

怎么分片,在哪里分片是由开发者决定的。大代码库通过这种方式可以组织得很合理。

结语

针对以上两大主题,Webpack 支持多种模块系统风格,支持灵活的 chunk 传输「Code Split」。

Webpack 是一个 JS 模块打包工具,可以用它打包 Web 网站的 JS 代码库,也可以用来打包第三方代码库。不像 RequireJs 只支持 AMD,NodeJS 是 CommonJS, SeaJS 只支持 CMD,如今还有 ES6 Module ... Webpack 像是集大成于一身,开发者在此之上灵活根据自己喜好编码。

下一篇文章,总结 Code Split 的用法。


啃先生
1.4k 声望1.2k 粉丝

前腾讯前端开发工程师,后来有一年时间经历参与创业,目前东南亚电商 Shopee,人在深圳。个人作品: