从包中加载模块
RequireJS支持加载CommonJS Packages目录结构中的模块,但是需要指定一些其他配置才能使其正常工作。具体来说,它支持以下CommonJS Packages功能:
- 软件包可以与模块名称/前缀关联。
- 程序包配置可以为特定程序包指定以下属性:
- name:程序包的名称(用于模块名称/前缀映射)
- location:磁盘上的位置。位置相对于baseUrl配置值,除非它们包含协议或以反斜杠(/)开头。
- main:某人对“ packageName”的要求时应使用的包内模块的名称。默认值为“ main”,因此仅当它不同于默认值时才指定它。该值是相对于包文件夹的。
重要笔记
- 尽管软件包可以具有CommonJS目录布局,但模块本身应采用RequireJS可以理解的模块格式。规则的例外:如果您使用的是r.js节点适配器,则这些模块可以采用传统的CommonJS模块格式。如果需要将传统的CommonJS模块转换为RequireJS使用的异步模块格式,则可以使用CommonJS转换工具。
- 一次只能在项目上下文中使用软件包的一个版本。您可以使用RequireJS多版本支持来加载两个不同的模块上下文,但是如果要在一个上下文中使用程序包A和B,并且它们依赖于程序包C的不同版本,那么这将是一个问题。将来可能会改变。
如果您使用《入门指南》中指定的类似项目布局,则Web项目的开始将类似于以下内容(基于Node / Rhino的项目是类似的,只需使用scripts目录的内容作为顶级项目目录):
- 项目目录/
- project.html
- 脚本/
- require.js
这是带有两个包cart和store的示例目录布局的外观:
- 项目目录/
- project.html
- 脚本/
- 大车/
- main.js
- 店铺/
- main.js
- util.js
- main.js
- require.js
- 大车/
project.html将具有如下脚本标记:
<script data-main="scripts/main" src="scripts/require.js"></script>
这将指示require.js加载脚本/main.js。main.js使用“ packages”配置来设置与require.js相关的软件包,在这种情况下,它们是源文件“ cart”和“ store”:
//main.js contents
//Pass a config object to require
require.config({
"packages": ["cart", "store"]
});
require(["cart", "store", "store/util"],
function (cart, store, util) {
//use the modules as usual.
});
“ cart”的需求意味着它将从scripts / cart / main.js加载,因为“ main”是RequireJS支持的默认主模块设置。将从scripts / store / util.js加载“ store / util”的需求。
如果“ store”包未遵循“ main.js”约定,则看起来更像这样:
- 项目目录/
- project.html
- 脚本/
- 大车/
- main.js
- 店铺/
- store.js
- util.js
- main.js
- package.json
- require.js
- 大车/
然后,RequireJS配置将如下所示:
require.config({
packages: [
"cart",
{
name: "store",
main: "store"
}
]
});
为避免冗长,强烈建议始终使用在结构中使用“主要”约定的软件包。
多版本支持
如配置选项中所述,可以使用不同的“上下文”配置选项将模块的多个版本加载到页面中。require.config()返回一个使用上下文配置的require函数。这是一个加载两个不同版本的alpha和beta模块的示例(此示例摘自其中一个测试文件):
<script src="../require.js"></script>
<script>
var reqOne = require.config({
context: "version1",
baseUrl: "version1"
});
reqOne(["require", "alpha", "beta",],
function(require, alpha, beta) {
log("alpha version is: " + alpha.version); //prints 1
log("beta version is: " + beta.version); //prints 1
setTimeout(function() {
require(["omega"],
function(omega) {
log("version1 omega loaded with version: " +
omega.version); //prints 1
}
);
}, 100);
});
var reqTwo = require.config({
context: "version2",
baseUrl: "version2"
});
reqTwo(["require", "alpha", "beta"],
function(require, alpha, beta) {
log("alpha version is: " + alpha.version); //prints 2
log("beta version is: " + beta.version); //prints 2
setTimeout(function() {
require(["omega"],
function(omega) {
log("version2 omega loaded with version: " +
omega.version); //prints 2
}
);
}, 100);
});
</script>
注意,“ require”被指定为模块的依赖项。这允许传递给函数回调的require()函数使用正确的上下文正确加载模块以支持多版本。如果未将“ require”指定为依赖项,则可能会出现错误。
页面加载后加载代码
上面“ Multiversion支持”部分中的示例显示了以后如何通过嵌套的require()调用来加载代码。
网络工作者支持
从0.12版开始,RequireJS可以在Web Worker中运行。只需在网络工作者中使用importScripts()来加载require.js(或包含require()定义的JS文件),然后调用require。
您可能需要设置baseUrl 配置选项,以确保require()可以找到要加载的脚本。
通过查看单元测试中使用的文件之一,可以看到其用法示例。
犀牛支持§4.5
RequireJS可以通过r.js适配器在Rhino中使用。有关更多信息,请参见r.js自述文件。
Nashorn支持
从RequireJS 2.1.16开始,RequireJS可以通过r.js适配器在Java 8+的JavaScript引擎Nashorn中使用。有关更多信息,请参见r.js自述文件。
处理错误
错误的一般类别是脚本(未找到),网络超时或所加载脚本中的错误的404。RequireJS有一些用于处理它们的工具:特定于需求的errback,“ paths”数组配置以及全局的requirejs.onError。
传递给errbacks的错误对象和全局requirejs.onError函数通常将包含两个自定义属性:
- requireType:具有一般分类的字符串值,例如“ timeout”,“ nodefine”,“ scripterror”。
- requireModules:超时的模块名称/ URL的数组。
如果您在requireModules中遇到错误,则可能意味着未定义依赖于requireModules数组中的模块的其他模块。
捕获IE中的负载故障
Internet Explorer存在一系列问题,使得难以检测到错误/路径后备的加载失败:
- script.onerror在IE 6-8中不起作用。无法知道加载脚本是否会生成404,更糟糕的是,即使在404情况下,它也会触发具有完整状态的onreadystatechange。
- script.onerror确实可以在IE 9+中运行,但是存在一个错误,即在执行脚本后不立即触发script.onload事件处理程序,因此它不支持允许匿名AMD模块的标准方法。因此仍使用script.onreadystatechange。但是,在script.onerror函数启动之前,onreadystatechange会以完整状态启动。
因此,使用IE很难同时允许匿名的AMD模块和可靠的检测错误,匿名的AMD模块是AMD模块的核心优势。
但是,如果您知道在一个项目中使用define()声明其所有模块,或者它使用shim config为不使用define()的任何内容指定字符串导出,那么如果您设置了defineDefine配置值确实,加载器可以通过检查define()调用或填充程序的导出全局值的存在来确认脚本是否已加载。
因此,如果要支持Internet Explorer,捕获负载错误并通过直接define()调用或shim config获得模块化代码,请始终将forcedDefine设置为true。有关示例,请参见下一部分。
注意:如果您确实设置了forceDefine:true,并且使用data-main =“”来加载主JS模块,则该主JS模块必须调用define()而不是require()来加载所需的代码。JS主模块仍然可以调用require / requirejs来设置配置值,但是对于加载模块,它应该使用define()。
如果然后您还使用杏仁来构建没有require.js的代码,请确保使用insertRequire构建设置为主模块插入一个require调用-达到与最初的require()调用相同的目的,即调用data-main做。
require([])错误
当与requirejs.undef()一起使用时,Errbacks将允许您检测模块是否无法加载,取消定义该模块,将配置重置到另一个位置,然后重试。
一个常见的用例是使用CDN托管的库版本,但是如果失败,请切换到本地加载文件:
requirejs.config({
enforceDefine: true,
paths: {
jquery: 'http://ajax.lug.ustc.edu.cn/ajax/libs/jquery/1.4.4/jquery.min'
}
});
//Later
require(['jquery'], function ($) {
//Do something with $ here
}, function (err) {
//The errback, error callback
//The error has a list of modules that failed
var failedId = err.requireModules && err.requireModules[0];
if (failedId === 'jquery') {
//undef is function only on the global requirejs object.
//Use it to clear internal knowledge of jQuery. Any modules
//that were dependent on jQuery and in the middle of loading
//will not be loaded yet, they will wait until a valid jQuery
//does load.
requirejs.undef(failedId);
//Set the path to jQuery to local path
requirejs.config({
paths: {
jquery: 'local/jquery'
}
});
//Try again. Note that the above require callback
//with the "Do something with $ here" comment will
//be called if this new attempt to load jQuery succeeds.
require(['jquery'], function () {});
} else {
//Some other error. Maybe show message to the user.
}
});
使用`requirejs.undef()`,如果您稍后设置其他配置并尝试加载相同的模块,则加载器仍会记住哪些模块需要该依赖关系,并在新配置的模块加载时完成加载。
注意:errbacks仅适用于回调样式的require调用,而不适用define()调用。define()仅用于声明模块。
路径配置后备
上面的用于检测负载故障,对模块进行undef(),修改路径和重新加载的模式是一个足够常见的请求,它也有一个简写。路径配置允许使用数组值:
requirejs.config({
//To get timely, correct error triggers in IE, force a define/shim exports check.
enforceDefine: true,
paths: {
jquery: [
'http://ajax.lug.ustc.edu.cn/ajax/libs/jquery/1.4.4/jquery.min',
//If the CDN location fails, load from this location
'lib/jquery'
]
}
});
//Later
require(['jquery'], function ($) {
});
上面的代码将尝试CDN位置,但是如果失败,则退回到本地lib / jquery.js位置。
注意:路径回退仅适用于确切的模块ID匹配。这与可应用于模块ID前缀段的任何部分的常规路径配置不同。后备的目标更多是针对异常错误的恢复,而不是通用的路径搜索路径解决方案,因为它们在浏览器中效率低下。
全局requirejs.onError函数
要检测本地错误未捕获的错误,可以覆盖requirejs.onError():
requirejs.onError = function (err) {
console.log(err.requireType);
if (err.requireType === 'timeout') {
console.log('modules: ' + err.requireModules);
}
throw err;
};