UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

133 lines (103 loc) 4.57 kB
--- name: extends-config description: How bos.config.json extends chains work, deep merge semantics, resolved config lifecycle, env-specific extends, and canonical field ordering. Use when debugging extends inheritance, configuring per-environment parents, understanding what dev writes vs publish writes, or reasoning about config merging. metadata: sources: "src/merge.ts,src/config.ts,src/shared.ts,src/types.ts" --- # extends & Config Merging ## extends Field The `extends` field in `bos.config.json` specifies a parent config to inherit from. Supports two forms: ### String (all environments use same parent) ```json { "extends": "bos://dev.everything.near/everything.dev" } ``` ### Object (per-environment parent) ```json { "extends": { "development": "bos://dev.everything.near/everything.dev", "production": "bos://dev.everything.near/everything.dev", "staging": "bos://staging.everything.near/everything.dev" } } ``` Fallback chain: requested env → `production` → first defined value. ## Deep Merge Semantics Uses `defu` (with `createDefu` for custom merge rules): | Field type | Merge behavior | |-----------|---------------| | Scalars (account, domain, repository) | Child overrides parent; parent inherited when child omits | | `shared.ui.*` dep entries | Deep merged — child overrides specific keys, parent deps preserved | | `plugins` | Deep merged — child overrides per-key, parent plugins preserved unless removed | | `secrets` arrays | Unioned (deduplicated) | | `routes` arrays | Child replaces parent | | `variables` | Deep merged per-key | ### Null Sentinel Removal Set a plugin to `null` to explicitly remove an inherited plugin: ```json { "plugins": { "template": null } } ``` ## Resolved Config: `.bos/bos.resolved-config.json` **Generated by**: `bos dev`, `bos build`, `syncAndGenerateSharedUi()` **Gitignored**: Yes (inside `.bos/`) When `bos dev` or `bos build` runs: 1. The full extends chain is resolved in memory 2. The merged config is written to `.bos/bos.resolved-config.json` 3. **`bos.config.json` is NOT modified** during dev Structure: ```json { "_resolved": { "env": "development", "resolvedAt": "2026-05-11T...", "extendsChain": ["bos://dev.everything.near/everything.dev"] }, "account": "me.near", "domain": "my.dev", "shared": { ... }, "app": { ... }, "plugins": { ... } } ``` ### Build configs read resolved config first All build configs (ui/rsbuild.config.ts, host/rsbuild.config.ts, api/rspack.config.js, plugins/*/rspack.config.js) try `.bos/bos.resolved-config.json` first, falling back to `bos.config.json`. The `_resolved` metadata is stripped before use. ### When bos.config.json IS written | Command | Writes bos.config.json? | Why | |---------|------------------------|-----| | `bos dev` | No | Uses resolved config | | `bos build` | No | Uses resolved config | | `bos publish --deploy` | Yes | Snapshot moment — pins production URLs + versions | | `bos plugin publish` | Yes | Records production URL + integrity | | `bos plugin add/remove` | Yes | Changes project's own plugin list | | `bos sync` | Yes | Merges template updates into local config | ### Remote host mode (bos->catalog) When host is remote, `syncAndGenerateSharedUi()` reads versions from `bos.config.json` and writes them into `package.json` catalog. No resolved config is written — the remote host reads `bos.config.json` directly. ## Canonical Field Ordering `BOS_CONFIG_ORDER` enforces consistent key order: 1. `extends` — always first 2. `account` 3. `domain` 4. `testnet` 5. `staging` 6. `repository` 7. `app` 8. `plugins` 9. `shared` Unknown keys go after known keys. `rebuildOrderedConfig()` is applied before every write. ## API From `src/config.ts`: - `writeResolvedConfig(configDir, config, env, extendsChain?)` — writes `.bos/bos.resolved-config.json` - `loadResolvedConfig(configDir)` — reads resolved config, returns `BosConfig | null` - `resolveBosConfigPath(configDir)` — returns resolved config path if exists, else `bos.config.json` - `readBosConfigForBuild(configDir)` — reads resolved config stripping `_resolved`, falls back to `bos.config.json` From `src/merge.ts`: - `mergeBosConfigWithExtends(parent, child)` — deep merge for extends chain - `mergeBosConfigWithTemplate(local, template)` — merge for sync (local wins) - `resolveExtendsRef(extendsField, env)` — resolve string|object extends for a given env - `rebuildOrderedConfig(config)` — enforce canonical ordering - `BOS_CONFIG_ORDER` — ordered field names