Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 41 additions & 62 deletions docs/docs/client.mdx
Original file line number Diff line number Diff line change
@@ -1,80 +1,59 @@
---
title: Client
description: Bun HTTP server that serves the browser-side of a NanoForge project
title: Client loader
description: The web server that serves the loading page and the client build
---

## Overview
## What it does

`loader-client` is a Bun HTTP server that bridges the browser and the compiled game client. It serves the `loader-website` frontend, exposes the game file manifest, delivers the compiled game assets, and forwards environment variables to the browser. It is the single entry point for everything the player's browser contacts.
The client loader (`@nanoforge-dev/loader-client`) is a Bun web server. [`nf start`](/docs/cli/commands/start)
starts one for each client app, pointed at the app's build folder. It serves:

## Usage
- the [loading page](./website), at `/`;
- the list of game files, at `/manifest`;
- the client's environment variables, at `/env`;
- the game files themselves, at `/game/<path>`.

```bash
nf start
```
It prints `Client started on url http://localhost:3000/` when it is ready.

Or invoke directly after building the loader packages:
## What nf start passes to it

```bash
npx loader-client --dir .nanoforge/client --port 3000
```
| `nf start` option or config field | Client loader option |
| ---------------------------------------------------------- | ------------------------------- |
| the client build folder (`out.dir`) | `-d, --dir <dir>` (required) |
| `--port`, or `port` (default `3000`) | `-p, --port <port>` |
| `--watch` (set by `nf dev`) | `--watch` |
| the server build folder, with `--watch` and one server app | `--watch-server-dir <dir>` |
| `--cert` and `--key`, or `tls` | `--cert <file>`, `--key <file>` |

## Routes
The client loader also has `--watch-port <port>` for the live-reload WebSocket. `nf start` doesn't
set it, so the WebSocket takes a free port.

| Route | Description |
| --------------- | --------------------------------------------------------------------- |
| `GET /` | Serves the `loader-website` HTML application |
| `GET /*` | Serves static assets bundled with `loader-website` |
| `GET /manifest` | Returns the game files (path, SHA-256 hash, size) and version as JSON |
| `GET /env` | Returns `NANOFORGE_*` environment variables (prefix stripped) as JSON |
| `GET /game/*` | Serves compiled game client files from the configured game directory |
## Routes worth knowing when you debug

## Options
Open them in the browser next to the game:

| Option | Type | Default | Description |
| -------------------------- | --------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-p, --port <port>` | `string` | `3000` | Port the HTTP server listens on |
| `-d, --dir <dir>` | `string` | `.nanoforge/client` | <Tooltip tip="The directory produced by nf build for the client part.">Directory of compiled client game files</Tooltip> |
| `--watch` | `boolean` | `false` | Enable file watcher and browser hot-reload |
| `--watch-port <port>` | `string` | auto | <Tooltip tip="When not provided, the OS picks the first available port.">Port for the WebSocket watch server</Tooltip> |
| `--watch-server-dir <dir>` | `string` | — | <Tooltip tip="Useful when client and server are compiled together and you want a single watch trigger.">Also watch a server game directory for changes</Tooltip> |
| `--cert <file>` | `string` | — | TLS certificate file (enables HTTPS) |
| `--key <file>` | `string` | — | TLS private key file (enables HTTPS) |
| Route | Returns |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `/manifest` | JSON: each file of the build with its path, SHA-256 hash and size, a version, and the live-reload WebSocket URL when `--watch` is on. |
| `/env` | JSON: the variables the client gets, without the `NANOFORGE_` prefix, plus `tlsEnabled`. |
| `/game/<path>` | One file of the build, for example `/game/main.js`. |

## Watch mode
`/manifest` lists the build folder each time it is requested, so files added by a rebuild show up
on the next page load. A hash is computed again only when a file's size or modification time
changes.

When `--watch` is enabled, `loader-client` starts a WebSocket server on `--watch-port` (or a random free port) and sets the `watch.url` field in the manifest response. Any file change in the game directory causes the server to broadcast an `update` message. The `loader-website` frontend connects to that WebSocket and reloads the page on receipt.
## Live reload

Pass `--watch-server-dir` to also reload when the server game directory changes — useful when client and server are compiled in one step.
With `--watch`, the client loader watches the build folder and sends `update` on its WebSocket
when a file changes. The loading page then reloads. Changes closer than 100 ms count as one. When
`nf start` passes `--watch-server-dir`, a change in the server build reloads the page too, 100 ms
later, to give the server time to restart.

## HTTPS / TLS
## HTTPS

Pass `--cert` and `--key` to enable HTTPS. The server reads both files with Bun's native TLS support. The `/env` response will include `tlsEnabled: true` so the game can detect the protocol at runtime.
With `--cert` and `--key`, the client loader serves HTTPS, and `/env` returns `tlsEnabled: true`.
You need HTTPS as soon as players open the game on an address other than `localhost`: see
[secure context](./website#secure-context).

HTTPS is required when the browser enforces a secure context — for example when using the Origin Private File System API used by `loader-website` to cache game files.

## Examples

**Start on port 8080:**

```bash
npx loader-client --port 8080
```

**Start with watch mode:**

```bash
npx loader-client --watch --watch-server-dir .nanoforge/server
```

**Start with HTTPS:**

```bash
npx loader-client --cert ./certs/server.crt --key ./certs/server.key
```

**Point to a custom game directory:**

```bash
npx loader-client --dir ./dist/client
```
The live-reload WebSocket stays plain `ws://`, on `localhost`. Live reload works only in a browser
on the machine that runs the loader.
75 changes: 34 additions & 41 deletions docs/docs/overview.mdx
Original file line number Diff line number Diff line change
@@ -1,55 +1,48 @@
---
title: Loader
description: Overview of the @nanoforge-dev/loader packages
description: What runs in the browser and on the server when you run nf start or nf dev
---

