This directory contains an example module resolution and loading framework and
require() implementation based on the Node.js module system:
The application needs only to provide the module resolution and loading logic:
Add
duk_module_node.cto list of C sources to compile.Ensure
duk_module_node.his in the include path.Include the extra header in calling code and initialize the bindings:
#include "duktape.h" #include "duk_module_node.h" /* After initializing the Duktape heap or when creating a new * thread with a new global environment: */ duk_push_object(ctx); duk_push_c_function(ctx, cb_resolve_module, DUK_VARARGS); duk_put_prop_string(ctx, -2, "resolve"); duk_push_c_function(ctx, cb_load_module, DUK_VARARGS); duk_put_prop_string(ctx, -2, "load"); duk_module_node_init(ctx);
Do not call
duk_module_node_init()more than once for the same global environment. Doing so is undefined behavior and may put the module system in an inconsistent state.It is possible to replace the callbacks after initialization by setting the following internal properties on the global stash:
\xffmodResolve\xffmodLoad
The resolve callback is a Duktape/C function which takes the string passed to
require()and resolves it to a canonical module ID (for Node.js this is usually the fully resolved filename of the module):duk_ret_t cb_resolve_module(duk_context *ctx) { /* * Entry stack: [ requested_id parent_id ] */ const char *requested_id = duk_get_string(ctx, 0); const char *parent_id = duk_get_string(ctx, 1); /* calling module */ const char *resolved_id; /* Arrive at the canonical module ID somehow. */ duk_push_string(ctx, resolved_id); return 1; /*nrets*/ }If the module ID cannot be resolved, the resolve callback should throw an error, which will propagate out of the
require()call. Note also that when the globalrequire()is called, the parent ID is an empty string.The load callback is a Duktape/C function which takes the resolved module ID and: (1) returns the ECMAScript source code for the module or
undefinedif there's no source code, e.g. for pure C modules, (2) can populatemodule.exportsitself, and (3) can replacemodule.exports:duk_ret_t cb_load_module(duk_context *ctx) { /* * Entry stack: [ resolved_id exports module ] */ /* Arrive at the JS source code for the module somehow. */ duk_push_string(ctx, module_source); return 1; /*nrets*/ }As with the resolve callback, the load callback should throw an error if the module cannot be loaded for any reason.
After these steps,
require()will be registered to the global object and the module system is ready to use.The main module (file being evaluated) should be loaded using
duk_module_node_peval_main(). This function registers the module inrequire.mainand thus should only be called once.