声明 本教程整理于互联网
webpack是当下最热门的前端资源模块化管理和打包工具。它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分隔,到实际需要的时候再异步加载。通过loader的转换,任何形式的资源都可以视作模块,比如CommonJs模块、AMD模块、ES6模块、CSS、图片、JSON、Coffeescript、 LESS等
# 一、模块系统的演进
-
模块系统主要解决模块的定义、依赖和导出,先来看看已经存在的模块系统
-
<script>标签
<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="libraryA.js"></script>
<script src="module3.js"></script>
@前端进阶之旅: 代码已经复制到剪贴板
-
这是最原始的
JavaScript文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在window对象中,不同模块的接口调用都是一个作用域中,一些复杂的框架,会使用命名空间的概念来组织这些模块的接口,典型的例子如YUI库 -
这种原始的加载方式暴露了一些显而易见的弊端
- 全局作用域下容易造成变量冲突
- 文件只能按照
<script>的书写顺序进行加载 - 开发人员必须主观解决模块和代码库的依赖关系
- 在大型项目中各种资源难以管理,长期积累的问题导致代码库混乱不堪
# 1.1 CommonJS
- 服务器端的
Node.js遵循CommonJS规范,该规范的核心思想是允许模块通过require方法来同步加载所要依赖的其他模块,然后通过exports或module.exports来导出需要暴露的接口
require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;
@前端进阶之旅: 代码已经复制到剪贴板
-
优点:
- 服务器端模块便于重用
NPM中已经有将近20万个可以使用模块包- 简单并容易使用
-
缺点:
- 同步的模块加载方式不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的
- 不能非阻塞的并行加载多个模块
-
实现
-
服务器端的
Node.js -
Browserify,浏览器端的CommonJS实现,可以使用NPM的模块,但是编译打包后的文件体积可能很大 -
modules-webmake,类似Browserify,还不如Browserify灵活 -
wreq,Browserify的前身
# 1.2 AMD
Asynchronous Module Definition规范其实只有一个主要接口define(id?, dependencies?,factory),它要在声明模块的时候指定所有的依赖dependencies,并且还要当做形参传到factory中,对于依赖的模块提前执行,依赖前置
define("module", ["dep1", "dep2"], function(d1, d2) {
return someExportedValue;
});require(["module", "../file"], function(module, file) { /* ... */ });
@前端进阶之旅: 代码已经复制到剪贴板
-
优点:
- 适合在浏览器环境中异步加载模块
- 可以并行加载多个模块
-
缺点:
- 提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义 不顺畅
- 不符合通用的模块化思维方式,是一种妥协的实现
-
实现:
RequireJScurl