前端开发和其他开发工作的主要区别,首先是前端是基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
那么什么是模块呢?
在模块化编程中,开发者将程序分解成离散功能块(discrete chunks of functionality),并称之为模块
每个模块具有比完整程序更小的接触面,使得校验、调试、测试轻而易举。 精心编写的模块提供了可靠的抽象和封装界限,使得应用程序中每个模块都具有条理清楚的设计和明确的目的
模块系统的演进
模块系统主要解决模块的定义、依赖和导出,先来看看已经存在的模块系统。
1)、非模块
通过多个script标签引入多个js文件,也即通过文件的方式来管理模块。
1 | <script src="Jquery.js"></script> |
这种原始的方案有很多显而易见的弊端:
- 污染全局作用域,多人协作简直是灾难。
- 手动维护script标签的顺序,多页应用更惨。
- 大型项目资源难以管理,容易留下隐患。
2)、CommonJS模块
CommonJS的模块方案是通过require同步加载依赖的其他模块,通过exports或module.exports来暴露出需要的接口。 (了解更多请移步 CommonJS模块规范)
这种原始的方案的优点:
- 复用性强。
- 有不少可以拿来即用的模块,生态不错。
- 实现简单,使用简单。
这种原始的方案的弊端:
- 同步加载不适合浏览器,浏览器的请求都是异步加载。
- 不能并行加载多个模块。
3)、AMD 模块
AMD 模块,全称为 Asynchromous Module Defination,翻译过来就是异步模块规范,它是由 RequireJs 推动的。
AMD方案只有一个主要接口define(moduleName, dependencies, factory),他要在声明模块的时候指定所有的依赖dependencies,并传入到factory中,对于依赖的模块异步加载并执行。
1 | // 定义 |
这种原始的方案的优点:
- 异步加载适合浏览器。
- 可并行加载多个模块。
这种原始的方案的弊端:
- 模块定义方式不优雅,不符合标准模块化
4)、ES6模块
ES6模块方案最大的特点就是静态化,静态化的优势在于可以在编译的时候确定模块的依赖关系以及输入输出的变量。上面提到的CommonJS模块和AMD模块都只能在运行时确定这些东西。
这种原始的方案的优点:
- 可静态分析,提前编译。
- 面向未来的标准。
这种原始的方案的弊端:
- 浏览器原生兼容性差,所以一般都编译成ES5。
- 目前可以拿来即用的模块少,生态差。
5)、webpack模块化机制
webpack并不强制你使用某种模块化方案,而是通过兼容所有模块化方案让你无痛接入项目,当然这也是webpack牛逼的地方。
有了webpack,你可以随意选择你喜欢的模块化方案,至于怎么处理模块之间的依赖关系及如何按需打包,放轻松,webpack会帮你处理好的。
webpack的模块化有什么特点?
- 可以兼容多种模块风格,无痛迁移老项目。
- 任何一个类型的文件都是模块,js/css/图片/字体都是模块。
- 静态解析,按需打包,动态加载。
本来,模块化方案仅仅是针对JS。但实际项目中,我们希望css也能被当做模块,进一步,css/less/sass是不是也可以被当做模块,再进一步,html/image/template是不是也可以被当做模块。
想到这些就觉得脑洞大开,不可思议!但是webpack居然做到了!webpack提供的loaders可以对文件做预处理,从而实现了一切皆模块。