简介
本文主要是翻译webpack官网文档,参考网络资料,添加部分自己的理解。
起初,JavaScript(以下简称JS)语言仅仅是Web前端技术,采取<script></script>
标签方式定义组件之间的引用、导出变量与方法。
随着传统的web sites演变成web apps,以下的现象越发明显:
- 无论是Web前端或者Web后端,越来越多的Java Script在正在被使用
- 富客户端化,Web前端的功能越来越强大
越来越少的Web前端页面重载(更加复杂的Java Script代码)
庞大的代码库,需要更加高效的组织。Module(组件)方式系统,成为大多数开发人员的选择。
组件系统
存在很多定义组件之间的依赖、导出组件接口的方法:
<script></script>
标签方法- CommonJs
- AMD
- ES6组件
- 其他
script 标签 ###
在非组件系统中,使用script标签,定义组件之间的依赖,会在Java Script代码或者html文件中多次出现:
<script src='module1.js'></script>
<script src='module2.js'></script>
<script src='lib1.js'></script>
各个组件提供接口给全局对象(window
对象)使用。之后,在全局对象实例中,我们能够自由地使用这些接口。
这种管理组件依赖的方法,存在以下缺点:
- 在全局对象里Java Script组件容易产生冲突。
- 我们必须关心组件的加载顺序。
- 我们必须了解各个Java Script组件的依赖关系。
- 在大项目中,Java Script组件列表,会变得非常冗长,并难以维护。
CommonJs 同步require
CommonJs使用同步的require方法加载依赖组件,同时返回创建依赖组件的接口。Java Script组件可以通过:
配置module.exports的参数 (nodejs开发者非常熟悉的方式)
添加exports对象的属性
方式设置组件的接口。
CommonJs组件,主要概念如下:
定义 | 作用 | 说明 |
---|---|---|
module | 组件标识 | module关键字,代表组件本身 |
module.exports | 组件的导出接口 | 组件的导出接口,方法或者变量,类似java语言的public修饰符号 |
exports | 组件的导出对象 | |
require(‘dependencies’) | 加载组件 | 引入外部组件,类似java语言的import功能 |
代码实例:
require("module");
require("../file.js");
exports.doStuff = function(){};
module.exports = someValue;
此种组件化系统存在以下特点
优点:
1、适用于服务端组件,组件单次加载到Cache里,可以被重复使用。
2、存在许多成熟的Java Script组件(通过npm管理)。
3、 简单易用。
缺点:
1、组件,通过阻塞方式的加载,不适合网络应用。网络应用需要异步操作。
2、缺少多个依赖组件的并行加载。
实现:
- nodejs - 服务端
- browserify
- modules-webmake
- wreq - 客户端
AMD :异步require
AMD,Asynchronous Module Definition,异步组件定义,很多需要使用组件系统的前端开发人员定义了AMD。
CommonJs主要是针对JS的后端运行制定的标准,无法适应前端的需求。
服务端的JS、客户端JS的不同点如下:
序号 | 服务端JavaScript | 客户端JavaScript |
---|---|---|
场景 | JS代码,在服务端由解释器执行多次 | JS代码,由服务端分发到各个客户端,再由Web浏览器解释执行 |
性能瓶颈 | 服务端的CPU与内存 | 服务端与Web浏览器之间的带宽 |
读取方式 | 通过读取磁盘加载JS代码 | Web浏览器通过网络下载JS代码 |
AMD规范,针对客户端Java Script的运行环境,制定规范。
require(["module","../file"],function(module,file){/*...*/});
define("mymodule",["dep1","dep2"],function(d1,d2){
return someExportedValue;
});
优点:
1、异步加载,适合前端环境。
2、支持依赖组件并行加载。
缺点:
1、编码开销较大,代码更难开发与阅读。
实现:
require.js - 客户端
curl - 客户端
ES6 组件
ECMAScript 2015 (6th Edition)标准添加了Java Script组件之间互相引用的标准。
import "jquery";
export function doStuff() {}
module "localModule" {}
优点:
1、静态分析容易
2、ES标准是以后的发展趋势
缺点:
1、本地浏览器支持需要时间
2、此种模式的Java Script组件较少。
组件传输
虽然web客户端的组件是在浏览器运行,但是都是由web服务端下载至客户端。
关于web客户端组件的传输,存在两个极端策略:
一次请求,仅传输一个组件
优点:仅传输必须的组件
缺点:多次请求,意味着高负载,给web app带来更高的启动延时。一次请求,传输所有组件
优点:网络畅通时,低负载,更低延时
缺点:传输了(当时)无用的组件这两种传输策略都曾经广泛应用,但都是次优的。
分块传输 Chunked Transferring
我们可以考虑,在取两者之间的平衡策略。
在编译所有组件时,将组件集合分割为多个批次(或者区块)。
某个批次在被请求时,再传输。既解决前者高负载、高启动延时的问题,又避免过多的传输无用组件。
开发者需要确定分割点,然后由webpack(grunt、gulp等)组件系统完成具体的分组划分工作。
webpack组件系统除了支持Java Script组件的,还通过加载器支持其他资源文件:
- 样式文件
- 图片
- 字体
- html模板
- coffeescript → javascript
- elm → javascript
- less stylesheets → css stylesheets
- jade templates → javascript which generates html
etc
语法类似:
require("./style.less");
require("./template.jade");
require("./image.png");
程序分析 STATIC ANALYSIS
当编译所有组件时,webpack组件系统的程序分析模块,会尝试理清这些组件之间的依赖关系。
通常,只能发现无表达式语句的简单依赖,但是经常会出现类似语句:require("./templates/" + name + ".jade")
。
许多代码库,都具有不同的风格。有些是非常奇怪的。webpack必须充分考虑现有代码的可用性以及兼容性。