A host controls how scripts pull in other scripts by implementing
ModuleProvider. Without one, require is unavailable — a script cannot load
code the host has not sanctioned. This is the JavaScript analogue of golua's
code provider.
WithModuleProvider(p) enables CommonJS-style require(specifier). Each
module runs in its own scope with module, exports, require,
__filename, and __dirname.
A module's require resolves relative specifiers (./lib/vec.js) against
that module — the provider's Resolve(specifier, referrer) does the mapping.
Modules are cached by canonical id: a module's body runs once and the same
exports is returned on subsequent requires (circular deps see a partial
exports rather than looping).
NewMapModuleProvider serves from an in-memory map — ideal when the host
already holds scripts in memory (game data files, bundled assets). Implement
the two-method ModuleProvider interface yourself to serve from a pak
archive, database, or network. NewDirModuleProvider(dir) serves from a
directory, confined to that root.
Example: intercepting require() with a ModuleProvider.
A host serves module source from its own storage — here an in-memory map,
standing in for a game's data files, a pak archive, or a virtual filesystem.
The engine never touches the real filesystem; every require() goes through the
provider. Modules use CommonJS conventions (module.exports / exports /
require), including relative specifiers and caching (a module runs once).