Data Nexus

Infrastructure · We run it ourselves

Vite

Vite is a development server and build tool: it serves source files as native ES modules while developing, and bundles them with Rollup for production.

Data Nexus builds this site on Next.js 16 and builds PakiBus, a WebGL game with a post-processing pipeline, on Vite. The split is not preference: a framework earns its weight when the product is documents at URLs that must be rendered, cached and crawled, and earns nothing when the product is a single canvas holding sixty frames a second. Vite is what is left once the router, the server and the HTML pipeline are removed and only the module graph remains.

vite.dev

01/Why this one

  1. 01

    A framework is a bet about the unit of work. Next.js bets on the route: file-system routing, per-URL cache semantics, server components, streamed HTML, an image pipeline. A WebGL game has one document, one canvas and one main loop — there is no second URL for a router to resolve and no HTML for a server to stream. Every one of those subsystems still has to be configured, upgraded and worked around, and none of them has anything to bill against.


  2. 02

    In development Vite does not bundle at all. Source files are served as native ES modules and transformed on request, so editing one shader or one post-processing pass invalidates that module and its importers rather than a route tree. This matters more for a game than for a page: tuning a bloom threshold or a camera easing curve is a loop of small numeric edits, and when each edit costs a rebuild the tuning stops happening — the value gets set once and left there.


  3. 03

    three.js and a post-processing chain are large dependencies whose chunking decides time to first frame. Vite exposes Rollup's output.manualChunks and the rest of rollupOptions as ordinary configuration, so the split between engine code, shaders and game logic is a decision the team makes and can measure against a loading screen. Bundler configuration inside a framework belongs to the framework and moves underneath the project between minor versions.


  4. 04

    vite build emits static files and nothing else — no server entry point, no Node runtime to boot. PakiBus ships through wrangler onto Cloudflare Workers, where a Worker serves those assets from the edge and no function cold start sits between a player and the first frame. A framework that can server-render tends to be deployed as though it must, and the cold start and the platform bill follow that assumption rather than the actual need.


  5. 05

    PakiBus carries @vitejs/plugin-basic-ssl and vite-plugin-qrcode, and the reason is correctness rather than convenience. Real WebGL throughput, touch handling and device orientation exist only on a phone, and both pointer lock and DeviceOrientationEvent.requestPermission require a secure context, which a phone pointed at a plain http LAN address does not have. The SSL plugin gives the dev server a self-signed certificate and the QR plugin prints the LAN URL in the terminal as a code to scan, which turns testing on hardware into something that happens every session — the only way frame-rate regressions are caught while they are still cheap to fix.


  6. 06

    Vitest reads the same Vite configuration: the same TypeScript transform, the same path aliases, the same environment replacement. The arithmetic that decides collision, spawn tables and scoring is therefore tested through the pipeline it ships through, and there is no second build configuration to drift out of step — drift between test config and build config is the usual reason a suite passes on code that fails in a browser.


  7. 07

    lil-gui and stats.js are instruments, a parameter panel and a frame monitor, and neither may reach a player. Vite statically replaces import.meta.env.DEV during the build, so the branch that constructs them becomes dead code that Rollup removes, and the check is grepping dist for the string lil-gui. The instrument stays in the source where it is useful instead of being deleted by hand before every release, which is how frame monitors quietly disappear from projects.

02/What you can check

An entry that cannot point at something you can open, run or read does not compile. That is a property of the type, not a promise in a paragraph.

In our code
pakibus/package.json — three, postprocessing, lil-gui and stats.js built and tested by vite and vitest, deployed with wrangler to Cloudflare Workers, with @vitejs/plugin-basic-ssl and vite-plugin-qrcode for HTTPS testing on a physical phone.

On this site
The build identifier of the page being read. This site is Next.js 16, not Vite — the two tools are chosen per artefact, and the artefact here is documents at URLs.Open it

Run it yourself
npm create vite@latest vite-shape-check -- --template vanilla-ts && cd vite-shape-check && npm install && npm run build → A dist/ directory holding index.html plus hashed .js and .css assets and nothing else: no server entry point and no Node runtime needed to serve the result.

Property of the thing
Vite runs two different module graphs from one configuration: development serves unbundled native ES modules transformed on demand, while vite build produces a Rollup bundle. — Start vite and open the network panel — each source file arrives as its own request and re-requests with a ?t= timestamp on save. Run vite build and read dist/assets — those same sources now appear merged into a small number of hashed chunks.

Property of the thing
Pointer lock and the iOS DeviceOrientationEvent.requestPermission prompt require a secure context, so a phone loading a development server over http on a LAN address cannot use either. — Open http://<lan-ip>:5173 on an iPhone and call DeviceOrientationEvent.requestPermission() in the console — it rejects. Serve the same page over https via @vitejs/plugin-basic-ssl, accept the self-signed certificate, and the permission prompt appears.
03/Where it stops

Invariant

Vite has no router, no data layer, no server rendering and no metadata pipeline, so anything that must exist as documents at URLs — crawled, indexed, and read by clients that do not execute JavaScript — has to be assembled from a router, a head library and a prerender step, and that assembly is consistently worse than the framework it was meant to avoid. There is also a real correctness gap in the tool itself: development serves unbundled native ES modules while production is a Rollup bundle, so a dependency with broken ESM/CJS interop, or code that depends on import order or on a side effect that only fires when a module is fetched separately, can run for weeks in development and fail only at vite build. Every change has to be validated against an actual production build, not against the dev server, and teams that skip that discover it during a release.