I am using Duktape to embed JavaScript, but using require
always causes an error:
int main(){
duk_context *ctx = duk_create_heap_default();
duk_peval_file(ctx, "example.js");
printf("file load err %s", duk_safe_to_string(ctx, -1));
duk_destroy_heap(ctx);
}
example.js
var mylib = require("mylib")
print (mylib.hello)
mylib.js
exports.hello = "Hello"
Error:
file load err TypeError: not callable
Stack dump says:
duk_js_call.c:682
require native strict preventsyield
eval example.js:1 preventsyield
I am using Duktape to embed JavaScript, but using require
always causes an error:
int main(){
duk_context *ctx = duk_create_heap_default();
duk_peval_file(ctx, "example.js");
printf("file load err %s", duk_safe_to_string(ctx, -1));
duk_destroy_heap(ctx);
}
example.js
var mylib = require("mylib")
print (mylib.hello)
mylib.js
exports.hello = "Hello"
Error:
file load err TypeError: not callable
Stack dump says:
Share Improve this question edited May 29, 2017 at 18:07 Badacadabra 8,5357 gold badges31 silver badges54 bronze badges asked Feb 25, 2015 at 21:21 caydanlikcaydanlik 513 bronze badgesduk_js_call.c:682
require native strict preventsyield
eval example.js:1 preventsyield
2 Answers
Reset to default 6Duktape requires (no pun intended) you to provide a Module Search function in order to preserve portability. However, implementing one is a pretty simple and straight-forward task even if you have little experience in Duktape.
A very simple but fully functional Module Search function would be:
Duktape.modSearch = function(id) {
return readFileAsString(id);
}
This would allow you to call require(filename)
from the Duktape Javascript environment with a filename as parameter and use it as your module. A more advanced function would handle errors or maybe search multiple paths and folders.
To use the require()
function, you now have to create a C/C++ function that handles reading a file and returning it's content as a string and bind this function to the Duktape engine (Example for this is on the Duktape home page).
Now call this function definition from the Duktape runtime (For example using duk_eval_string(ctx, "Duktape.modSearch = ...");
) and you should be able to call require()
.
This answer is fairly inplete. Leave many things to the imagination.
The following code is not mine, but is also available in sof and solves the problem of implementing the modSearch function:
duk_ret_t mod_search(duk_context *ctx) {
/* Nargs was given as 4 and we get the following stack arguments:
* index 0: id
* index 1: require
* index 2: exports
* index 3: module
*/
char *src = NULL;
FILE *f = NULL;
const char *filename = "/home/user/benchmark/js_modules/mylib.js";
int rc, len;
// Pull Arguments
char *id = duk_require_string(ctx, 0);
printf("ID => %s \n", id);
rc = strcmp(id, "mylib");
if(rc == 0)
{
printf("Module found, loading... \n");
// Read File and calculate its size (as DUKtape examples)
f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
len = (int) ftell(f);
// Rewind
fseek(f, 0, SEEK_SET);
src = malloc(len);
fread(src, 1, len,f);
fclose(f);
duk_push_lstring(ctx, src, len);
free(src);
return 1;
}
// Error
return -1;
}
Then, we need a native-code C function to register the modSearch function:
/* Declaration */
void modSearch_register(duk_context *ctx) {
duk_get_global_string(ctx, "Duktape");
duk_push_c_function(ctx, mod_search, 4 /*nargs*/);
duk_put_prop_string(ctx, -2, "modSearch");
duk_pop(ctx);
}
Then the main code:
duk_context *ctx;
ctx = duk_create_heap_default();
if (!ctx) {
return 1;
}
duk_push_c_function(ctx, handle_print, 1);
duk_put_global_string(ctx, "print");
duk_module_duktape_init(ctx);
printf("top after init: %ld\n", (long) duk_get_top(ctx));
//call function defintion for require
modSearch_register(ctx);
/* We push to Duktape heap the JS file*/
push_file_as_string(ctx, argv[1]);
if (duk_peval(ctx) != 0) {
printf("Error peval: %s\n", duk_safe_to_string(ctx, -1));
goto finished;
}
duk_pop(ctx); /* pop result/error */
finished:
duk_destroy_heap(ctx);
The native c code print function can be obtained from duktape web page, for example:
static duk_ret_t handle_print(duk_context *ctx) {
printf("%s\n", duk_safe_to_string(ctx, 0));
return 0;
}