Skip to main content

The Compiler

Overview​

The OpenCore Compiler is the technical core of the OpenCore CLI.
It is not just a transpiler or a bundler: it is a monorepo-aware build orchestrator designed specifically for FiveM and similar GTA runtimes.

Its job is to:

  • Understand what each environment can and cannot do
  • Compile server, client, and UI (NUI) code correctly
  • Coordinate multiple resources in parallel
  • Produce drop-in ready artifacts for FiveM

All of this is done with performance, safety, and predictability as first-class goals βš™οΈ


The Compiler as a Monorepo Orchestrator πŸ§ β€‹

An OpenCore project is effectively a monorepo of runtime units:


workspace/
β”œβ”€ core/
β”‚ β”œβ”€ server/
β”‚ β”œβ”€ client/
β”‚ └─ views/
β”œβ”€ resources/
β”‚ β”œβ”€ inventory/
β”‚ β”‚ β”œβ”€ server/
β”‚ β”‚ β”œβ”€ client/
β”‚ β”‚ └─ views/
β”‚ β”œβ”€ jobs/
β”‚ └─ chat/
└─ shared/

The compiler:

  • Discovers all resources automatically
  • Detects entrypoints per environment
  • Builds each unit independently
  • Runs them in parallel when possible
  • Resolves cross-resource framework contracts (CORE ↔ RESOURCE)

Think of it less as β€œtsc for FiveM” and more as:

A coordinator that understands the topology of your server


FiveM Runtime Environments​

FiveM runs JavaScript in three fundamentally different environments.
The compiler enforces hard boundaries between them.

Runtime Matrix​

EnvironmentTargetPurposeWhat you can useWhat will break
ServerNode.jsBackend logicNode APIs, DBs, filesystemDOM, Web APIs, GTA natives
ClientNeutral JSGameplay logicGTA natives, FiveM eventsNode APIs, browser APIs
Views (NUI)BrowserUI / HUDDOM, fetch, UI frameworksNode APIs, natives

Server Environment (Node.js)​

The server runs on FiveM’s Node runtime.

  • Default: Node 16
  • Optional: Node 22 (via fxmanifest.lua)

Intended responsibilities​

  • Authentication & persistence
  • Command handling
  • Business logic
  • External APIs
  • Background jobs

Examples​

βœ… Allowed

import fs from 'fs'
import crypto from 'crypto'
import pg from 'pg'

❌ Forbidden

window
document
GetEntityCoords(...)

The compiler:

  • Targets Node explicitly
  • Keeps node_modules
  • Preserves Node globals

Client Environment (Neutral JS / V8)​

Client code runs inside the GTA V client, not Node, not a browser.

This environment is intentionally minimal.

Intended responsibilities​

  • Player input
  • Game state
  • Entity interaction
  • Natives and events

Examples​

βœ… Allowed

onNet('event', ...)
GetEntityCoords(PlayerPedId())
Math.random()

❌ Forbidden

fs
process
fetch
window
require('some-lib')

The compiler:

  • Bundles everything into a single file
  • Strips Node & browser globals
  • Fails fast on incompatible imports

This is one of the main reasons a generic bundler is not enough.


Views (NUI / Browser)​

Views run in an embedded Chromium instance.

This is a browser-like environment, but not guaranteed to be modern Chrome.

Intended responsibilities​

  • UI / HUD
  • Menus
  • Web-based interactions
  • Styling & animations

Examples​

βœ… Allowed

fetch('/api')
window.postMessage(...)
React / Vue / Svelte

❌ Forbidden

fs
path
process
GTA natives

The compiler:

  • Detects the UI framework automatically
  • Injects the correct esbuild plugins
  • Builds optimized browser bundles
  • Copies static assets (HTML, CSS, fonts, images)

Automatic Environment Discovery πŸ”β€‹

The compiler does zero-config discovery.

It scans for:

  • server.ts, client.ts, index.ts, main.ts
  • View entrypoints (views/, ui/, nui/)
  • Resource boundaries
  • Binary files (bin/, bin/win32, bin/linux)

Diagram:

Resource
β”œβ”€ server β†’ Node build
β”œβ”€ client β†’ Neutral JS build
└─ views β†’ Browser build

If an environment does not exist, it is simply skipped.


Technology Stack​

The compiler is a hybrid system, each tool doing exactly what it’s best at:

  • Go β†’ orchestration, parallelism, filesystem, process control
  • SWC (Rust) β†’ TypeScript, decorators, metadata reflection
  • esbuild β†’ ultra-fast bundling and linking
  • Custom plugins β†’ FiveM-specific constraints

This separation is deliberate:

  • Go handles scale (Esbuild and CLI)
  • Rust handles syntax & speed (SWC)
  • JS tooling handles ecosystem compatibility (embedded js)

Parallel Build Model βš‘β€‹

Traditional builds are sequential.

OpenCore is not.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Resource A │──┐
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€ parallel workers ⚑
β”‚ Resource B │───
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
β”‚ Resource C β”‚β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Each resource:

  • Is built in isolation
  • Has its own dependency graph
  • Does not block others

Typical results:

  • 8–12 resources β†’ < 1 second build
  • CPU-bound, not IO-bound

Why this Matters​

The compiler guarantees that:

  • Server code cannot accidentally leak into client
  • Client code cannot rely on Node
  • UI code stays browser-safe
  • CORE and RESOURCE builds stay contract-correct
  • Large projects remain maintainable and fast

In short:

The compiler encodes the rules of the FiveM universe so you don’t have to remember them.


Final Mental Model​

CLI
└─ Compiler
β”œβ”€ Discovers project structure
β”œβ”€ Orchestrates monorepo builds
β”œβ”€ Enforces runtime boundaries
β”œβ”€ Runs parallel workers
└─ Emits ready-to-run resources

This is what enables OpenCore to scale from:

  • a single script to
  • a full modular server architecture πŸš€