- Category
- Developer Tools
- Rank
- No. 1090Tools index
Previous survey · No. 1080 ·
- Pricing
- Open Source
- Type
- TOOL
- Use case
- Coding
- GitHub
- 628 stars
- Latest release
- v0.3.1
- Date
About
OJ is an experimental Rust-native build tool positioned as a drop-in replacement for Vite when building React apps, aimed at lowering memory use and cold-start time for scenarios that run many builds, such as CI pipelines, coding agents, or multi-tenant hosting. It supports a streaming SSR mode via renderToReadableStream with working Fast Refresh and HMR, and runs Vite/Rollup-style plugins through a persistent Node plugin host.
What it does
OJ is a command-line frontend toolchain written in Rust that stands in for Vite's dev server, production build and preview commands. It compiles TypeScript and JSX natively, bundles production output with Rolldown, the same Rust bundler current Vite uses, and runs the JavaScript work it cannot avoid (CSS tooling, config files, the app's own Vite plugins, server rendering) inside a V8 engine embedded in the binary, so Node does not need to be installed. It reads an existing Vite config, adopts its plugins and aliases, and also runs TanStack Start apps, emitting a Node server or a Cloudflare Worker.
Why it's ranked here
The memory numbers are the case for it. In the project's own benchmark, published with its method, OJ holds 96 to 190 MB from 1,000 to 10,000 components while default Vite dev climbs from 325 MB to 1.1 GB, and it starts cold about 1.7 times faster at the largest size. Production output matches Vite's byte for byte because both use Rolldown. Lovable maintains it, it is MIT licensed, and the test strategy goes well past unit tests. The limit on the verdict: it calls itself experimental, and the numbers come from the authors' runs on one Mac.
What's good
The test suite is organised around failure modes rather than modules: fuzzing over the compiler, env files and cache entries, property tests that re-parse every compiled output, model-based tests for the dependency graph, and mutation testing on the pure crates with each surviving case explained. Request paths are tested against every spelling of directory traversal. Each embedded JavaScript job runs under a heap cap and a wall-clock deadline, so a runaway job fails alone instead of taking the dev server down. The docs are unusually candid, listing where behaviour differs from Vite and which cases are deliberately left unhandled.
Tradeoffs
Vite's own experimental bundled dev mode beats OJ on cold start and page reload at every size in OJ's table: 1.6 seconds against 4.2 cold at 10,000 components, and 0.3 against 2.9 on reload. Hot module replacement, the in-place update after a save, is a tie. Embedding V8 grows the stripped binary from about 30 MB to about 98 MB, and platforms are limited to those prebuilt V8 ships for. Watch-mode builds are not supported yet, the on-disk module cache is opt-in and experimental, and a crashing native addon in a plugin still takes the process down. The changelog is mostly Vite-parity fixes, so compatibility is still moving.
How to use it well
Reach for it where many dev servers or builds run side by side and memory is the bill: CI fleets, coding agents spinning up previews, multi-tenant hosting of React apps. Install it with Cargo or Nix, point it at an existing Vite or TanStack Start app, and compare against your current setup before switching, since plugin and config coverage is broad but still being filled in. For a single developer laptop where fast reloads matter more than memory, Vite's bundled dev mode measured faster. It does not cover frameworks beyond plain Vite-style apps and TanStack Start, and it is not a test runner.
Technical notes+
Cargo.toml declares a 16-crate workspace (compiler, resolver, graph, cache, CSS, server, JS engine, plus forks of deno_napi and deno_runtime published as oj_deno_napi and oj_deno_runtime) on oxc 0.146; the napi fork carries a finalizer-registry patch because upstream's Vec-based deregistration went quadratic under GC when rolldown held hundreds of thousands of references. The release profile is opt-level z with fat LTO and opt-level 3 overrides on hot-path crates, and leaves panic=abort off so the plugin RPC boundary can catch_unwind. crates/oj/src/main.rs exposes dev, build, preview and compile plus hidden js-eval, start-script and engine-job subcommands; per docs/embedded-js-runtime.md the one-shot children get their own process because rolldown's binding retains native memory per build() until exit and napi-rs 3.9-era addons segfault on re-registration, and they self-reap by polling for a ppid change. raise_fd_limit lifts the soft NOFILE limit, binary-searching under a 1<<20 ceiling. crates/oj_resolver/src/lib.rs wraps oxc_resolver with Vite's conditions, dedupe and a require_variant that swaps import for require. crates/oj_server/src/lib.rs is an axum server holding the module graph, persistent cache, fs allow/deny lists and HMR gate. docs/development/testing.md lists five cargo-fuzz targets, proptest suites and cargo-mutants results (95 caught, 6 timed out, 6 equivalent survivors of 108 in oj_env and oj_css).
Observed
- License
- MIT
- Language
- Rust, a 16-crate Cargo workspace
- Install
- cargo install from crates.io, or nix run
- Interface
- CLI with dev, build and preview commands, Vite-compatible flags
- Platforms
- Linux glibc and musl, macOS, Windows MSVC; x64 and arm64
- JavaScript runtime
- Embedded V8 via the Deno runtime; Node not required
- Plugin support
- Vite/Rollup-style plugins, read from the app's Vite config or a plugins file
- Framework support
- React apps and TanStack Start; Svelte 5 components in dev and build
- Testing
- Rust unit, integration and property suites, cargo-fuzz targets, Node end-to-end scripts
- Project status
- Self-described experimental
- Maintainer
- Lovable
Read from README.md, Cargo.toml, LICENSE, crates/oj/src/main.rs, crates/oj_compiler/src/lib.rs, crates/oj_server/src/lib.rs, crates/oj_resolver/src/lib.rs, crates/oj_deno_runtime/lib.rs, docs/embedded-js-runtime.md, docs/development/testing.md, CHANGELOG.md.
Tags
Tech Stack
Comments (0)
No comments yet
Editorially curated, with community endorsements as a secondary signal. Corrections welcome.