require.js用于非浏览器平台或使用函数构造函数的正确方法



我正试图在Apple TV项目中使用requirejs。我们有很多为web编写的requirejs模块,如果我们能重用它们,那就太酷了。

苹果电视平台有一定的局限性,不可能"按原样"使用requirejs。没有常识性的DOM。我发现克服这个问题的一种可能方法是:首先加载require.js本身,然后覆盖其.load()方法,因此每当调用require('foo')时,它都会通过一个简单的XHR调用加载foo.js

requirejs.load = (context, moduleName, moduleUrl) ->
reqModule = new XMLHttpRequest()
reqModule.open('GET', appRoot+moduleUrl, true)
reqModule.send(null)
reqModule.onreadystatechange = ->
if reqModule.readyState is 4 and reqModule.status is 200
fn = (new Function(reqModule.responseText))() # parse module                             
context[moduleName] = fn
context.completeLoad(moduleName)

因此,这适用于像这样的正常定义的模块:

define [], ->
someField: 'empty field'

甚至适用于这样的自执行功能(配置垫片):

(myFoo = ->
someField:"empty field"
)()

例如Undercore.js包含在一个自执行包装器中

然而,这不适用于这样定义的模块:

myFoo = ->
someField:"empty field"

问题:如何使它适用于所有3种情况?当在浏览器中使用时,requirejs成功地加载了所有这些文件。

我发现的一个解决方案是像上一个例子一样,将函数封装在未封装模块的define块中,所以我不做fn = (new Function(reqModule.responseText))(),而是做:

fn = define [], (new Function("return "+reqModule.responseText))()

但这将打破第一种和第二种情况下的load。有没有一种方法可以确定函数是否封装在自执行块中?如何区分前两种情况和后一种情况?

以问题中的代码为起点,我能够使以下代码发挥作用。我没有苹果电视,所以我不能在苹果电视上测试。我已经在浏览器上测试过了。只要第2个和第3个模块有合适的垫片,它就可以加载您在问题中显示的所有3种类型的模块。因此,逻辑是合理的。缺失的部分是需要在eval.call(window, ...)中代替window的部分。在Node.js中,它将是global。我不知道苹果电视中的对等产品。

requirejs.load = function(context, moduleName, moduleUrl) {
var reqModule = new XMLHttpRequest();
reqModule.open('GET', moduleUrl, true);
reqModule.send(null);
return reqModule.onreadystatechange = function() {
if (reqModule.readyState === 4 && reqModule.status === 200) {
eval.call(window, reqModule.responseText);
return context.completeLoad(moduleName);
}
};
};

如果我是你,我会使用Browserify

使用node.js-style requires编写浏览器代码。

最新更新