Building & Deployment#

Get your OneJS app running in standalone builds and WebGL.

How It Works#

When you build your Unity project, the JSRunnerBuildProcessor runs automatically and handles everything:

  1. Locates each JSRunner's app.js.txt bundle and assigns it as a TextAsset
  2. Copies assets/ to StreamingAssets/onejs/assets/ (images, fonts, data files)
  3. Extracts cartridge files to StreamingAssets
Styles (CSS Modules and Tailwind) are embedded in the JavaScript bundle, so they work automatically in builds.

Standalone Builds#

Works out of the box. Build normally from File > Build Settings.

The JavaScript bundle is stored as a TextAsset alongside your scene:

Assets/Scenes/YourScene/
└── App_abc123/
    └── app.js.txt      # TextAsset used in builds

In the Editor, JSRunner loads from the filesystem (enabling hot reload). In builds, it uses this TextAsset.

WebGL Builds#

WebGL works with some differences:

  • JavaScript runs in the browser's V8/SpiderMonkey engine (JIT compiled, not QuickJS)
  • Uses the browser's native requestAnimationFrame
  • Full browser API access
Build normally and deploy to a web server.

Assets in Builds#

Image and data files from your assets/ folder are automatically copied to StreamingAssets/onejs/assets/ during the build. This means <Image src="logo.png" /> and loadImage("logo.png") work identically in Editor and builds.

The destination is flushed before each build, so deleted or renamed files won't linger as stale copies.

See the Asset Loading guide for more details.

Production Checklist#

Minify Your Code#

// esbuild.config.mjs
await esbuild.build({
    minify: true,
    treeShaking: true,
    drop: ["console", "debugger"],
})

Test Before Building#

Run npm run build and verify your app works in the Editor before making a Unity build.

Check Console#

Watch the Unity Console for build processor messages:

[JSRunner] Copied 3 asset file(s) to StreamingAssets for: App
[JSRunner] Build preprocessing complete. Processed 1 runner(s), created 1 asset(s), copied 3 asset file(s) to StreamingAssets.

Platform-Specific Code#

const isWebGL = typeof window !== "undefined"

function App() {
    useEffect(() => {
        if (isWebGL) {
            console.log("Running in browser")
        } else {
            console.log("Running in Unity")
        }
    }, [])
}

Troubleshooting#

"Bundle not found" in Build#

  • Ensure npm run build completed successfully
  • Verify app.js.txt exists in the instance folder
  • Check Unity Console for build processor errors

"Script error" in WebGL#

  • Open browser DevTools for the full error message
  • Check for CORS issues if loading external resources
  • Verify all imports are bundled (not externalized)

Assets Missing in Build#

  • Verify files are in the assets/ folder inside your working directory (~/)
  • Check the build log for "Copied N asset file(s) to StreamingAssets"
  • Ensure the JSRunner is enabled and its GameObject is active

Size Optimization#

Analyze your bundle:

npx esbuild-visualizer --open

Common optimizations:

  • Import only what you need from libraries
  • Remove unused exports with tree shaking
  • Use drop: ["console"] in production builds