1 回答

TA貢獻1770條經驗 獲得超3個贊
基本上,您想要的是文件導入功能。您可以通過兩種方式實現它:
在后端提供一個函數并將其導出到 JS,以允許在運行時動態加載文件。
實現像Node.js這樣的模塊處理(本質上也歸結為導入函數)。
第二個想法是最常用的方法,并實現了一種定義良好的方法,以在JS應用程序中包含其他文件。Duktape附帶了一個額外的文件來實現該命令,就像在Node.js中一樣。您只需要提供自己的函數來解析模塊并從磁盤加載它(因為 duktape 沒有文件 I/O 支持)。require
我在MySQL Workbench的MGA工具中實現了這種方法。用于實現節點模塊處理的 duktape 文件在這里。解析模塊的函數(包括處理嵌套文件夾等)在 ScriptingContext 類中實現。它的相關部分是這樣的:node_modules
/**
* Part of the module loading machinery. JS interfacing is done by the duk_module_node code.
* But we have to do the file work here. On the stack we get the value passed to `require()` as a "module ID" and
* the ID of the calling script (which is empty for the main script).
*/
duk_ret_t ScriptingContext::resolveModule(duk_context *ctx) {
// stack: [ requested_id parent_id ]
std::string requestedID = duk_get_string(ctx, 0);
std::string callingID = duk_get_string(ctx, 1);
std::string parentPath = FS::isDir(callingID) ? callingID : Path::dirname(callingID);
// Module resolution strategy in Node.js style: https://nodejs.org/api/modules.html#modules_all_together
auto modules = getInternalModules();
if (modules.find(requestedID) != modules.end()) {
duk_push_string(ctx, requestedID.c_str());
return 1;
}
ScriptingContext *context = ScriptingContext::fromDuktapeContext(ctx);
std::string resolvedID;
std::string cwd = Process::cwd();
try {
if (Path::isAbsolute(requestedID) || Utilities::hasPrefix(requestedID, ".")) {
std::string temp;
if (Path::isAbsolute(requestedID)) {
temp = Path::relative(cwd, requestedID);
} else
temp = Path::join({ parentPath, requestedID });
resolvedID = resolveFile(temp);
if (resolvedID.empty())
resolvedID = resolveFolder(context, temp);
}
} catch (std::runtime_error &e) {
// Triggered for parse errors in package.json.
context->throwScriptingError(ScriptingError::Syntax, e.what());
return 0;
}
// No files found so far. Check node modules.
if (resolvedID.empty()) {
for (auto &folder : moduleFolders(parentPath)) {
std::string path = Path::join({ folder, requestedID });
std::string temp = resolveFile(path);
if (!temp.empty()) {
resolvedID = temp;
break;
}
temp = resolveFolder(context, path);
if (!temp.empty()) {
resolvedID = temp;
break;
}
}
}
if (resolvedID.empty()) {
context->throwScriptingError(ScriptingError::Error, Utilities::format("Cannot resolve module %s", requestedID.c_str()));
return 0;
}
duk_push_string(ctx, resolvedID.c_str());
return 1; // Use result on stack.
}
添加回答
舉報