1

原文地址

现今Web网页正逐步向Web App进化,主要体现在:

  • 越来越多依赖JavaScript的使用。

  • 现代浏览器提供了多样化的接口。

  • 更多的局部加载代替全局刷新,甚至单个页面代码量的提升。

因此,客户端将承载大量代码!
大量的底层代码需要被组织。而模块系统则提供了一个可以将底层代码分割成不同模块的方式。

常见的模块系统风格

对于如何定义依赖与引用,存在许多不同的标准:

  • <script>标签(即不使用模块系统)

  • CommonJS

  • AMD及其衍生

  • ES6模块

  • 其他

<script>标签

下面用一个例子来展示如果你不使用模块系统,你提交的底层代码模块化结构是这样的:

<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="libraryA.js"></script>
<script src="module3.js"></script>

模块向全局对象(即window对象)暴露一个接口,模块通过全局对象访问依赖的接口。

缺点:

  • 全局空间的污染

  • 需要合理的加载顺序

  • 开发者要解决模块/库的依赖

  • 大型项目中列表冗长且难以管理

CommonJs:同步调用

CommonJs采用require方法同步调用依赖并返回暴露的接口。一个模块可以通过添加暴露对象的属性或设定module.exports的值被暴露出来。

require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;

该方法以通过node.js被使用于服务端。

优势

  • 服务端模块可以被复用

  • 有大量现成的模块(如npm)

  • 简单且易于使用

不足

  • 阻塞式并不能很好地适用于互联网,网络环境需要异步调用

  • 无法平行加载多个模块

具体应用

AMD:异步调用

异步模块的定义
在客户端其他同步模块系统有着同样的问题,下面介绍一种异步的版本,包括其如何定义变量与暴露值:

require(["module", "../file"], function(module, file) { /* ... */ });
define("mymodule", ["dep1", "dep2"], function(d1, d2) {
  return someExportedValue;
});

优势

  • 满足客户端异步调用风格

  • 可平行加载多个模块

不足

  • 头部声明不利于阅读和编写

  • 看上去像是一种妥协

具体应用

ES6模块

EcmaScript6向JavaScript添加了许多语言结构,因此形成了另一种模块系统。

import "jquery";
export function doStuff() {}
module "localModule" {}

优势

  • 易于静态解析

  • 未来将成为ES标准

不足

  • 还有待浏览器支持

  • 由于比较新,这种方式的实现较少

客观的意见

应然开发者自己选择模块风格,使已存在的代码与库可以正常工作,以简单的方式添加习惯的模块风格。

加载

由于模块需要在客户端执行,因此需要在客户端加载服务端模块。
以下是两种比较极端的模块加载:

  • 一个模块写一个加载

  • 所有模块写在一个加载中
    两者都应用广泛,但都有所不足:

  • 一个模块写一个加载

    • 优势:只有一个模块需要加载

    • 不足:越多模块意味着越多的顶部声明

    • 不足:由于需要较长的加载时间,应用启动较慢

  • 所有模块写一个加载

    • 优势:更少的顶部声明,更快的加载

    • 不足:不需要的模块也同时被加载

分块加载

一种更灵活的加载似乎更好。一种介于这两种极端中间的方式对大多数情况来的更好。
当编译所有模块时:把模块的集合拆分成许多更小的chunk(块)。
这能实现更小更快的加载。由模块组成的chunks在初始化的时候并不会被加载。当需要使用模块时,才加载块,这加快了应用加载的速度。
如何分割模块集合取决于开发者。

这让组织大量代码成为可能!
注意:这一想法来源于Google’s GWT
了解更多关于代码拆分

为何只提到JavaScript

有许多其他资源如样式、图片、字体、HTML 模板也需要处理,为何只提及JavaScript?也还有其他需要编译的资源:coffee script,elm,less,jade,i18n等。
如果把他们都看成chunk(块)事情就变得很简单:

require("./style.css");
require("./style.less");
require("./template.jade");
require("./image.png");

了解更多关于使用加载

静态解析

当编译所有这些模块时,静态解析会试图找到它的依赖。
通常,只能解析一些简单的格式,但像("./template/" + templateName + ".jade") 又是一种常见的书写格式。
并且多数库都采用不同的写法,有些写法时很奇特的…

策略

一款好的语法分析程序可以是大多数现存代码正常运行。如果开发者风格奇特,它也会试图去找到最合适的解决方法。

译者注:
这个系列会试图将webpack的官方文档都翻译一遍,未翻译的链接,翻译后会改成相应中文翻译页面。


这是上帝的杰作
2.2k 声望164 粉丝

//loading...