diff --git a/CHANGELOG.md b/CHANGELOG.md index a849ef5..f5512e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,247 @@ All notable changes to this project will be documented in this file. +# [2.3.0](https://github.com/NanoForge-dev/CLI/compare/1.6.2...2.3.0) - (2026-09-24) + +> NanoForge v2 changes **how a game is structured**. In v1 a game was one folder split into +> `client/` and `server/`, and the CLI rebuilt its entry files from JSON "save" files. In v2 a +> game is a set of standalone **projects** (client, server, and shared libs). Each project has +> its own typed `nanoforge.config.ts`, and a **workspace** can group them in one monorepo. Entry +> files are normal source code that you own. Nothing regenerates them. +> +> The CLI repository is now a monorepo, and this release is shared by three packages. Each +> library has its own changelog with the details: +> +> - **[`@nanoforge-dev/config` changelog](https://github.com/NanoForge-dev/CLI/blob/main/libs/config/CHANGELOG.md)**: +> the new `nanoforge.config.ts` format, its four types, defaults, validation, and the +> field-by-field migration from `nanoforge.config.json`. +> - **[`@nanoforge-dev/schematics` changelog](https://github.com/NanoForge-dev/CLI/blob/main/libs/schematics/CHANGELOG.md)**: +> the generated game in v1 vs v2, the new `workspace` / `project` schematics, the engine v2 +> entry file, the demo game and dependency versions. +> +> This section covers what changed in the `nf` CLI itself. + +## Why 2.3.0 (and not 2.0.0) + +The CLI, `@nanoforge-dev/config` and `@nanoforge-dev/schematics` now share **one version +number** and are released together. That shared version must be higher than the latest +published version of every package. Schematics was already at **2.2.1** (last release from its +old repository), so all three packages are **aligned to the schematics version** and released +as **2.3.0**. The CLI goes from 1.6.2 straight to 2.3.0. There are no CLI 2.0.0, 2.1.x or 2.2.x +releases. + +## Game architecture in short + +| Concern | v1 | v2 | +| ---------------- | --------------------------------------------- | ----------------------------------------------------------------------- | +| Unit of the game | One app with a `client` and a `server` part | Independent `client` / `server` projects (plus libs), grouped by a workspace | +| Config | One `nanoforge.config.json` | One `nanoforge.config.ts` / `.js` per project, lib and workspace | +| Entry file | Regenerated from `.nanoforge/*.save.json` | `src/main.ts`, scaffolded once, then yours | +| Output / assets | `.nanoforge/`, `/static` | `dist/`, `assets/` inside each project | +| Several apps | Not possible | Every project matched by the workspace's `packages` is built and started | + +`nf new` creates either a single `client` project (single-player) or a workspace with +`apps/client` and `apps/server` (multiplayer). The schematics changelog has the full generated +trees. + +## How the CLI reads configs + +The CLI no longer ships its own JSON config loader (`class-validator` defaults, `-c` file name). +It uses `@nanoforge-dev/config` to load the config in the command's directory +(`nanoforge.config.ts`, or `.js` if there's no `.ts`). If neither file exists, the command +fails with `ConfigNotFoundError`. + +On top of that, the CLI resolves the workspace (`parseWorkspaceConfig`, `resolveProjects`): + +- **Root is `client` / `server`:** that project is the only target. +- **Root is `workspace`:** each `packages` glob is expanded from the root: + - a matched directory without a config is skipped + - a glob that matches nothing logs a warning + - a nested `workspace` throws +- **Root is `lib`:** error. A lib can't be an entry point. + +The result is a list of `{ directory, config }` for every client and server project. Libs are +left out. `build` and `start` loop over this list, and `create` uses it to find its target. + +## Code is no longer generated from save files + +In v1, `main.ts` was build output: the CLI regenerated it from `.nanoforge/.save.json` +with `nf generate` or `nf dev --generate`. In v2 you write `main.ts` yourself, so the CLI +drops everything that supported regeneration (#217): + +- the `generate` command, its action, messages, docs page and e2e suite +- the `--generate` option of `nf dev` +- the `initFunctions` input of `nf new` + +`build --editor` now builds the project's `editor.entryFile`. It defaults to the same +`src/main.ts`, and nothing editor-specific is added to it any more. In v1, a separate +generated entry added `Graphics2DEditorLibrary`. + +## Command changes + +### `nf new` (#218) + +- The "server?" question now means **multiplayer**, and it decides the architecture: + - **No:** a single `client` project is generated directly in the target directory. + - **Yes:** a `workspace` is generated, plus `apps/client` (`hasServer: true`) and + `apps/server`. Package names become `-client` / `-server`. +- It calls the new `workspace` and `project` schematics instead of the old chain + (`application` → `configuration` → `part-base` → `part-main` → `docker`). +- It forwards `strict`, `packageManager`, `docker` and `editor` to each project. + +### `nf build` (#219) + +- It builds **every client/server project** found in the workspace, instead of looking at + `client.enable` / `server.enable`. +- Each target builds, copies assets, resets its output and watches files **inside its own + project directory**. +- If there is more than one project, logs show the project path, e.g. `Client (apps/client)`. +- `--client-entry`, `--client-static-dir`, `--client-out-dir` and their `--server-*` + equivalents still work. They now override `entryFile`, `dir.assets` and `out.dir` of each + project of that type. +- If no assets directory is set, the asset copy step is skipped. + +### `nf start` (#220, #224) + +- It starts **every server project, then every client project**. If it finds no project, it + fails with a hint to check `packages` or run `nf new`. +- Each client uses its own `port` and its own `tls` config. `--port`, `--cert` and `--key` + still override them. +- `--watch-server-dir` is passed to the client loader only when there is **exactly one** + server project. +- `--client-dir` / `--server-dir` now mean **output** directories. They override `out.dir`. +- Wording changed from SSL to **TLS** in flags, errors and docs. Errors now point to + `tls.cert` / `tls.key` in `nanoforge.config.ts`. +- The package manager is detected **once**, from the directory the command runs in (the + workspace root), not once per loader (#224). + +### `nf create` (#222) + +- It reads the project config to find where to put the file (`dir.components` / `dir.systems`) + and which language to use. +- **Client or server is now inferred** from the project's `type`, so `-s, --server` is removed. +- Running it at a **workspace root** is refused. Run it inside a project, or pass + `-d apps/client`. + +### `nf dev` (#217) + +- `--generate` is removed. `dev` now just runs `build --watch` (plus `--editor` when asked) and + `start --watch` side by side. + +### `nf generate` (#217) + +- **Removed.** + +## Breaking changes + +- `nanoforge.config.json` is **no longer read**. Use one `nanoforge.config.ts` / `.js` per + project. The key mapping is in the + [config changelog](https://github.com/NanoForge-dev/CLI/blob/main/libs/config/CHANGELOG.md). +- `nf generate` and `nf dev --generate` are removed. +- `nf create -s/--server` is removed. The side now comes from the project config. +- `-c, --config` is removed from `build`, `start` and `create`. +- `--client-dir` / `--server-dir` on `nf start` now point to **output** directories. +- `nf new` generates the v2 layout and engine v2 code. See the + [schematics changelog](https://github.com/NanoForge-dev/CLI/blob/main/libs/schematics/CHANGELOG.md). +- The CLI now declares `engines.node: "26"`, so **users need Node 26**. + +## Migrating a v1 game + +1. **Choose the shape.** + - Client only: keep a single project at the root. + - Client + server: create a workspace root with `packages: ["apps/*"]`, then move + `client/` to `apps/client/src/` and `server/` to `apps/server/src/`. +2. **Replace `nanoforge.config.json`** with one `nanoforge.config.ts` per project. The + field-by-field table is in the + [config changelog](https://github.com/NanoForge-dev/CLI/blob/main/libs/config/CHANGELOG.md). +3. **Make `main.ts` yours.** Copy the last generated `client/main.ts` / `server/main.ts` to + `src/main.ts`. Then remove `.nanoforge/*.save.json` and `.nanoforge/editor/`. +4. **Inline init hooks.** Move the contents of `init/before-*.ts` / `after-*.ts` into `main.ts` + around `app.init()` / `app.run()`. +5. **Update engine imports.** For example `@nanoforge-dev/ecs-client` → + `@nanoforge-dev/ecs/client`, and `Context` from `@nanoforge-dev/common` → `nanoforge`. The + [schematics changelog](https://github.com/NanoForge-dev/CLI/blob/main/libs/schematics/CHANGELOG.md) + shows a full v2 entry file. +6. **Split dependencies** into a `package.json` per project, and set up your package manager's + workspace (`pnpm-workspace.yaml` or `"workspaces"`). +7. **Move static files** into `assets/`, or set `dir.assets`. +8. **Update scripts.** Drop `nf generate` and `--generate`. Instead of `nf create --server`, + run `nf create` inside the server project. + +## Known issues + +CLI issues: + +- **Leftover `-c, --config` on `nf dev`.** Its default is still `nanoforge.config.json`, and the + value is never passed on to `build` / `start`. The configuration docs, `dev.mdx` and the README + still mention `-c`. +- **`build` / `start` ignore libs.** `libs` and `lib` configs are discovered but not built or + linked yet. + +Issues in the generated code, which users will hit through `nf new` / `nf create` (details in +the [schematics changelog](https://github.com/NanoForge-dev/CLI/blob/main/libs/schematics/CHANGELOG.md)): + +- The generated workspace scripts run `nf dev -r`, `nf build -r` and `nf start -r`, but no + command defines `-r`. +- `nf create` templates still use v1 imports, so created components and systems don't compile + in a v2 project. +- Generated configs import `nanoforge/config`, and the engine v2 packages aren't published yet. + +## Repository, tooling & CI + +- **Monorepo** (#197): a pnpm workspace (`.`, `libs/*`) run by **Turborepo** (`turbo.json` + with `build`, `build:dev`, `lint`, `format`, `test:unit` and `test:e2e`, remote cache on). + New root scripts `repo:build`, `repo:lint`, `repo:format`, `repo:test`, `repo:test:unit` and + `repo:test:e2e`. The Husky pre-push hook runs the `repo:*` versions. +- **Packages:** `@nanoforge-dev/cli` (root), `@nanoforge-dev/config` (`libs/config`) and + `@nanoforge-dev/schematics` (`libs/schematics`, previously its own repository). The CLI uses + both libraries through `workspace:*`. All three share one version and release together. +- **Releases** (#225): release branches are now named `releases/cli@`. The Release + workflow publishes config → schematics → cli. The automatic beta release on every merged PR + is gone. Alpha releases of a single package are still triggered by hand. CONTRIBUTING explains + the flow. +- **Commit scopes** `cli`, `config` and `schematics` are documented, and the labels and + issue/labeler configs were updated for the new packages. +- **Runtime:** Node **25 → 26** (`.nvmrc`, `engines`), pnpm **11.10 → 12.0**. +- **Build:** tsdown no longer uses `skipNodeModulesBundle`, because its package-name check also + matched the `@lib/*` / `@utils/*` path aliases and left them unresolved in the output. +- **Dependencies:** `@nanoforge-dev/editor` moved from `optionalDependencies` to + `dependencies`. Loaders went to `^1.5.1` (#227). Vitest 5, tsdown 0.23, Angular DevKit 22.1, + dotenv 18 and others were bumped (#230). The pnpm catalog `tests` was renamed to `test`. +- **Docs:** new *Schematics* section. The configuration page was rewritten for the typed + multi-config model. The `generate` page was removed and the command pages renumbered. +- **Tests:** the e2e suites for `new`, `build`, `create`, `install` and `new-config` were + rewritten for the new layout, and `cli-generate` was removed. New unit tests cover the + workspace config parser and the config loader. +- **Contributors** list updated (#229). + +## Commits + +### Bug Fixes + +- **start:** Change path for detecting package manager (#224) ([ddbed0a](https://github.com/NanoForge-dev/CLI/commit/ddbed0a6bd39383f48b2e4fc71ba015e4df856ae)) by @Exeloo +- Remove generate command as it's no longer usefull (#217) ([a07acd7](https://github.com/NanoForge-dev/CLI/commit/a07acd7ee01afd9dd17eb15051c15e24dbb19c84)) by @Exeloo + - **BREAKING CHANGE:** The `generate` command no longer exist + +### Documentation + +- Update links (#212) ([be9f483](https://github.com/NanoForge-dev/CLI/commit/be9f483c76ba841cb9edccfc477fb2b1904c1f5f)) by @Exeloo + +### Features + +- Put network lib in dependencies (#226) ([e2dde26](https://github.com/NanoForge-dev/CLI/commit/e2dde2607736949caf85a057135c23fed8408861)) by @Exeloo +- Add new project and workspace schematics and remove old ones (#216) ([f551392](https://github.com/NanoForge-dev/CLI/commit/f551392a843d592b1efc70cf4613f98f616999b0)) by @Exeloo +- Add config parser (#214) ([cde54ab](https://github.com/NanoForge-dev/CLI/commit/cde54abba3a8b8385e6441bff8a39365dffde90c)) by @Exeloo +- Add schematics (#200) ([330b9be](https://github.com/NanoForge-dev/CLI/commit/330b9bee1084c911aad8291c25aa591f0eb0d340)) by @Exeloo +- Add config lib and monorepo config files (#197) ([197a75c](https://github.com/NanoForge-dev/CLI/commit/197a75c82699f8a90c14be03208bd6313f53886d)) by @Exeloo + +### Refactor + +- **cli:** Change create command to fit the new architecture (#222) ([3afb463](https://github.com/NanoForge-dev/CLI/commit/3afb463c96d7e511e492a6c8cbe82b686d837a08)) by @Exeloo +- **cli:** Change start command to fit the new architecture (#220) ([3acb4a1](https://github.com/NanoForge-dev/CLI/commit/3acb4a1e214426a1f5e953774859eba38ca49ffa)) by @Exeloo +- Change build cmd to new archi (#219) ([6700f71](https://github.com/NanoForge-dev/CLI/commit/6700f71e9d500efea0eb80aaad655623415f489b)) by @Exeloo +- **cli:** Change new cmd to new archi (#218) ([a2e0d1f](https://github.com/NanoForge-dev/CLI/commit/a2e0d1ffe60063d3f5ae22ed78718e7592fe0f72)) by @Exeloo + # [1.6.2](https://github.com/NanoForge-dev/cli/compare/1.6.1...1.6.2) - (2026-07-07) ## Bug Fixes diff --git a/libs/config/CHANGELOG.md b/libs/config/CHANGELOG.md index 6361e43..9260d16 100644 --- a/libs/config/CHANGELOG.md +++ b/libs/config/CHANGELOG.md @@ -1,3 +1,195 @@ # Changelog All notable changes to this project will be documented in this file. + +# [2.3.0](https://github.com/NanoForge-dev/CLI/compare/1.6.2...2.3.0) - (2026-09-24) + +> First release of `@nanoforge-dev/config` from the CLI monorepo (`libs/config`). Earlier 1.x +> versions were published from the NanoForge Engine repository. This package replaces the CLI's +> built-in `nanoforge.config.json` handling, and it's what makes the new NanoForge v2 game +> architecture possible: a game is no longer one app with a `client` and a `server` part, but a +> set of projects, each with its own typed config. + +## Why 2.3.0 + +The CLI, `@nanoforge-dev/config` and `@nanoforge-dev/schematics` now share **one version +number** and are released together. That shared version must be higher than the latest +published version of every package. `@nanoforge-dev/schematics` was already at **2.2.1**, so all +three packages are **aligned to the schematics version** and released as **2.3.0**. Config goes +from 1.4.2 straight to 2.3.0. There are no config 2.0.0, 2.1.x or 2.2.x releases. + +## Why this package exists + +In v1, one `nanoforge.config.json` at the root described the whole game. The CLI deep-merged +it with its own `CONFIG_DEFAULTS` and validated it with `class-transformer` / `class-validator` +decorators. Client and server were two sections of the same file, switched on with +`client.enable` / `server.enable`. + +In v2, a NanoForge game is made of independent **projects** (`client`, `server`), optional +shared **libs**, and an optional **workspace** that groups them in a monorepo. Every one of +them has its **own** `nanoforge.config.ts` (or `.js`). This package defines what those files +look like, how they're loaded and validated, and what their defaults are. The CLI and your +editor both use it. + +``` +my-game/ # multiplayer game (workspace) +├── nanoforge.config.ts # { type: "workspace", packages: ["apps/*"] } +└── apps/ + ├── client/nanoforge.config.ts # { type: "client" } + └── server/nanoforge.config.ts # { type: "server" } + +my-game/ # single-player game (standalone project) +└── nanoforge.config.ts # { type: "client" } +``` + +## Config files are now typed modules + +```ts +import { defineConfig } from "@nanoforge-dev/config"; + +export default defineConfig({ + type: "client", + entryFile: "src/main.ts", + libs: ["../../libs/shared"], +}); +``` + +- **`defineConfig`** returns its argument unchanged. It exists only so your editor can + type-check and autocomplete the config. +- **Loading:** `parseConfig(path)` imports the file with [`unrun`](https://github.com/unjs/unrun) + (`bundle-require` preset), so TypeScript configs work without a separate build step. The + file's **default export** is the config. +- **Validation:** the default export is checked against a **`zod`** schema: a discriminated + union on `type`, with every field typed. Unknown `type` values or wrong field types are + rejected. +- **Errors:** every failure throws a `ConfigParseError` with a `code`: + + | `code` | When | + | ------------------- | ----------------------------------------------------- | + | `not-found` | The file doesn't exist | + | `load-failed` | `unrun` couldn't import it (syntax error, it throws…) | + | `no-default-export` | The module has no default export | + | `invalid-type` | The default export doesn't match the schema | + +## Four config types + +`NanoforgeConfig` is a discriminated union keyed by `type`: + +| `type` | Role | Fields | +| ----------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `workspace` | Monorepo root | `packages: string[]`: globs for the project/lib directories | +| `client` | Browser-side game project | `entryFile`, `out.{dir,mainFile}`, `dir.{assets,packages,components,systems,scenes}`, `editor.entryFile`, `language`, `libs`, `port`, `tls` | +| `server` | Server-side game project | Same as `client`, without `port` and `tls` | +| `lib` | Shared code used by clients and servers | `dir.{assets,shared,components,systems,scenes}` | + +The `client` and `server` types are built from small **mixins**, and each mixin is exported as +its own type: + +| Mixin | Adds | +| ------------------ | ------------------------------------------------------------------------------ | +| `BuildableConfig` | `entryFile`, `out.dir`, `out.mainFile` | +| `SourceableConfig` | `dir.assets`, `dir.packages`, and `dir.components/systems/scenes` (editor only) | +| `EditorConfig` | `editor.entryFile`: the entry used by `--editor` | +| `LanguageConfig` | `language: "ts" \| "js"`: picks the component/system templates | +| `ContainLibConfig` | `libs: string[]`: relative paths to shared libs | +| `TlsConfig` | `tls: { enable?: false } \| { enable: true, cert, key }` (client only) | + +## Defaults and resolution + +`resolveConfig(config)` fills in missing fields with the defaults for the config's `type`. +There's also one helper per type: `resolveClientConfig`, `resolveServerConfig`, +`resolveLibConfig` and `resolveWorkspaceConfig`. The defaults themselves are exported as +`defaultClientConfig`, `defaultServerConfig`, `defaultLibConfig` and `defaultWorkspaceConfig`. + +- Nested objects (`dir`, `out`, `editor`, `tls`) are **deep-merged**. +- Arrays (`packages`, `libs`) are **replaced**, not concatenated. + +| Field (`client` / `server`) | Default | +| --------------------------- | ---------------- | +| `entryFile` | `src/main.ts` | +| `out.dir` | `dist` | +| `out.mainFile` | `main.js` | +| `dir.assets` | `assets` | +| `dir.packages` | `nf_modules` | +| `dir.components` | `src/components` | +| `dir.systems` | `src/systems` | +| `dir.scenes` | `src/scenes` | +| `editor.entryFile` | `src/main.ts` | +| `language` | `ts` | +| `libs` | `[]` | +| `port` (client) | `3000` | +| `tls.enable` (client) | `false` | + +`lib` defaults: `dir.assets = assets`, `dir.shared = shared`, and `components` / `systems` / +`scenes` under `shared/`. `workspace` defaults: `packages = []`. + +## How the CLI uses these configs + +The CLI (`src/lib/config`) builds its **workspace resolution** on top of this package: + +- If the root config is `client` / `server`, that project is the only target. +- If the root config is `workspace`, each `packages` glob is expanded and every matching + directory's config is loaded: + - A directory without a config is skipped. + - A glob that matches nothing only logs a warning. + - A nested `workspace` throws. +- If the root config is `lib`, it's rejected: a lib can't be an entry point. + +`build`, `start` and `create` all go through this resolution. That's how one `nf build` or +`nf start` now handles every client and server project in a game. + +## Migrating from `nanoforge.config.json` (v1) + +| v1 (`nanoforge.config.json`) | v2 (`nanoforge.config.ts`) | +| ----------------------------------------------- | ------------------------------------------------------------ | +| `name` | **Removed.** Use the project's `package.json` name | +| `language` | `language`, now **per project** | +| `initFunctions` | **Removed** | +| `client.enable` / `server.enable` | **Removed.** A project of that `type` exists or it doesn't | +| `client.port` | `port` on the `client` config | +| `.outDir` (`.nanoforge/`) | `out.dir` (`dist`) + `out.mainFile` | +| `.build.entry` (`/main.ts`) | `entryFile` (`src/main.ts`) | +| `.build.staticDir` (`/static`) | `dir.assets` (`assets`) | +| `.editor.entry` (`.nanoforge/editor/…`) | `editor.entryFile` (`src/main.ts`) | +| `.editor.save` (`.nanoforge/*.save.json`) | **Removed.** Entry files aren't generated from saves anymore | +| `.dirs.components` / `.dirs.systems` | `dir.components` / `dir.systems` | +| `ssl.{enable,cert,key}` (top level) | `tls` on the **client** config | +| — | **New:** `dir.scenes`, `dir.packages`, `libs`, `out.mainFile` | + +To migrate, write one `nanoforge.config.ts` per project with the matching `type`. If your game +has a server, add a `workspace` config at the root that lists them in `packages`. + +## Package + +- Published as dual ESM/CJS with type declarations (`dist/index.{js,cjs,d.ts,d.cts}`). +- Runtime dependencies: `unrun`, `zod`. +- Requires Node 26. +- Released together with `@nanoforge-dev/cli` and `@nanoforge-dev/schematics`, which all + share one version. + +## Known issues + +- Generated projects import `defineConfig` from **`nanoforge/config`** (the engine + meta-package), but that path isn't published yet. `@nanoforge-dev/config` works today. +- `libs` (on projects) and `lib` configs are parsed and discovered, but the CLI's + `build` / `start` don't use them yet. +- The configuration docs page says client and server "share the exact same fields". Its table + is missing `port`, `tls`, `editor.entryFile` and `language`. + +## Commits + +### Features + +- Add config parser (#214) ([cde54ab](https://github.com/NanoForge-dev/CLI/commit/cde54abba3a8b8385e6441bff8a39365dffde90c)) by @Exeloo +- Add schematics (#200) ([330b9be](https://github.com/NanoForge-dev/CLI/commit/330b9bee1084c911aad8291c25aa591f0eb0d340)) by @Exeloo +- Add config lib and monorepo config files (#197) ([197a75c](https://github.com/NanoForge-dev/CLI/commit/197a75c82699f8a90c14be03208bd6313f53886d)) by @Exeloo + +### Refactor + +- **cli:** Change create command to fit the new architecture (#222) ([3afb463](https://github.com/NanoForge-dev/CLI/commit/3afb463c96d7e511e492a6c8cbe82b686d837a08)) by @Exeloo +- **cli:** Change start command to fit the new architecture (#220) ([3acb4a1](https://github.com/NanoForge-dev/CLI/commit/3acb4a1e214426a1f5e953774859eba38ca49ffa)) by @Exeloo +- Change build cmd to new archi (#219) ([6700f71](https://github.com/NanoForge-dev/CLI/commit/6700f71e9d500efea0eb80aaad655623415f489b)) by @Exeloo + +# Changelog + +All notable changes to this project will be documented in this file. diff --git a/libs/config/package.json b/libs/config/package.json index 66a0346..111d770 100644 --- a/libs/config/package.json +++ b/libs/config/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@nanoforge-dev/config", - "version": "1.4.2", + "version": "2.3.0", "description": "NanoForge CLI - Config", "keywords": [ "nanoforge", diff --git a/libs/schematics/CHANGELOG.md b/libs/schematics/CHANGELOG.md index 911dfd8..5dfd474 100644 --- a/libs/schematics/CHANGELOG.md +++ b/libs/schematics/CHANGELOG.md @@ -2,6 +2,233 @@ All notable changes to this project will be documented in this file. +# [2.3.0](https://github.com/NanoForge-dev/CLI/compare/1.6.2...2.3.0) - (2026-09-24) + +> `@nanoforge-dev/schematics` now lives in the CLI monorepo (`libs/schematics`) and is released +> together with `@nanoforge-dev/cli` and `@nanoforge-dev/config`. In this release the +> collection was rewritten for the NanoForge v2 game architecture. The generated game changed +> shape, and entry files are no longer regenerated from save files. + +## Why 2.3.0 + +`@nanoforge-dev/cli`, `@nanoforge-dev/config` and `@nanoforge-dev/schematics` now share **one +version number** and are released together. The shared version must be higher than the latest +published version of every package. Schematics had the highest number of the three: **2.2.1**, +its last release from the old `NanoForge-dev/schematics` repository. So every package is +aligned on the schematics line, and this release is the next minor version, **2.3.0**. + +For schematics, this is the normal next release after 2.2.1. The other packages jump to catch +up: CLI 1.6.2 → 2.3.0, config 1.4.2 → 2.3.0. From now on, the three packages always have the +same version. + +## The generated game: v1 vs v2 + +### v1: one app, two parts, entry files built from save files + +``` +my-game/ +├── nanoforge.config.json # one config for client + server +├── .nanoforge/ +│ ├── client.save.json # libraries / components / systems / entities +│ ├── server.save.json +│ └── editor//main.ts # generated editor entry +├── client/ +│ ├── main.ts # GENERATED from client.save.json (part-main) +│ ├── init/ # before-/after- init, registry-init and run hooks +│ ├── components/example.component.ts +│ └── systems/example.system.ts +└── server/ # same layout, only with a server +``` + +It took five schematics to build this: `application` → `configuration` → `part-base` → +`part-main` → `docker`. `part-main` read `.nanoforge/.save.json` and wrote `main.ts` +again every time `nf generate` ran. + +### v2: standalone projects, grouped by a workspace + +A single-player game is **one `client` project**: + +``` +my-game/ +├── nanoforge.config.ts # { type: "client" } +├── package.json # nf dev / nf build / nf start +├── tsconfig.json | jsconfig.json +├── assets/ +└── src/ + ├── main.ts # scaffolded once, then yours + ├── components/ position-2d, drawable-circle-2d + └── systems/ draw-2d +``` + +A multiplayer game is a **workspace** plus one project per app: + +``` +my-game/ +├── nanoforge.config.ts # { type: "workspace", packages: ["apps/*"] } +├── package.json # workspace root +├── pnpm-workspace.yaml # pnpm only +├── .env # client ↔ server networking +├── Dockerfile / .dockerignore # optional: one image for every app +└── apps/ + ├── client/ # { type: "client" }: draw-2d + position-sync + └── server/ # { type: "server" }: move-2d +``` + +| Concern | v1 | v2 | +| ------------------ | ----------------------------------------------- | --------------------------------------------------------------- | +| Unit of generation | One app with `client/` and `server/` parts | A `workspace` and independent `project`s (`part: client/server`) | +| Config | One `nanoforge.config.json` | One `nanoforge.config.ts/.js` per workspace and per project | +| Entry file | Regenerated from `.nanoforge/*.save.json` | Scaffolded once, then owned by the developer | +| Lifecycle hooks | `init/*.ts` files (`initFunctions`) | Removed. Write the code in `main.ts` around `init()` / `run()` | +| Dependencies | One `package.json` | One per project, each with only the libraries it needs | +| Docker | `docker` schematic | `docker` option on `workspace` or on a standalone `project` | + +## Collection + +| Schematic | Status | Purpose | +| ----------- | ----------- | ------------------------------------------------------------------------------------------- | +| `workspace` | **New** | Monorepo root: config, `package.json`, TS/JS config, `.env`, `.gitignore`, README, Docker | +| `project` | **New** | A `client` or `server` project: config, `package.json`, `src/main`, demo game, Docker | +| `component` | Kept | A single ECS component with its editor manifest | +| `system` | Kept | A single ECS system with its editor manifest | +| `application`, `configuration`, `part-base`, `part-main`, `docker` | **Removed** | Replaced by `workspace` + `project` | + +With `part-main` gone, the save-file format, the save → `main.ts` code generator, the editor +entry variant (`Graphics2DEditorLibrary`) and the `init/` hook templates are all removed too. + +## `workspace` schematic + +- Options: `name`, `directory` (defaults to `name`), `language`, `strict`, `packageManager`, + `allowBuilds`, `docker`. +- Writes a root `nanoforge.config` with `{ type: "workspace", packages: ["apps/*"] }`, and + workspace wiring for the chosen package manager: `pnpm-workspace.yaml` for pnpm, + `"workspaces": ["apps/*"]` for the others. +- Root `devDependencies`: `@nanoforge-dev/cli`, `nanoforge`, `typescript` (limited to major 6). +- `bun` is always allowed to run its install script, because `@nanoforge-dev/cli` depends on + it. The allow-list goes into `allowBuilds` (pnpm), `allowScripts` (npm) or + `trustedDependencies` (bun). +- `.env` sets the default networking values: + `NANOFORGE_CLIENT_SERVER_{TCP,UDP}_PORT=4444/4445`, `NANOFORGE_CLIENT_SERVER_ADDRESS=127.0.0.1` + and `NANOFORGE_SERVER_LISTENING_{TCP,UDP}_PORT=4444/4445`. +- With `docker`, it writes one multi-stage `Dockerfile` that builds every app, tuned for each + package manager: `pnpm fetch` + offline install, `npm ci`, or a Bun image. Node 26, + port 3000. + +## `project` schematic + +- Options: + - `part` (`client` | `server`, required) + - `name` / `workspaceName`: the package name becomes `-`, or just `` + for a standalone project + - `directory`: the full destination path, with nothing appended + - `workspace`, `hasServer`, `docker`, `strict`, `language`, `packageManager` + - `editor`: for now it only adds an `nf editor` section to the README +- `docker` is ignored inside a workspace, because the workspace's own Dockerfile builds the + project. + +### Generated entry file + +```ts +import { NanoforgeFactory, type ClientRunOptions } from "nanoforge"; +import { EcsLibrary } from "@nanoforge-dev/ecs/client"; +import { Graphics2DLibrary } from "@nanoforge-dev/graphics-2d"; +import { InputLibrary } from "@nanoforge-dev/input"; +import { NetworkClientLibrary } from "@nanoforge-dev/network/client"; + +export const main = async (options: ClientRunOptions): Promise => { + const app = NanoforgeFactory.createClient({ tickRate: 60 }); + + const ecs = new EcsLibrary(); + app.use(ecs); + app.use(new Graphics2DLibrary()); + app.use(new InputLibrary()); + app.use(new NetworkClientLibrary()); + + await app.init(options); + // spawn entities, add systems… + await app.run(); +}; +``` + +- It targets the **engine v2 API**: the `nanoforge` meta-package with `NanoforgeFactory`, + run-option types and `Context`, and libraries added with `app.use(...)`. +- Client/server variants now use **subpath exports**: `@nanoforge-dev/ecs/` and + `@nanoforge-dev/network/`, instead of `@nanoforge-dev/ecs-client` / `ecs-server`. +- `Registry` and the editor manifest types come from `@nanoforge-dev/ecs`. `Context` comes from + `nanoforge`, no longer from `@nanoforge-dev/common`. +- Default libraries: the client gets ECS, Graphics 2D, Input and Network. The server gets ECS + and Network. The v1 default save also included AssetManager and Music. + +### Demo game: the server owns the state + +The v1 placeholder (`ExampleComponent` / `exampleSystem`, which stopped the app after a +countdown) is replaced by a small multiplayer loop: + +| Project | Components | Systems | +| ------- | --------------------------------- | ---------------------------------------------------------------------------------- | +| client | `Position2D`, `DrawableCircle2D` | `draw2D`: draws every drawable at its position | +| client | — | `positionSync` (only with `hasServer`): applies positions received over TCP | +| server | `Position2D` | `move2D`: moves the entity and broadcasts `{x, y}` with `network.tcp.sendToEverybody` | + +Components and systems still export an editor manifest and a default export of their name, +the same as in v1. + +### Dependencies + +- client `devDependencies`: `nanoforge`, `@nanoforge-dev/ecs`, `@nanoforge-dev/graphics-2d`, + `@nanoforge-dev/input`, `@nanoforge-dev/network`. +- server: `@nanoforge-dev/network` is a runtime **`dependency`** (#226). `nanoforge` and + `@nanoforge-dev/ecs` are `devDependencies`. +- **Version lookup at generation time** (`fetchTrustedVersion(s)`): the npm registry is + queried, and only stable versions published **at least 48 hours ago** are picked (the same + idea as pnpm's `minimumReleaseAge`). Lookups time out after 3 s. If a lookup fails, engine + packages fall back to `^2`, the CLI to `latest` and TypeScript to `6.0.3`. + +## Breaking changes + +- The `application`, `configuration`, `part-base`, `part-main` and `docker` schematics are + removed. Use `workspace` + `project`. +- Save files (`.nanoforge/*.save.json`) are no longer generated or read. Entry files are + scaffolded once. +- `init/` hook files and the `initFunctions` behaviour are removed. +- Generated configs are `nanoforge.config.ts` / `.js` (`@nanoforge-dev/config` format), no + longer `nanoforge.config.json`. +- Generated code targets the engine v2 packages. + +## Tests & docs + +- E2E suites for `workspace`, `project`, `component` and `system`, and unit tests for the + registry, naming, formatting and object helpers. +- New docs section *Schematics*: overview, workspace, project, component, system. +- Built with tsdown and part of the Turborepo pipeline. Requires Node 26. + +## Known issues + +- **`component` / `system` templates still use v1 imports:** `@nanoforge-dev/ecs-` and + `@nanoforge-dev/common`. The system template also imports `../components/example.component`, + which v2 projects don't have. Code generated by `nf create` in a v2 project won't compile. +- **The workspace `package.json` scripts run `nf dev -r`, `nf build -r` and `nf start -r`,** + but the CLI has no `-r` option. +- **`project` declares options it ignores:** `libs`, `allowBuilds` (hardcoded to + `workspace ? [] : ["bun"]`) and `initFunctions`, which is left over from v1. +- Generated configs import `defineConfig` from `nanoforge/config`, and the entry file imports + the engine v2 packages. Neither is published yet. + +## Commits + +### Features + +- Put network lib in dependencies (#226) ([e2dde26](https://github.com/NanoForge-dev/CLI/commit/e2dde2607736949caf85a057135c23fed8408861)) by @Exeloo +- Add new project and workspace schematics and remove old ones (#216) ([f551392](https://github.com/NanoForge-dev/CLI/commit/f551392a843d592b1efc70cf4613f98f616999b0)) by @Exeloo +- Add schematics (#200) ([330b9be](https://github.com/NanoForge-dev/CLI/commit/330b9bee1084c911aad8291c25aa591f0eb0d340)) by @Exeloo + +### Refactor + +- **cli:** Change create command to fit the new architecture (#222) ([3afb463](https://github.com/NanoForge-dev/CLI/commit/3afb463c96d7e511e492a6c8cbe82b686d837a08)) by @Exeloo +- **cli:** Change start command to fit the new architecture (#220) ([3acb4a1](https://github.com/NanoForge-dev/CLI/commit/3acb4a1e214426a1f5e953774859eba38ca49ffa)) by @Exeloo +- Change build cmd to new archi (#219) ([6700f71](https://github.com/NanoForge-dev/CLI/commit/6700f71e9d500efea0eb80aaad655623415f489b)) by @Exeloo +- **cli:** Change new cmd to new archi (#218) ([a2e0d1f](https://github.com/NanoForge-dev/CLI/commit/a2e0d1ffe60063d3f5ae22ed78718e7592fe0f72)) by @Exeloo + # [2.2.0](https://github.com/NanoForge-dev/schematics/compare/2.1.4...2.2.0) - (2026-06-30) ## Features diff --git a/libs/schematics/package.json b/libs/schematics/package.json index 4be5c5f..f80f62f 100644 --- a/libs/schematics/package.json +++ b/libs/schematics/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@nanoforge-dev/schematics", - "version": "2.2.0", + "version": "2.3.0", "description": "NanoForge Schematics", "keywords": [ "nanoforge", diff --git a/package.json b/package.json index 82b1552..e650796 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@nanoforge-dev/cli", - "version": "1.6.2", + "version": "2.3.0", "description": "NanoForge CLI", "keywords": [ "nanoforge",