Hao JS is an embeddable JavaScript and TypeScript runtime for native projects.
It is meant for projects that want to run JS/TS inside a native host, expose a
few first-party modules, and keep the host language close to the script world.
Hao owns the runtime layer: loading modules, running async work, registering
native bindings, and giving scripts a stable std: module namespace.
Hao reserves std: for runtime modules.
Current modules include:
std:runtimestd:fsstd:processstd:httpstd:ffistd:telemetrystd:utilstd:teststd:plot
Host projects should use their own prefixes, such as affon: or myapp:, for
their product modules.
Hao loads third-party packages from node_modules using package manifests. A
package must include package.json and expose entry points through exports or
main. Resolved entries are accepted only when they are ESM-compatible by a
safe whitelist: .mjs, .mts, .ts, native addon libraries, or .js inside a
package that declares "type": "module".
{
"type": "module",
"exports": {
".": "./index.ts",
"./native": "./native.dylib"
}
}CommonJS packages, ambiguous .js entries, and unexported package subpaths are
rejected by the module loader.
Set RUNTIME_PACKAGE_PATH to add package search roots before Hao walks ancestor
node_modules directories. Entries use the platform path delimiter (: on
macOS/Linux, ; on Windows), and each root should contain package directories:
RUNTIME_PACKAGE_PATH="../packages:../vendor/node_modules" hao app/main.tsWith that configuration, import "foo" checks ../packages/foo, then
../vendor/node_modules/foo, then the usual node_modules chain.
hao path/to/main.ts
hao --versionRun tests:
hao test test/e2e/runtimeTest output uses ANSI colors by default. Use plain Unicode output:
RUNTIME_TEST_REPORTER=plain hao test test/e2e/runtimeBuild the local CLI from source:
zig build
./zig-out/bin/hao path/to/main.ts