Modularized Output
By default, emscripten outputs regular JS scripts which can be loaded on the Web
via a script
tag, or on the command line using Node or other JS runtime.
In this default configuration the generated Module object variable (and indeed all of the emscripten internal symbols) are added to the global scope. This means that only one emscripten-built program can be loaded in a given scope (since multiple modules would clobber each other’s state).
The MODULARIZE setting (along with other related settings) can be used to isolate the generated module within its own private scope and/or allow multiple instances of the same module to be created.
This section covers the various modularization options available and how to use them.
Using -sMODULARIZE
The MODULARIZE setting has two primary functions. Firstly, it
puts all of the generated code inside its own scope so that the global namespace
is not polluted when the JS is loaded (for example, via script
tag).
Secondly, it allows multiple instances of the module to be created.
The generated factory function is async and it returns a promise of an instance of the program. It can be called any number of times to create multiple separate and isolated instances of the same program.
By default, the factory function is called Module
, but it can be given a
unique name via the -sEXPORT_NAME
setting.
For example, a program is built using -sMODUARLIZE -sEXPORT_NAME=Foo
can
be instantiated using:
var myFoo = await Foo({ /* optional params */ });
myFoo._nativeMethod();
or:
Foo({ /* optional params */ }).then((myFoo) => {
myFoo._nativeMethod();
}
If node is included in the -sENVIRONMENT
setting then the generated module
also acts as a CommonJS
module under node.
Because there is no global Module
object in this case any parameters to the
module creation are passed via the optional parameter to the factory function.
For example, if you wanted to use a custom print
method you could write:
var myFoo = await Foo({ print: myPrint });
Generating ES6 Modules
The EXPORT_ES6 setting can be used to instead output JavaScript in the form of an ES module. (The ES module format did not exist at time when the MODULARIZE setting was first created otherwise this would likely be the default).
Using an output filename that ends in .mjs will automatically enable this setting.
In this mode the module has a single default export which is the factory function for creating new instances of the module. For example:
import Foo from './emcc-output.js';
var myFoo = await Foo({ print: myPrint });
The name Foo
here can be whatever you choose and will always be assigned to
the default export of the module.
Using -sMODULARIZE=instance (experimental)
Emscripten has experimental support for performing only the encapsulation part of modularization, and not the ability to create multiple instances. In this mode a module is created that exports a single instance of the program rather than a factory function.
This setting only works when EXPORT_ES6 is enabled.
In this mode the default export of the module is an initializer function which allows input parameters to be passed to the instance. Other elements normally found on the module object are instead exported directly. For example:
// Import the default init function and a named native method
import init, { _nativeMethod } from './emcc-output.js';
await init({ print: myPrint });
_nativeMethod();
Source Phase Imports (experimental)
Source phase imports is a JavaScript proposal that adds support for importing Wasm modules via ES import statements. This allows emscripten to elide some of the auto-generated code for finding and fetching the Wasm binary.
See SOURCE_PHASE_IMPORTS.
This setting only works when EXPORT_ES6 is enabled.
ES Module Integration (experimental)
Wasm ESM integration is a WebAssembly proposal that allows Wasm instances to be imported directly as ES modules. This allows emscripten to elide a lot of boilerplate code for linking up Wasm and JavaScript.
See WASM_ESM_INTEGRATION.
This setting only works when EXPORT_ES6 is enabled.