## What is the Loader?
## What is the loader?

The NanoForge Loader is the runtime layer that starts a NanoForge project. It is invoked by the [NanoForge CLI](https://github.com/NanoForge-dev/CLI) when you run `nf start`, and handles both sides of a game simultaneously: the **client side** delivered to the browser and the **server side** running in Bun.
The loader is the runtime behind [`nf start`](/docs/cli/commands/start) and
[`nf dev`](/docs/cli/commands/dev). You don't install or run it yourself: the CLI includes it and
starts one loader per app of your project.

The Loader is a monorepo of three packages, each with a distinct responsibility at runtime:
| Part | Runs | Does |
| ------------------------- | ----------------------- | ---------------------------------------------------------------------------------------- |
| [Client loader](./client) | on your machine, in Bun | Serves the loading page and the client build to the browser, and the client's variables. |
| [Loading page](./website) | in the player's browser | Downloads the game files into a browser cache, then starts the client's `main.js`. |
| [Server loader](./server) | on your machine, in Bun | Runs the server build's `main.js` in a child process, and restarts it on change. |

- **`loader-client`** — the Bun HTTP server that serves the browser with the loader UI and the compiled game files.
- **`loader-server`** — the Bun process that runs the compiled server game code in an isolated worker.
- **`loader-website`** — the browser application that displays the loading screen, caches game files locally, and bootstraps the game.
A game without a server has only the client loader and the loading page.

The NanoForge CLI orchestrates all three; as a game developer you never interact with these packages directly.
## Ports

## Installation
| Port | Used by | Set with |
| ---------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| 3000 | the client loader (the page players open) | `nf start --port`, or `port` in the client's `nanoforge.config.ts` |
| a free port, picked at start | the live-reload WebSocket of `nf dev` | nothing: the loading page gets it from the client loader |
| 4444 (TCP), 4445 (UDP) | your game's network, in a project made by `nf new --server` | the `.env` file: see [environment variables](/docs/cli/configuration/environment-variables) |

```bash
npm install -g @nanoforge-dev/cli
```
The server loader opens no port of its own: your server code opens the ones it needs.

The loader packages are dependencies of the CLI and do not need to be installed separately. If you want to invoke the loaders directly outside of the CLI:
## Environment variables

```bash
npm install @nanoforge-dev/loader-client
npm install @nanoforge-dev/loader-server
```
Each loader passes the `NANOFORGE_*` variables that `nf start` gives it to your game, with the
prefix removed: `NANOFORGE_CLIENT_SERVER_ADDRESS` in `.env`
reaches the client game as `SERVER_ADDRESS`. The client's
variables are sent to the browser, so anyone can read them. The rules are on the
[environment variables](/docs/cli/configuration/environment-variables) page.

Then run them with:
## Troubleshooting

```bash
npx loader-client --dir .nanoforge/client
npx loader-server --dir .nanoforge/server
```

## Packages

<CardGroup cols={2}>
<Card title="loader-client" href="./client">
Bun HTTP server that serves the loader website and the compiled client game files. Exposes the
manifest, environment variables, and game assets. Supports HTTPS and hot-reload.
</Card>
<Card title="loader-website" href="./website">
Browser application bundled as static assets. Displays the loading screen, downloads and caches
game files via the browser Origin Private File System, then bootstraps the game.
</Card>
<Card title="loader-server" href="./server">
Bun process that runs the server-side game code in an isolated worker process. Supports
live-reload by restarting the worker on file changes.
</Card>
</CardGroup>

see the [changelog](https://github.com/NanoForge-dev/Loader/blob/main/CHANGELOG.md) for the full release history.
| What you see | Why, and what to do |
| ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Storage issue: The game must be hosted with SSL (HTTPS) to enable local storage and load properly.` | The page is not in a secure context: it was opened over HTTP on an address other than `localhost`. Use `localhost`, or [serve over HTTPS with nf start](/docs/cli/commands/start#https). |
| `Could not find main function` | The client build has no `main.js` exporting `main`. Run `nf build`, and keep the entry file named `main.ts`. |
| The server log shows `No main.js found` | Same, for the server build. |
| `Game file not found : <path>` | A file listed when the page loaded was removed before it was downloaded, usually by a rebuild. Reload the page. |
| The page shows old code after a rebuild | Reload the page. If it persists, clear the site's data in the browser (storage and cache) to empty the loader's cache. |
| The page doesn't reload with `nf dev` | The live-reload WebSocket address is `localhost` on a free port. Live reload works only in a browser on the machine that runs `nf dev`: reload by hand elsewhere. |
| An error message on the loading screen | The loading page shows errors thrown while loading or running the game. Open the browser console for the stack trace. **Back home** reloads the page. |
Loading
Loading