在我的应用程序中,有动态部分从数据库加载为字符串,看起来像:
"define(['dependency1', 'dependency2'], function(){"+
" // function body" +
"})"
,它只是一个简单的requireJS模块,作为一个字符串。我想用async require调用延迟加载上面的脚本。所以,我的主要requireJS脚本看起来像:
require(["jquery"], function($){
$(document).ready(function(){
// logic to load specific script from database
var scriptString = functionToLoadTheStringAbove();
// ideally i would like to call it like this
require([scriptString], function(){
// scriptString, dependency1, dependency2 are loaded
}
});
});
我如何在requireJS加载这些字符串?我知道关于文本插件,但它只允许从文件加载。我试过eval,但它不能正确地解决依赖关系
这已经很晚了,但我只是把我的解决方案贴在这里,以防有人需要。
所以我最终在requireJS论坛上询问并检查了文本的来源!插件和json!插件。在RequireJS中从字符串中加载模块的最干净的方法是通过制作自己的插件来加载字符串,然后使用onLoad.fromText()来eval
你的字符串并解析所有依赖项。
我的插件的例子(让我们称之为db!
插件):
define([], function(){
var db = new Database(); // string is loaded from LocalStorage
return {
load: function(name, req, onLoad, reqConfig){
db.get(name, function(err, scriptString){
if (err) onLoad(err);
else onLoad.fromText(scriptString);
});
}
}
});
你可以这样使用插件:
require(["jquery", "db!myScript"], function($, myScript){
// jQuery, myScript and its dependencies are loaded from database
});
注意:
- 没有
eval
就没有办法从String到require()
。这就是onLoad.fromText()
内部所做的。因为eval是邪恶的,你应该只在你知道你要去eval()
的字符串的时候使用它。如果你在浏览器扩展中使用它,你可能想放松CSP策略。 要命名String模块,可以使用显式命名语法。这样,您的模块将始终具有相同的绝对名称。
要更直接地回答这个问题,创建一个这样的插件:
define("load-string",[], function(){
var strings=[],
re_package_name = /^string_module_(d+)$/;
return {
normalize: function(name, _){
if(re_package_name.test(name)){
return name
}
var nml = "string_module_" + (strings.push(name)-1);
return nml;
},
load: function(name, _, onLoad, config){
if(re_package_name.test(name)){
onLoad.fromText(strings[name.match(re_package_name)[1]]);
}else{
onLoad.error("Invalid package name: ",name);
}
}
}
});
,像这样使用:
var world_module = "define([],function(){return 'world!'})";
require(["load-string!" + world_module],
function(x){
console.log("Hello "+x);
})
你应该能够做到:
require(["jquery"], function($){
$(document).ready(function(){
// logic to load specific script from database
var scriptString = functionToLoadTheStringAbove();
var olddefine = define; // require js define
var runme; // capture function
define = function (args,func){
runme = func;
}
eval(scriptString);
runme(); // run the function in current scope
define = olddefine; // restore requirejs function
// dependency1, dependency2 are loaded
});
});