How QuickJS-VM Bootstrap Sync Works from TypeScript Source in Instatic
The Instatic runtime keeps its QuickJS sandbox in sync by bundling TypeScript source files into self-contained IIFE strings via a dedicated sync script, exporting them as constants that the VM evaluates at startup.
Instatic uses QuickJS to sandbox plugin execution, but because the engine lacks a module loader, the entire runtime must be injected as a single JavaScript string. This article explains how the QuickJS-VM bootstrap sync from TypeScript source works, detailing the build pipeline that transforms TypeScript entry points into importable string constants.
The Core Challenge: Bootstrapping Without a Module Loader
QuickJS is a bare engine. When Instatic spawns a VM, it cannot rely on require or import to fetch dependencies. Instead, the server must supply a pre-bundled bootstrap script that defines the entire execution environment.
The TypeScript source for this environment lives in server/plugins/quickjs/bootstrap/src/, but the VM initialization code needs a plain JavaScript string. Maintaining this manually is error-prone, so Instatic automates the bootstrap sync through a TypeScript build pipeline.
Architecture: Source Entry Points
The project defines two distinct bootstrap targets:
- [
pluginRuntime.ts](https://github.com/CoreBunch/Instatic/blob/main/server/plugins/quickjs/bootstrap/src/pluginRuntime.ts) – The full plugin VM environment providing globals, APIs, and module resolution for standard plugins. - [
modulePackRuntime.ts](https://github.com/CoreBunch/Instatic/blob/main/server/plugins/quickjs/bootstrap/src/modulePackRuntime.ts) – A lighter VM used exclusively for "module-packs," which are pre-bundled plugin distributions.
Both files are located under server/plugins/quickjs/bootstrap/src/ and serve as entry points for the bundling process. They import the rest of the bootstrap logic, including boundary wrappers and the plugin API definitions found in buildApi.ts and boundary.ts.
The Sync Script: Bundling TypeScript to IIFE
The synchronization logic resides in [scripts/sync-plugin-bootstrap.ts](https://github.com/CoreBunch/Instatic/blob/main/scripts/sync-plugin-bootstrap.ts). This script uses Bun.build to convert each entry point into a single Immediately Invoked Function Expression (IIFE) suitable for direct evaluation inside QuickJS.
Key build parameters include:
format: 'iife'– Wraps the output in a self-executing function so it runs standalone.target: 'browser'– Ensures no Node.js or Bun-specific shims are included, maintaining compatibility with the bare QuickJS engine.- Minification disabled – Keeps the output deterministic and diff-friendly for version control.
The script exports buildBootstrapArtifacts(), which returns the bundled code as an in-memory string before writing to disk.
Generated Artifacts: String Constants for the VM
For each entry point, the sync script generates a TypeScript file under server/plugins/quickjs/bootstrap/generated/:
- [
pluginBootstrap.ts](https://github.com/CoreBunch/Instatic/blob/main/server/plugins/quickjs/bootstrap/generated/pluginBootstrap.ts) – ExportsPLUGIN_BOOTSTRAP_SOURCE, a JSON-stringified IIFE containing the full plugin runtime. - [
modulePackBootstrap.ts](https://github.com/CoreBunch/Instatic/blob/main/server/plugins/quickjs/bootstrap/generated/modulePackBootstrap.ts) – ExportsMODULE_PACK_BOOTSTRAP_SOURCE, the equivalent string for the module-pack runtime.
Using JSON.stringify() on the bundled code safely escapes backticks, backslashes, and template literal placeholders like ${}. This ensures the generated TypeScript files are valid and the strings can be directly evaluated without corruption.
Runtime Consumption: Seeding the Sandbox
When the server initializes a QuickJS VM, typically in server/plugins/quickjs/vm.ts, it imports the generated constants and evaluates them inside the fresh context:
import { PLUGIN_BOOTSTRAP_SOURCE } from '@quickjs/bootstrap/generated/pluginBootstrap';
import { createQuickJsVm } from '@quickjs/vm';
const vm = createQuickJsVm();
vm.eval(PLUGIN_BOOTSTRAP_SOURCE); // Injects the entire runtime
This pattern guarantees that the VM receives exactly the code that was type-checked in the TypeScript source, eliminating drift between the source of truth and the executed bootstrap.
Freshness Guarantee: CI Validation
To prevent stale bootstrap code from shipping, Instatic includes an architectural test in src/__tests__/architecture/plugin-bootstrap-fresh.test.ts. This test imports buildBootstrapArtifacts from the sync script, generates the expected strings in memory, and compares them against the committed files in server/plugins/quickjs/bootstrap/generated/.
If any discrepancy is detected, the test fails with a message instructing developers to run:
bun run bootstrap:sync
This ensures that every pull request contains bootstrap artifacts that match the current TypeScript source.
Developer Workflow
After modifying any file under server/plugins/quickjs/bootstrap/src/, regenerate the artifacts:
bun run bootstrap:sync
Continuous integration automatically runs the freshness test, blocking merges where the generated files are out of sync.
Summary
- QuickJS-VM bootstrap sync from TypeScript source solves the problem of injecting complex runtimes into a module-less JavaScript engine.
- The pipeline bundles
pluginRuntime.tsandmodulePackRuntime.tsinto IIFE strings usingBun.buildwith browser targeting. - Generated artifacts in
server/plugins/quickjs/bootstrap/generated/export these strings asPLUGIN_BOOTSTRAP_SOURCEandMODULE_PACK_BOOTSTRAP_SOURCE. - The VM initialization code evaluates these constants to establish the sandbox environment.
- A dedicated test enforces freshness, ensuring TypeScript changes are always reflected in the bootstrap before deployment.
Frequently Asked Questions
How does Instatic handle module loading in QuickJS?
QuickJS does not provide a module loader, so Instatic bundles the entire runtime—including APIs and polyfills—into a single IIFE string. This string is generated from TypeScript source and injected into the VM via vm.eval() before any plugin code runs.
Why are the bootstrap artifacts stored as TypeScript files with exported strings?
Storing the bundled code as exported string constants (generated via JSON.stringify) keeps the artifacts type-safe and importable. It prevents syntax errors from unescaped characters like backticks or backslashes, and allows the bundler to tree-shake the bootstrap code effectively when the server starts.
What happens if I forget to run the sync script after editing the bootstrap source?
The CI pipeline runs src/__tests__/architecture/plugin-bootstrap-fresh.test.ts, which compares the in-memory build of the current source against the committed generated files. If they differ, the build fails with instructions to run bun run bootstrap:sync, preventing stale code from reaching production.
Can I use a different bundler instead of Bun for the bootstrap sync?
The current implementation relies on Bun.build specifically for its speed and deterministic output suitable for QuickJS. While other bundlers could theoretically produce compatible IIFE output, the sync script and freshness test are tightly coupled to Bun's behavior and would require modification to support alternatives.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →