RequireJS是用于浏览器的AMD模块加载器,可以异步加载脚本和CSS文件。 您不再需要处理单个文件中脚本文件的顺序(例如index.html)。 取而代之的是,您只需将代码包装在模块定义中,RequireJS将处理依赖项,从而使您的代码更加结构化和组织良好。 它还具有优化工具,该工具可以对文件进行丑化和连接,以供生产使用。
该官方站点提供了有关其API的大量文档 ,并且有许多示例存储库可为您提供帮助。 但是它有很多配置,一开始需要RequireJS很难。
在本文中,我们将通过使用AMD模块构建库,对其进行优化并使用RequireJS优化器将其导出为独立模块,来学习如何使用RequireJS。 稍后,我们将使用RequireJS来构建应用程序并使用我们的库。
本教程假定您对RequireJS有所了解。 如果您正在寻找入门书籍 ,请查看: 了解RequireJS进行有效的JavaScript模块加载 。
安装RequireJS
RequireJS可通过Bower获得:
bower install requirejs --save
或者您可以在github上获取文件。
对于RequireJS项目,还有一个基于Grunt的Yeoman生成器 。
定义AMD模块
我们将代码包装在define()
,这将使其成为AMD模块。
文件: mylib.js
define(['jquery'], function($) {
// $ is jquery now.
return 'mylib';
});
而已。 请注意, define()
采用依赖项数组的可选第一个参数,在这种情况下为['jquery']
。 这是此模块的依赖项列表。 阵列中的所有模块将在此模块之前加载。 执行此模块时,参数是依赖项数组中的相应模块。
因此,在这种情况下,将首先加载jQuery,然后将其作为参数$
传递到函数中,然后我们可以在模块内部安全地使用它了。 最后,我们的模块返回一个字符串。 返回值是需要此模块时传递给函数参数的值。
需要其他模块
让我们通过定义第二个模块并要求我们的第一个模块mylib.js
了解其工作原理。
文件: main.js
define(['jquery', 'mylib'], function($, mylib) {
// $ is jquery as usual
// mylib is the string `mylib` because that's the return value
// from the first module
return {
version: '0.0.1, jQuery version: ' + $.fn.jquery,
mylibString: mylib
}
});
您可以在依赖项数组中根据需要选择任意多个依赖项,并且所有模块都可以通过函数参数以相同的顺序使用。 在第二个模块中,我们需要jquery
和mylib
模块,并仅返回一个对象,并公开一些变量。 该库的用户将使用该对象作为您的库。
配置RequireJS优化器:r.js
您可能想知道,仅通过查看依赖项数组中的字符串,RequireJS如何知道要加载的文件? 在我们的例子中,我们以字符串形式提供了jquery
和mylib
,而RequireJS知道这些模块在哪里。 mylib
很简单,就是mylib.js
,省略了.js
。
jquery
怎么样? 那就是使用RequireJS配置的地方。 您可以通过RequireJS配置提供广泛的配置。 提供此配置的方法有两种,由于我们使用的是RequireJS优化器,因此我将向您展示r.js方法。 r.js是RequireJS优化器。
我们将为r.js提供一个配置,它将所有模块优化到一个文件中。 我们提供的配置将使r.js将模块构建为独立的全局库,该库既可以用作AMD模块,也可以在浏览器中用作全局导出。
r.js可以通过命令行运行或作为Node模块运行。 还有一个Grunt任务grunt-requirejs
用于运行优化器。
话虽如此,让我们看看我们的配置是什么样的:
文件: tools/build.js
{
"baseUrl": "../lib",
"paths": {
"mylib": "../main"
},
"include": ["../tools/almond", "main"],
"exclude": ["jquery"],
"out": "../dist/mylib.js"
"wrap": {
"startFile": "wrap.start",
"endFile": "wrap.end"
}
}
配置文件确实是RequireJS的主要内容。 一旦了解了这些参数的工作原理,就可以像专业人士一样使用RequireJS。
您可以做不同的事情,并使用配置文件来调整项目构建。 要总体上了解有关配置和RequireJS的更多信息,我建议参考docs和Wiki 。 还有一个示例配置文件 ,演示了如何使用构建系统,因此请确保也参考该文件。
最后,我们实际上运行了优化器。 如前所述,您可以通过命令行或Node以及Grunt任务来运行它。 请参阅r.js自述文件,以了解如何在不同的环境中运行优化器。
node tools/r.js -o tools/build.js
这将在dist/mylib.js
生成构建文件
build.js
接下来,让我们看看参数的实际含义。
baseUrl –所有模块查找的根路径。
路径 –相对于baseUrl的模块名称的路径映射。
在我们的例子,“MYLIB”映射到“../main”,是相对于baseUrl
,所以当我们需要“MYLIB”它加载文件“../lib/../mylib/main.js”。
注意,我们附加了baseUrl
,然后是paths
设置,而不是模块名称,后跟.js
后缀。 您可以在此处指定如何将模块映射到jquery
和mylib
等文件。
包含 –我们要包含在优化过程中的模块。 包含的模块所需的依赖项被隐式包含。 在我们的例子中, main
模块也依赖于mylib
和jquery
,因此不需要显式地包含它。 我们还包括almond
,我将在后面提到。
排除 –我们要从优化过程中排除的模块。 在我们的例子中,我们排除了jquery
。 内置库的使用者将提供一个jQuery库。 以后使用我们的库时,我们会看到这一点。
out –优化的输出文件的名称。
wrap –将构建包包装在wrap
指定的开始和结束文本中。 优化后的输出文件如下: wrap.start
+包含的模块+ wrap.end
。 wrap.start
和wrap.end
是文件的名称,其内容包含在输出中。
杏仁
生成的库在文件中不包含require.js,而是使用杏仁。 almond是AMD API的一个小型实现,它将替换require.js。
包装我们的图书馆
在r.js配置中,我们用wrap.start
和wrap.end
文件包装了我们的库。 我们还在库中包含了杏仁,这些将使我们的库独立,因此可以通过浏览器全局变量使用它们而无需RequireJS或通过requirejs作为AMD模块使用。
File: wrap.start
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD.
define(['jquery'], factory);
} else {
// Browser globals.
root.mylib = factory(root.$);
}
}(this, function($) {
我们的模块包括main
, mylib
,和almond
都在这里中间wrap.start
和wrap.end
。
File: wrap.end
// Register in the values from the outer closure for common dependencies
// as local almond modules
define('jquery', function() {
return $;
});
// Use almond's special top level synchronous require to trigger factory
// functions, get the final module, and export it as the public api.
return require('mylib');
}));
如果使用者使用AMD加载程序,则生成的文件将要求“ jquery”作为AMD依赖项。 如果使用者仅使用浏览器全局变量,则库将获取$
全局变量并将其用于jQuery依赖项。
将库与RequireJS一起使用
我们的库已完成,现在通过构建requirejs应用程序来实际使用它。
文件: app.js
define(['jquery', 'mylib'], function($, mylib) {
// $ is jquery
// mylib is mylib that is:
// {
// version: 'version 0.0.1 jQuery version: xxx',
// mylib: 'mylib'
// }
});
这里没什么好想的,它是另一个需要jQuery和mylib的模块。 当使用define
模块时,不会立即执行该模块,即不会立即执行其回调函数(在依赖项数组之后传递)。 这意味着我们的应用程序不只是从定义此模块开始。 现在,让我们看看如何配置RequireJS并实际执行此模块即我们的应用程序。
为浏览器配置RequireJS
我们将配置RequireJS并在一个文件中执行我们的应用模块。 尽管有不同的方法可以做到这一点。
文件: common.js
requirejs.config({
baseUrl: '../lib',
paths: {
'jquery': 'jquery/dist/jquery.min',
'underscore': 'underscore/dist/underscore',
'backbone': 'backbone/backbone',
'mylib': 'mylib/dist/mylib',
'app': '../app'
},
shim: {
'jquery': {
exports: '$'
},
'backbone': {
deps: ['jquery', 'underscore'],
exports: 'Backbone',
},
'underscore': {
exports: '_'
}
}
});
require(['app/app'], function(App) {
// app module is available here
// you can start your application now
// this is immediately called because
// we used `require` instead of `define`
// to define this module.
});
baseUrl
和paths
配置与以前相同。 此处的附加配置值为:
shim :为不使用define()
声明依赖关系和设置模块值的传统“浏览器全局变量”脚本配置依赖关系并导出。 例如, Backbone不是AMD模块,而是一个全局浏览器,它将Backbone
导出到我们在exports
指定的全局名称空间中。 在我们的示例中,该模块还依赖于jQuery和Underscore ,因此我们使用deps
指定。 在装入Backbone之前,将装入deps
数组中的脚本,并且在装入后,将exports
值用作模块值。
请注意,您也可以在此应用程序项目中使用r.js,这将需要单独的配置。 但是不要为此感到困惑。 我不会详细介绍如何执行此操作,但这类似于我们为库所做的操作。 请参阅示例构建配置以获取更多参考。
要求与定义
稍后,我们使用require
加载模块并立即执行它。 有时,对于何时使用哪个define
和require
可能会感到困惑。 define
定义一个模块,但不执行它, require
定义一个模块并执行它-也就是说,它在执行自身之前加载并执行相关模块。 通常,你将有一个require
作为主要输入模块,将依赖于通过定义额外的模块define
。
加载脚本
通常,您将所有脚本文件都包含在index.html
。 现在我们正在使用RequireJS,我们只需要包括RequireJS并指定我们的data-main
,这是我们应用程序的入口点。 设置配置选项或分离index.html
使用的主模块有多种方法。 您可以在此处找到更多信息。
<script data-main="scripts/common" src="scripts/lib/require/require.js"></script>
结论
在本文中,我们构建了一个库,以及一个将该库与RequireJS一起使用的应用程序。 我们学习了如何配置r.js优化器,以及如何在浏览器中配置RequireJS。 最后,我们学习了如何使用RequireJS定义和使用AMD模块。 这使我们的代码井井有条,井井有条。
我在本教程的上半部分(配置优化器)中使用了这个example-libglobal存储库,下半部分并不那么复杂,因此现在应该自己动手制作它。
RequireJS官方网站是最终文档,但请确保查看github上的示例存储库以及该存储库中的示例项目,这些示例项目演示了RequireJS应用程序的用法。
From: https://www.sitepoint.com/building-library-with-requirejs/