Updated October 4, 2023
This directory contains example projects that use package.json
to describe the build dependencies. These are intended to be used with mcpack
, a tool in the Moddable SDK to package embedded applications. mcpack
is front-end to the Moddable build process. It starts with package.json
, scans the dependencies, and generates a Moddable manifest.json
file which is built, deployed, and run using mcconfig
.
mcpack
has has several features to help streamline development and provide compatibility with common JavaScript conventions. It does this by analyzing the project source code.
- Built-in modules. When a project imports a module built into the Moddable SDK such as "timer", "wifi", "pins/digital", or "piu/MC",
mcpack
includes the module in the project. Built-in modules may optionally prefixed with "moddable:", such as "moddable:timer", to be explicit that they are Moddable SDK built-in modules. - Well-known globals. JavaScript developers are accustomed to using certain global variables, such as
setTimeout
,console
, andfetch
across JavaScript environments.mcpack
detects use of these globals and automatically includes the required modules and defines the global. The following globals are supported.clearImmediate
,setImmediate
,setInterval
,setTimeout
- Timer functions.console.log()
- Output to the debug console. The other capabilities ofconsole
are not providedfetch
- HTTP requests.Headers
- Map of http headers, typically used withfetch()
structuredClone
- Clone JavaScript objects.TextDecoder
- Convert binary buffers to JavaScript strings.TextEncoder
- Convert JavaScript strings to UTF-8 formatted buffers.URL
- URL parsingWorker
,SharedWorker
- Use multiple independent JavaScript virtual machines (Web Workers).
- Top-level await (TLA). The Moddable SDK supports TLA but requires it to be explicitly enabled in the project. This allows projects that do not use the feature to be smaller.
mcpack
detects when TLA is used and automatically sets theMODDEF_MAIN_ASYNC
build flag.
The package.json
support does not replace the Moddable SDK manifest.json
, though for many projects package.json
may be all that's needed. mcpack
generates a manifest.json
from the package.json
, and manifests can still be used together with package.json
.
To run the package examples on the simulator, do the following:
cd $MODDABLE/examples/package/hello
npm install
mcpack mcconfig -d -m -p sim
The npm install
is only necessary the first time you build, to retrieve any external dependencies. The mcpack
tool invocation is followed by the usual mcconfig
. To run the same project on an ESP32 Node-MCU board:
mcpack mcconfig -d -m -p esp32/nodemcu
To run a package that requires the network, such as fetch
, specify the Wi-Fi credentials to mcconfig as usual:
mcpack mcconfig -d -m -p esp/moddable_one ssid="My Wi-Fi" password=secret
The following section provides notes on each example. The notes describe some of the features of package.json
and mcpack
that each example demonstrates.
This is the package.json version of the classic Moddable SDK Piu balls example. In addition to the package.json
there is a manifest.json
which is used to include the graphical assets and disable touch input handling. The manifest.json is included automatically based on its name and location in the same directory as the package.json
.
Notice that main.js does:
import {} from "piu/MC";
This import is automatically detected and the manifest_piu.json
is included in the generated manifest:
> mcpack mcconfig -d -m
# mcpack include: $(MODDABLE)/examples/manifest_piu.json
This example demonstrates use of the @moddable/eventemitter3
package, a Moddable SDK port of the popular eventemitter3
npm package.
This example makes several HTTP requests using the fetch()
API. In main.js, the application accesses fetch
, URL
, Headers
, and console.log
globals so these are automatically included by mcpack
.
> mcpack mcconfig -d -m
# mcpack include: $(MODDABLE)/modules/data/url/manifest.json
# mcpack define: URL, URLSearchParams
# mcpack include: $(MODDABLE)/modules/data/headers/manifest.json
# mcpack define: Headers
# mcpack include: $(MODDABLE)/examples/io/tcp/fetch/manifest_fetch.json
# mcpack define: fetch
# mcpack define: console
# xsc globals.xsb
mcpack
generates a globals.js
file to initialize the global variables.
This example shows different ways that modules can be included in a project. This example uses external modules from npm, so it is necessary to do npm install
in the directory to download those before running mcpack
.
The package.json
imports three packages from npm. Two of those are examples to show package import and mapping. The third is the popular mustache library, to demonstrate that modules implemented using standard JavaScript and supported dependencies can run on embedded devices, thanks to the ES2023 support of the XS JavaScript engine in the Moddable SDK.
The imports
section of package.json
shows two important features:
"imports": {
"#test": {
"moddable": "./test-xs.js",
"default": "./test-node.js"
}
}
First, the "#test"
import is a private relative specifier, so the module will only be available within this package. Second, the package.json can provide different implementations of a module depending on the target runtime. Here the key "moddable" means that test-xs.js is used when building for the Moddable SDK with mcpack
and otherwise test-node.js is used. This is a powerful tool for organizing your project so that it can run on embedded targets as well as others.
This is an example of using mcpack
to build and run a mod using mcrun
. Before running this example, it is necessary to run the run-mod
example to install the host for the mod.
mod-balls is the classic balls example as a mod using package.json
. To run it on the simulator:
mcpack mcrun -d -m
Rather than use an external manifest.json
, like balls above, to include the graphical assets, it embeds a manifest inside package.json
. The choice of whether to use an embedded or external manifest is a matter of preferred style; there is no functional difference.
"moddable": {
"manifest": {
"resources": {
"*": "./balls"
}
}
}
When mcpack
is used to build a mod, it does not perform any automatic imports or initialization of globals as it assumes the host will take care of that. Dependencies on the built-in Moddable SDK modules can still be included by adding them to the manifest.
This is a host for running mods that use the Piu user interface framework.
By itself run-mod doesn't do much. It relies on a mod to draw something. Once run-mod is installed, run the mod-balls example.
This example is a web-compatible variation of the timers example. Instead of using the timer
module directly, it uses setTimeout
(and friends) through globals. mcpack
detects the use of these well-known globals and automatically adds implementations of these functions to globals.js to make them available to the script. The implementation of those globals uses the "timer" module.
This example shows two different way that top-level await can be used, even in a projects main.js
. The main module imports the "wow" module, which uses await at the top-level to initialize its return value. This promise is resolved before execution of main continues. Once main runs, it waits 500 ms for setTimeout
and then outputs "done waiting."
This example shows how TypeScript sources files can be used in a package.json
using mcpack
The package.json
contains a "build" script to convert the TypeScript sources to JavaScript:
"scripts": {
"build": "tsc"
}
To invoke this script as part of the mcpack
build, use the following command line:
npm run build && mcpack mcconfig -d -m
There are many different ways that developers use to process the TypeScript sources. This is just one workflow.
The directory includes a tsconfig.json
to configure the TypeScript compiler. This is important as it sets the target output of the TypeScript compiler to ES2022. Targeting earlier versions of JavaScript causes TypeScript to generate JavaScript that is less efficient and, in some cases, incompatible with embedded execution.