摘要:本文学习了前端模块化工具RequireJS的基本原理和使用方式。
1 简介
1.1 介绍
RequireJS是基于AMD(Asynchronous Module Definition)规范实现的JS模块加载器,主要用于浏览器环境。
AMD规范采用异步方式加载模块,推崇依赖前置,模块会提前加载。
RequireJS解决了传统加载方式的依赖管理混乱、命名冲突、加载顺序不可控等问题。
RequireJS的出现早于ESM,是早期前端模块化开发的主流方案之一,与SeaJS并称前端模块化双雄。
1.2 背景
在传统的JS开发中,所有代码都写在一个或多个全局作用域中,容易造成以下问题:
- 命名冲突
- 文件依赖顺序难以维护
- 代码难以复用和测试
模块化开发通过将代码拆分成独立、可复用的单元,解决了上述问题。
1.3 对比
前端模块化规范对比:
| 规范 | 特点描述 |
|---|---|
| AMD | 异步加载,依赖前置,代表实现:RequireJS |
| CMD | 异步加载,依赖就近,代表实现:SeaJS |
| CommonJS | 同步加载,适用于服务端,代表实现:NodeJS |
| ESM | 原生支持,静态编译,浏览器和服务端通用 |
2 快速使用
2.1 引入
下载使用依赖的require.js文件,提供了压缩版和注释版适用不同的使用环境:
目录结构:
1 | webapp |
在HTML中通过script元素引入:
1 | <script data-main="js/require-main" src="js/require.js"></script> |
使用data-main属性指定入口脚本的位置,入口脚本可以省略文件后缀,在加载依赖文件后,会自动加载入口脚本。
2.2 入口脚本
入口脚本也称为顶级脚本,入口脚本中定义了框架配置,加载入口脚本的方式属于异步加载。
如果不指定data-main属性,也可以手动加载:
1 | <script src="js/require-main.js"></script> |
如果需要在页面上执行require()方法,就不能使用异步加载的方式,因为在执行时入口脚本可能还没有加载,所以只能使用手动加载的方式。
2.3 定义模块
RequireJS官方文档建议一个JS文件只定义一个模块。
使用define()方法定义模块,需要在模块文件中定义。
示例:
1 | define(function() { |
2.4 配置模块
通过require.config()定义框架配置,需要在入口脚本中定义。
示例:
1 | require.config({ |
2.5 使用模块
RequireJS默认所有模块都是脚本,因此使用模块时不需要指定.js后缀。
使用require()方法加载模块,可以在脚本文件中使用,也可以在页面中使用。
示例:
1 | require(['show'], function(show) { |
在页面使用时需要先加载入口脚本,才能使用模块。
3 高级用法
3.1 多种方式定义模块
3.1.1 无返回值
定义无返回值的模块并配置模块:
1 | define(function() { |
使用show模块:
1 | require(['show'], function() { |
3.1.2 有返回值
定义有返回值的模块并配置模块:
1 | define(function() { |
使用show模块:
1 | require(['show'], function(show) { |
3.1.3 模块依赖
定义show模块并配置模块:
1 | define(function() { |
定义test模块并配置模块,在test模块中依赖show模块:
1 | define(['show'], function(show) { |
使用test模块:
1 | require(['test'], function() { |
3.1.4 匿名模块
定义模块时没有指定模块名:
1 | define(function() { |
匿名模块有两种使用方式:
- 不在配置中定义模块名,在使用时将位置作为模块名使用:
js 1
2
3require(['show/show'], function(show) {
show.show('hello');
}); - 在配置中定义模块名并指定位置,在使用时通过模块名使用:
js 1
2
3require(['show'], function(show) {
show.show('hello');
});
3.1.5 具名模块
定义模块时指定模块名,需要在第一个参数传入字符串:
1 | define('show/show', function() { |
具名模块有两种使用方式:
- 模块名就是文件所在位置,在使用时通过模块名使用:
js 1
2
3require(['show/show'], function(show) {
show.show('hello');
}); - 模块名不是文件所在位置,需要在配置中定义模块名并指定位置,在使用时通过模块名使用:
js 1
2
3require(['show'], function(show) {
show.show('hello');
});
3.2 非AMD模块支持
3.2.1 配置
对于非AMD规范的库,比如早期的JQuery库,这些库并没有通过define()方法定义,并不是模块,所以需要对其进行特殊配置,以便作为模块使用。
配置path属性,增加JQuery库:
1 | 'jquery': 'jquery/jquery-1.6.4.min' |
配置shim属性,增加JQuery库:
1 | 'jquery': { |
参数:
- deps:表示依赖,单个依赖可以使用字符串,多个依赖需要使用数组,如果没有可以省略。
- exports:表示导出对象的名称,如果没有可以省略。
如果只有deps属性,还可以进一步简写为:
1 | 'test': ['jquery'] |
3.2.2 使用
可以在页面上直接使用JQuery库:
1 | require(['jquery'], function($) { |
也可以在test模块中依赖JQuery库:
1 | define(['jquery'], function($) { |
然后在页面上使用test模块:
1 | require(['test'], function() { |
3.3 模块替换
3.3.1 多版本支持
通过map属性可以配置模块的多版本支持:
1 | map: { |
在使用test模块时,默认使用test-1.0模块,如果是new/demo.js文件,则使用test-2.0模块。
3.3.2 模块映射
通过map属性可以配置模块映射:
1 | map: { |
在依赖css模块时,会自动映射为js/css.min模块:
1 | require(['css!css/min'], function(css) { |
先加载js/css.min模块,再加载css/min模块。
条