From cd10f5ade7d6d7bc6d509aed7417247f1872faa2 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Aug 2026 19:07:52 +0000 Subject: [PATCH 1/5] Align out-layout-preset: inject ADR 0007 out/ defaults. Record light-align decisions and clarify Conventional role outputs in the glossary so unset distPath stops falling back to roleRoot/dist. Co-authored-by: Zane --- docs/monorail/CONTEXT.md | 5 ++- docs/monorail/CONTEXT.zh.md | 5 ++- docs/monorail/out-layout-preset/align.md | 39 ++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 docs/monorail/out-layout-preset/align.md diff --git a/docs/monorail/CONTEXT.md b/docs/monorail/CONTEXT.md index 23268a8..3070569 100644 --- a/docs/monorail/CONTEXT.md +++ b/docs/monorail/CONTEXT.md @@ -47,7 +47,10 @@ The role that serves or produces browser-facing renderer content. Multiple pages The complete Rsbuild configuration for one role, extended with Rselectron-owned Electron behavior for that role. **Role preset** -Rselectron's defaults and invariants for a role. A preset may be overridden where safe, while role identity constraints remain enforced. +Rselectron's defaults and invariants for a role. A preset may be overridden where safe, while role identity constraints remain enforced. Unset `output.distPath` receives the Conventional role outputs layout; other preset values (targets, formats, Node entry naming) are owned by their respective contracts. + +**Conventional role outputs** +The default Role output roots when `output.distPath` is unset: `out/main`, `out/preload`, and `out/renderer`, resolved against the Application root (not against each Role `root`). Explicit `distPath` (string or object with `root`) always wins. **Role module format** The module system used for a Main or Preload source-build output: `cjs` or `esm`. It is derived from Electron capability, the application manifest `"type"`, and the role-level `electron.format`, and is applied through Rsbuild `output.module`. diff --git a/docs/monorail/CONTEXT.zh.md b/docs/monorail/CONTEXT.zh.md index 238f9b2..f142c9c 100644 --- a/docs/monorail/CONTEXT.zh.md +++ b/docs/monorail/CONTEXT.zh.md @@ -49,7 +49,10 @@ Rselectron 有意排除的基线能力。Vite 插件、字节码编译,以及 某一角色的完整 Rsbuild 配置,并扩展该角色由 Rselectron 拥有的 Electron 行为。 **Role preset(角色预设)** -Rselectron 对某一角色的默认值与不变量。在安全处可覆盖预设,但角色身份约束仍被强制执行。 +Rselectron 对某一角色的默认值与不变量。在安全处可覆盖预设,但角色身份约束仍被强制执行。未设置 `output.distPath` 时采用 Conventional role outputs 布局;其余预设(目标、格式、Node 入口命名)由各自契约拥有。 + +**Conventional role outputs(约定角色产物目录)** +未设置 `output.distPath` 时的默认角色输出根:`out/main`、`out/preload`、`out/renderer`,相对 Application root 解析(不相对各 Role 的 `root`)。显式 `distPath`(字符串或带 `root` 的对象)始终优先。 **Role module format(角色模块格式)** Main 或 Preload 源码构建产物使用的模块系统:`cjs` 或 `esm`。由 Electron 能力、应用清单 `"type"` 与角色级 `electron.format` 推导,并通过 Rsbuild `output.module` 生效。 diff --git a/docs/monorail/out-layout-preset/align.md b/docs/monorail/out-layout-preset/align.md new file mode 100644 index 0000000..3f5dfcd --- /dev/null +++ b/docs/monorail/out-layout-preset/align.md @@ -0,0 +1,39 @@ +# Align: out-layout-preset + +## Intent + +Close the gap between the accepted Electron role build contract (default outputs under `out/`) and today’s unset fallback (`/dist`). Conventional apps should stop hand-writing `output.distPath` (and absolute path workarounds) just to get the layout ADR 0007 already promises. Make the Role preset inject that layout when unset, keep explicit overrides intact, and align docs/examples with the real default. + +## Decisions settled + +- **Gap class:** implementation of an already-accepted convention (ADR 0007 / BUILD-001), not a new packaging or scaffolding product. No new ADR; optionally note in BUILD-001 evidence when landed. +- **When to inject:** for each configured Role, if `output.distPath` is unset **or** `output.distPath` is an object without a usable `root` (and not a string form), inject the conventional root. Any explicit string `distPath` or object with `root` wins and keeps today’s resolution rules (relative paths resolve against the Role `root`, else application root). +- **Injected path:** Application-root-relative convention `out/main`, `out/preload`, `out/renderer`. During normalization, set `output.distPath.root` to `resolve(appRoot, 'out', role)` (absolute) so custom Role `root` values (e.g. `./src/main`) still emit beside the app root, not under `src/main/out/...` or `src/main/dist`. +- **Planned entry / diagnostics:** `plannedMainEntry`, `roleDistRoot`, entry↔manifest mismatch checks, and renderer-only reuse validation must observe the injected path the same way they observe an explicit one. +- **Other Node defaults unchanged here:** Main/Preload `filenameHash: false` and entry filename policy remain as already shipped (ADR 0007 / 0009). This effort does not re-litigate them. +- **Docs / examples:** Getting started and learning examples must describe `out/` as the unset default (today’s copy still teaches `root/dist` + optional `distPath`). Example `package.json#main` (or documented entry) tracks the planned Main output under the entry filename policy. Fixtures that already set `out/` may stay explicit or drop the redundant `distPath` once the preset exists. +- **Migration posture:** no production-user migration window claimed; changing the unset default from `/dist` → `out/` is acceptable for beta. Document the change in migration / getting-started so early adopters who relied on `root/dist` without setting `distPath` know to set an explicit `distPath` or point `main` at `out/...`. +- **Acceptance seam:** unit/normalize asserts that unset configs receive `out/` under `appRoot`; explicit `distPath` is preserved; at least one build or example path proves outputs land under `out/` without hand-written `distPath`. Prefer extending existing `electron-runtime` / build / docs-site seams. + +## Deferred + +- Renderer default `output.assetPrefix: './'` for `build` / `preview` (file-protocol relative assets) when unset — related Electron-preset ergonomics, not required to close the `out/` layout gap +- Zero-config Role discovery with no `rselectron.config.*` (remaining BUILD-001 partial) +- Helpers that generate BrowserWindow `loadURL` / `loadFile` / preload path resolution boilerplate +- Packaging `extraResources` / asarUnpack compose guides (separate compose-docs effort) +- Changing resolution rules for **explicit** relative `distPath` strings + +## Out of scope + +- Default-enabling Main/Preload `watch` in `dev` (ADR 0003) +- Embedding electron-builder / Forge or a project scaffolder (ADR 0001) +- Implicit cross-Role `shared` config block (ADR 0002; keep `mergeRselectronConfig`) +- Format / externalizeDeps / ESM-native behaviour (owned by `role-esm-native` / `cjs-import-only-diag`) +- Electron support snapshot / peer range changes (ADR 0005) + +## Domain pointers + +- Glossary: `docs/monorail/CONTEXT.md` — Role preset; Conventional role outputs (added/clarified by this align); Application root; Electron entry +- ADR: `docs/monorail/adr/0007-electron-role-build-contract.md` (default outputs `out/`; Role presets) +- Matrix: `docs/monorail/compatibility-matrix.md` — BUILD-001 (Partial: convention documented, preset injection / zero-config discovery not complete) +- Consumer pain context: migration apps hand-writing absolute `distPath` while ADR already names `out/` From 6cad572e075bb8e19e343032b3eb036503357f4d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Aug 2026 19:10:36 +0000 Subject: [PATCH 2/5] Spec out-layout-preset: inject Conventional role outputs. Add spec.md and issues for normalizeRuntime distPath preset injection plus docs/examples alignment. Co-authored-by: Zane --- .../issues/02-docs-and-examples.md | 16 +++++ docs/monorail/out-layout-preset/spec.md | 58 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 docs/monorail/out-layout-preset/issues/02-docs-and-examples.md create mode 100644 docs/monorail/out-layout-preset/spec.md diff --git a/docs/monorail/out-layout-preset/issues/02-docs-and-examples.md b/docs/monorail/out-layout-preset/issues/02-docs-and-examples.md new file mode 100644 index 0000000..42785eb --- /dev/null +++ b/docs/monorail/out-layout-preset/issues/02-docs-and-examples.md @@ -0,0 +1,16 @@ +# 02 — Docs and examples for out/ default + +Status: open +Blocked by: 01 + +## What to build + +Update getting-started (en + zh) so the Electron entry section teaches `out/` as the unset default (not `src/main/dist`). Add a short migration / getting-started note that early beta unset `root/dist` behaviour is replaced. Point learning examples’ `package.json#main` at the planned Main output under Conventional role outputs + entry filename policy. Optionally note BUILD-001 matrix evidence for preset injection (zero-config discovery still deferred). + +## Acceptance criteria + +- [ ] Getting-started en + zh describe `out/main` (or `out/`) as the default unset layout and no longer present `src/main/dist` as that default +- [ ] Migration (en + zh) or getting-started mentions the beta default change / how to keep an explicit `distPath: 'dist'` layout +- [ ] `examples/vanilla` and `examples/react` declare `package.json#main` aligned with planned Main output under `out/main` +- [ ] `tests/docs/docs-site.test.ts` asserts the getting-started default-layout copy anchors +- [ ] BUILD-001 evidence updated to credit preset injection while leaving zero-config-without-config as deferred/Partial if still accurate diff --git a/docs/monorail/out-layout-preset/spec.md b/docs/monorail/out-layout-preset/spec.md new file mode 100644 index 0000000..bf7f71b --- /dev/null +++ b/docs/monorail/out-layout-preset/spec.md @@ -0,0 +1,58 @@ +# Spec: out-layout-preset + +## Problem Statement + +ADR 0007 and BUILD-001 document Conventional role outputs under `out/main`, `out/preload`, and `out/renderer`. When `output.distPath` is unset, normalization nevertheless falls through to Rsbuild’s `/dist` (see `plannedMainEntry` / `roleDistRoot` fallbacks of `'dist'`). Authors and learning docs either hand-write `distPath` (often absolute) or teach `src/main/dist/...` as the default—contradicting the accepted contract and recreating the migration boilerplate this effort exists to remove. + +## Solution + +Inject Conventional role outputs in Role preset normalization: + +1. **Preset injection** — for each configured Role, when `output.distPath` is unset or is an object without a usable `root`, set `output.distPath.root` to `resolve(appRoot, 'out', role)`. Explicit string `distPath` or object with `root` always wins and keeps today’s relative-resolution rules (relative → Role `root`, else application root). +2. **Downstream consistency** — `plannedMainEntry`, `roleDistRoot`, entry↔manifest mismatch, and renderer-only reuse continue to read the normalized Role config (already post-`normalizeRuntime`); no change to mismatch severity. +3. **Docs / examples** — getting-started (en + zh) and migration note the unset default as `out/`; learning examples’ `package.json#main` (and any documented entry) track the planned Main output under the entry filename policy. Optional: drop redundant explicit `distPath` from fixtures that only restate `out/`. + +No new ADR. Glossary already defines Conventional role outputs / Role preset. + +## User Stories + +1. As an app author with a minimal three-role config and no `distPath`, I want outputs under `out/` at the application root, so I do not hand-write absolute paths. +2. As an app author who sets an explicit `distPath`, I want that layout preserved unchanged, so custom monorepo / packaging layouts keep working. +3. As an app author reading getting-started, I want `package.json#main` examples to match the real unset default, so entry mismatch diagnostics do not surprise me. +4. As a maintainer, I want normalize/unit and docs-site asserts for the preset, so BUILD-001’s preset-injection gap does not regress. + +## Implementation Decisions + +- **Contract authority:** ADR 0007; glossary Conventional role outputs, Role preset, Application root, Electron entry. Matrix BUILD-001 (advance evidence for preset injection; zero-config discovery remains deferred). +- **Injection site:** `normalizeRuntime` (same place other Role presets apply). Helper may live beside runtime/entry for testability (`applyConventionalDistPath` or equivalent). +- **Usable `root`:** treat as present when `distPath` is a non-empty string, or when `distPath` is an object whose `root` is a non-empty string. Empty string / missing `root` → inject. +- **Absolute injected root:** always `resolve(appRoot, 'out', role)` so Role `root` like `./src/main` does not nest outputs under the source tree. +- **Do not change:** Main/Preload `filenameHash` / entry filename policy; watch defaults; packaging; renderer `assetPrefix`; resolution rules for explicit relative `distPath`. +- **Docs:** dual-write getting-started Electron entry section; short migration / getting-started note that early beta `root/dist` unset behaviour is replaced—set explicit `distPath: 'dist'` (or role-relative) to keep the old layout, or point `main` at `out/...`. +- **Examples:** vanilla / react `package.json#main` align with planned Main output after preset + entry filename policy (`type: module` → `.cjs` or `.mjs` per ADR 0009). +- **BUILD-001:** when landed, update matrix evidence to note preset injection for unset `distPath`; leave zero-config-without-config-file as still Partial / deferred. + +## Testing Decisions + +External behaviour over implementation details. Confirmed seams: + +1. **`tests/unit/electron-runtime.test.ts`** — unset three-role fixture: normalized `distPath.root` equals `join(appRoot, 'out', role)` for main/preload/renderer; explicit string and object-with-`root` preserved (including relative-to-role-root semantics where already tested or trivially asserted); object without `root` receives injection while preserving sibling `distPath` fields if any. +2. **Build or example path** — at least one path proves artifacts land under `out/` without hand-written `distPath` (extend an existing build fixture / example assert, or a focused unit that reads normalized config into `plannedMainEntry` and asserts `out/main/...`). +3. **`tests/docs/docs-site.test.ts`** — getting-started (en + zh) mentions `out/main` (or `out/`) as the default layout and does not teach `src/main/dist` as the unset default. + +Prefer extending these seams; do not invent a parallel test stack. + +## Out of Scope + +- Renderer default `assetPrefix: './'` for build/preview +- Zero-config Role discovery without `rselectron.config.*` +- Window `loadURL` / `loadFile` / preload path helpers +- Packaging compose guides +- Changing explicit relative `distPath` resolution +- Default Main/Preload watch; packaging/scaffolding; implicit `shared`; ESM/externals; Electron snapshot + +## Further Notes + +- Align source: `docs/monorail/out-layout-preset/align.md`. +- Today’s getting-started still documents `./src/main/dist/index.js` — that copy is wrong relative to ADR 0007 and must flip with this effort. +- Consumer migration pain: hand-written absolute `distPath` while the ADR already named `out/`. From 883b70e8539987f1d442b927b5b355cc04c99155 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Aug 2026 19:11:53 +0000 Subject: [PATCH 3/5] Inject Conventional role outputs when distPath is unset. normalizeRuntime now presets out/ under the application root; unit tests cover injection and explicit overrides. Co-authored-by: Zane --- .../issues/01-inject-conventional-distpath.md | 19 +++++ .../issues/02-docs-and-examples.md | 2 +- packages/core/src/electron/runtime.ts | 48 +++++++++++- tests/unit/electron-runtime.test.ts | 74 +++++++++++++++++++ 4 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 docs/monorail/out-layout-preset/issues/01-inject-conventional-distpath.md diff --git a/docs/monorail/out-layout-preset/issues/01-inject-conventional-distpath.md b/docs/monorail/out-layout-preset/issues/01-inject-conventional-distpath.md new file mode 100644 index 0000000..b2f8501 --- /dev/null +++ b/docs/monorail/out-layout-preset/issues/01-inject-conventional-distpath.md @@ -0,0 +1,19 @@ +# 01 — Inject conventional out/ distPath + +Status: done +Blocked by: None + +## What to build + +In `normalizeRuntime`, apply Conventional role outputs: when a Role’s `output.distPath` is unset or is an object without a usable `root`, set `output.distPath.root` to `resolve(appRoot, 'out', role)`. Preserve explicit string `distPath` and objects that already set `root`. Keep sibling `distPath` fields when injecting into an object missing `root`. Ensure `plannedMainEntry` / `roleDistRoot` consumers (already post-normalize) observe the injected path. + +## Acceptance criteria + +- [x] Unset three-role `normalizeRuntime` fixture: each Role’s `distPath.root` is `join(appRoot, 'out', role)` (absolute) +- [x] Explicit string `distPath` and object-with-`root` are unchanged; object without `root` receives injection +- [x] `plannedMainEntry` for an unset Main config (after normalize) resolves under `out/main/` with the entry filename policy +- [x] Coverage lives in `tests/unit/electron-runtime.test.ts` (extend existing seam); oxlint/format clean for touched files + +## Comments + +- 2026-08-01: Claimed + implemented. `applyConventionalDistPath` in `normalizeRuntime`; unit tests green. diff --git a/docs/monorail/out-layout-preset/issues/02-docs-and-examples.md b/docs/monorail/out-layout-preset/issues/02-docs-and-examples.md index 42785eb..e24aea9 100644 --- a/docs/monorail/out-layout-preset/issues/02-docs-and-examples.md +++ b/docs/monorail/out-layout-preset/issues/02-docs-and-examples.md @@ -1,6 +1,6 @@ # 02 — Docs and examples for out/ default -Status: open +Status: claimed Blocked by: 01 ## What to build diff --git a/packages/core/src/electron/runtime.ts b/packages/core/src/electron/runtime.ts index a626db5..ed1a9bd 100644 --- a/packages/core/src/electron/runtime.ts +++ b/packages/core/src/electron/runtime.ts @@ -41,6 +41,52 @@ interface ApplicationManifest { type?: string; } +/** + * Conventional role outputs (ADR 0007): unset distPath → out/ under appRoot. + */ +export function applyConventionalDistPath( + appRoot: string, + role: Role, + config: RoleConfig, +): RoleConfig { + const dist = config.output?.distPath; + if (typeof dist === 'string') { + if (dist.length > 0) { + return config; + } + } else if ( + typeof dist === 'object' && + dist !== null && + !Array.isArray(dist) && + typeof dist.root === 'string' && + dist.root.length > 0 + ) { + return config; + } + + const root = resolve(appRoot, 'out', role); + if (typeof dist === 'object' && dist !== null && !Array.isArray(dist)) { + return { + ...config, + output: { + ...config.output, + distPath: { + ...dist, + root, + }, + }, + }; + } + + return { + ...config, + output: { + ...config.output, + distPath: { root }, + }, + }; +} + function readManifest( appRoot: string, packageJson?: string, @@ -438,7 +484,7 @@ export function normalizeRuntime(options: { const pendingWarnings: Diagnostic[] = []; for (const [role, config] of roles) { - let next = config; + let next = applyConventionalDistPath(options.appRoot, role, config); if (role === 'main' || role === 'preload') { const format = deriveFormat(next, manifest, electron); diff --git a/tests/unit/electron-runtime.test.ts b/tests/unit/electron-runtime.test.ts index 184f73e..b03aa9e 100644 --- a/tests/unit/electron-runtime.test.ts +++ b/tests/unit/electron-runtime.test.ts @@ -8,6 +8,7 @@ import { resolveProjectElectron, } from '../../packages/rselectron/src/index.ts'; import { electronChromeBrowserslist } from '../../packages/core/src/electron/snapshot.ts'; +import { plannedMainEntry } from '../../packages/core/src/electron/entry.ts'; import { normalizeRuntime } from '../../packages/core/src/electron/runtime.ts'; import { writeFakeElectron } from '../helpers/fake-electron.ts'; @@ -172,6 +173,79 @@ test('normalizeRuntime writes clamped Renderer overrideBrowserslist and leaves r ).toBe(false); }); +test('normalizeRuntime injects Conventional role outputs when distPath is unset', () => { + const appRoot = createAppRoot('conventional-dist'); + writePackageJson(appRoot, { name: 'app', private: true, type: 'module' }); + writeFakeElectron({ appRoot, version: '43.0.0' }); + + const runtime = normalizeRuntime({ + appRoot, + config: { + main: { + root: join(appRoot, 'src/main'), + source: { entry: { index: './index.ts' } }, + }, + preload: { + root: join(appRoot, 'src/preload'), + source: { entry: { index: './index.ts' } }, + }, + renderer: { + root: join(appRoot, 'src/renderer'), + source: { entry: { index: './index.ts' } }, + html: { template: './index.html' }, + }, + }, + }); + + for (const role of ['main', 'preload', 'renderer'] as const) { + const dist = runtime.roles[role]?.output?.distPath; + expect( + typeof dist === 'object' && dist !== null && !Array.isArray(dist), + ).toBe(true); + expect((dist as { root: string }).root).toBe(join(appRoot, 'out', role)); + } + + const planned = plannedMainEntry(appRoot, runtime.roles.main!); + expect(planned).toBe(join(appRoot, 'out/main/index.mjs')); +}); + +test('normalizeRuntime preserves explicit distPath and fills missing object root', () => { + const appRoot = createAppRoot('explicit-dist'); + writePackageJson(appRoot, { name: 'app', private: true }); + writeFakeElectron({ appRoot, version: '43.0.0' }); + + const runtime = normalizeRuntime({ + appRoot, + config: { + main: { + root: join(appRoot, 'main'), + source: { entry: { index: './index.ts' } }, + output: { distPath: 'custom-main' }, + }, + preload: { + root: join(appRoot, 'preload'), + source: { entry: { index: './index.ts' } }, + output: { distPath: { root: join(appRoot, 'pack/preload') } }, + }, + renderer: { + root: join(appRoot, 'renderer'), + source: { entry: { index: './index.ts' } }, + html: { template: './index.html' }, + output: { distPath: { js: 'static/js' } }, + }, + }, + }); + + expect(runtime.roles.main?.output?.distPath).toBe('custom-main'); + expect(runtime.roles.preload?.output?.distPath).toEqual({ + root: join(appRoot, 'pack/preload'), + }); + expect(runtime.roles.renderer?.output?.distPath).toEqual({ + js: 'static/js', + root: join(appRoot, 'out/renderer'), + }); +}); + test('build selects ESM automatically for module packages on supported Electron', async () => { const appRoot = createAppRoot('auto-esm'); writePackageJson(appRoot, { name: 'app', private: true, type: 'module' }); From 27e598f876f00b7012533998f187e49240f285f8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Aug 2026 19:13:10 +0000 Subject: [PATCH 4/5] Document Conventional role outputs and align examples. Update getting-started/migration, point example package.json#main at out/main, refresh BUILD-001 evidence, and assert docs-site copy. Co-authored-by: Zane --- docs/monorail/compatibility-matrix.md | 2 +- .../issues/02-docs-and-examples.md | 16 ++++++++++------ examples/react/package.json | 1 + examples/vanilla/package.json | 1 + tests/docs/docs-site.test.ts | 5 +++++ website/docs/en/guide/getting-started.mdx | 6 +++--- website/docs/en/guide/migration.md | 7 ++++--- website/docs/zh/guide/getting-started.mdx | 6 +++--- website/docs/zh/guide/migration.md | 7 ++++--- 9 files changed, 32 insertions(+), 19 deletions(-) diff --git a/docs/monorail/compatibility-matrix.md b/docs/monorail/compatibility-matrix.md index c0c1e19..cc644e9 100644 --- a/docs/monorail/compatibility-matrix.md +++ b/docs/monorail/compatibility-matrix.md @@ -162,7 +162,7 @@ Implementation evidence remains **Pending / 待实现** until automated tests or - Contract / 契约: preserve the same conventions and warn for omitted roles. - Classification / 分类: Target / 目标 - Acceptance / 验收: zero-config Vanilla fixture resolves the documented entries and output directories. -- Evidence / 证据: Partial — ADR `docs/monorail/adr/0007-electron-role-build-contract.md` documents `src/` → `out/` conventions; `tests/build.test.ts` and `examples/vanilla` prove explicit Role configs emit those outputs. Automatic zero-config discovery without `rselectron.config.*` is not implemented yet. / 部分完成——ADR `docs/monorail/adr/0007-electron-role-build-contract.md` 记录 `src/` → `out/` 约定;`tests/build.test.ts` 与 `examples/vanilla` 证明显式 Role 配置产出这些路径。尚无无 `rselectron.config.*` 的自动零配置发现。 +- Evidence / 证据: Partial — ADR `docs/monorail/adr/0007-electron-role-build-contract.md` documents `src/` → `out/` conventions; `normalizeRuntime` injects Conventional role outputs (`out/` under the Application root) when `output.distPath` is unset (`tests/unit/electron-runtime.test.ts`); getting-started / examples document and point `package.json#main` at `out/main`. Automatic zero-config discovery without `rselectron.config.*` is not implemented yet. / 部分完成——ADR `docs/monorail/adr/0007-electron-role-build-contract.md` 记录 `src/` → `out/` 约定;未设置 `output.distPath` 时 `normalizeRuntime` 会注入约定角色产物(应用根下的 `out/`,见 `tests/unit/electron-runtime.test.ts`);getting-started / examples 将 `package.json#main` 指到 `out/main`。尚无无 `rselectron.config.*` 的自动零配置发现。 ### BUILD-002 — Independent role compilation / 独立角色编译 diff --git a/docs/monorail/out-layout-preset/issues/02-docs-and-examples.md b/docs/monorail/out-layout-preset/issues/02-docs-and-examples.md index e24aea9..f091d16 100644 --- a/docs/monorail/out-layout-preset/issues/02-docs-and-examples.md +++ b/docs/monorail/out-layout-preset/issues/02-docs-and-examples.md @@ -1,6 +1,6 @@ # 02 — Docs and examples for out/ default -Status: claimed +Status: done Blocked by: 01 ## What to build @@ -9,8 +9,12 @@ Update getting-started (en + zh) so the Electron entry section teaches `out/`) as the default unset layout and no longer present `src/main/dist` as that default -- [ ] Migration (en + zh) or getting-started mentions the beta default change / how to keep an explicit `distPath: 'dist'` layout -- [ ] `examples/vanilla` and `examples/react` declare `package.json#main` aligned with planned Main output under `out/main` -- [ ] `tests/docs/docs-site.test.ts` asserts the getting-started default-layout copy anchors -- [ ] BUILD-001 evidence updated to credit preset injection while leaving zero-config-without-config as deferred/Partial if still accurate +- [x] Getting-started en + zh describe `out/main` (or `out/`) as the default unset layout and no longer present `src/main/dist` as that default +- [x] Migration (en + zh) or getting-started mentions the beta default change / how to keep an explicit `distPath: 'dist'` layout +- [x] `examples/vanilla` and `examples/react` declare `package.json#main` aligned with planned Main output under `out/main` +- [x] `tests/docs/docs-site.test.ts` asserts the getting-started default-layout copy anchors +- [x] BUILD-001 evidence updated to credit preset injection while leaving zero-config-without-config as deferred/Partial if still accurate + +## Comments + +- 2026-08-01: Docs, examples, matrix evidence, and docs-site asserts landed. diff --git a/examples/react/package.json b/examples/react/package.json index 710cba9..53a170a 100644 --- a/examples/react/package.json +++ b/examples/react/package.json @@ -2,6 +2,7 @@ "name": "rselectron-example-react", "private": true, "type": "module", + "main": "./out/main/index.mjs", "scripts": { "dev": "rselectron dev", "build": "rselectron build", diff --git a/examples/vanilla/package.json b/examples/vanilla/package.json index ffd9b3e..397f76e 100644 --- a/examples/vanilla/package.json +++ b/examples/vanilla/package.json @@ -2,6 +2,7 @@ "name": "rselectron-example-vanilla", "private": true, "type": "module", + "main": "./out/main/index.mjs", "scripts": { "dev": "rselectron dev", "build": "rselectron build", diff --git a/tests/docs/docs-site.test.ts b/tests/docs/docs-site.test.ts index c7665db..20c66d8 100644 --- a/tests/docs/docs-site.test.ts +++ b/tests/docs/docs-site.test.ts @@ -346,6 +346,9 @@ test('guide pages cover concepts, parity, and learning sources in both languages expect(gettingStarted).toContain('examples/'); expect(gettingStarted).not.toMatch(/tests\/fixtures|fixtures\//); expect(gettingStarted).toMatch(/\/guide\/concepts|concepts/); + expect(gettingStarted).toMatch(/out\/main|out\//); + expect(gettingStarted).toContain('./out/main/index.js'); + expect(gettingStarted).not.toContain('./src/main/dist/index.js'); expect(troubleshooting).toContain('RSELECTRON_ELECTRON_NOT_FOUND'); expect(troubleshooting).toContain('RSELECTRON_ROLE_MISSING'); @@ -371,6 +374,8 @@ test('guide pages cover concepts, parity, and learning sources in both languages expect(migration).toMatch(/swc/i); expect(migration).toMatch(/\/config\//); expect(migration).toMatch(/\/api\//); + expect(migration).toMatch(/out\/main/); + expect(migration).toMatch(/distPath/); } }); diff --git a/website/docs/en/guide/getting-started.mdx b/website/docs/en/guide/getting-started.mdx index 08123c2..ae77acb 100644 --- a/website/docs/en/guide/getting-started.mdx +++ b/website/docs/en/guide/getting-started.mdx @@ -81,17 +81,17 @@ Each of `main` / `preload` / `renderer` is a full Rsbuild config. Omit a key onl ## Electron entry -Point Electron’s application entry at the **main-process build output**. With the minimal config above, the default output is `dist` under each process `root`, so `package.json` can look like: +Point Electron’s application entry at the **main-process build output**. When `output.distPath` is unset, Rselectron presets Conventional role outputs under `out/` at the application root (not under each process `root`). With the minimal config above and a classic (non-`type: module`) package, `package.json` can look like: ```json title="package.json" { "name": "electron-app", "version": "1.0.0", - "main": "./src/main/dist/index.js" + "main": "./out/main/index.js" } ``` -Keep `main` (or `electron.entry` in config) aligned with the actual main output path. You can also set `output.distPath` to gather outputs under a shared directory (for example `out/main`), as many apps and the learning examples do. +Keep `main` (or `electron.entry` in config) aligned with the actual main output path. Entry extensions follow the Main format / `"type"` policy (for example `"type": "module"` with derived ESM uses `index.mjs`). Set an explicit `output.distPath` only when you need a custom layout—early beta builds that fell back to `/dist` without setting `distPath` should either point `main` at `out/...` or set `distPath` deliberately (for example `'dist'` relative to the Role `root`). ## Start from an example diff --git a/website/docs/en/guide/migration.md b/website/docs/en/guide/migration.md index 1aa2276..c754cdd 100644 --- a/website/docs/en/guide/migration.md +++ b/website/docs/en/guide/migration.md @@ -48,6 +48,7 @@ Rselectron aims for **capability parity**, not drop-in Vite config renaming. Mig 1. Replace Vite plugins with Rsbuild plugins. 2. Remove bytecode / SWC-helper usage; handle remaining needs outside Rselectron if required. 3. Map each process `root` and entry to Rsbuild config under [Configuration](/config/). -4. Install project-local Electron within the supported peer range ([Compatibility](./compatibility)). -5. Validate with `rselectron inspect`, then run `dev` / `build` / `preview`. -6. Prefer copying from [`examples/`](https://github.com/guangzan/rselectron/tree/main/examples), not from `tests/fixtures/`. +4. Point `package.json#main` at the planned Main output under Conventional role outputs (`out/main/...` when `distPath` is unset). Early beta unset layouts used `/dist`—set an explicit `distPath` if you still want that layout. +5. Install project-local Electron within the supported peer range ([Compatibility](./compatibility)). +6. Validate with `rselectron inspect`, then run `dev` / `build` / `preview`. +7. Prefer copying from [`examples/`](https://github.com/guangzan/rselectron/tree/main/examples), not from `tests/fixtures/`. diff --git a/website/docs/zh/guide/getting-started.mdx b/website/docs/zh/guide/getting-started.mdx index abc78a6..9f22aee 100644 --- a/website/docs/zh/guide/getting-started.mdx +++ b/website/docs/zh/guide/getting-started.mdx @@ -81,17 +81,17 @@ export default defineConfig({ ## Electron 入口 -把 Electron 的应用入口指到**主进程构建产物**。在上面的最小配置下,默认输出在各进程 `root` 下的 `dist`,因此 `package.json` 可以是: +把 Electron 的应用入口指到**主进程构建产物**。未设置 `output.distPath` 时,Rselectron 会按约定角色产物目录,在应用根下使用 `out/`(不会落在各进程 `root` 里)。上面的最小配置配合经典(非 `"type": "module"`)包时,`package.json` 可以是: ```json title="package.json" { "name": "electron-app", "version": "1.0.0", - "main": "./src/main/dist/index.js" + "main": "./out/main/index.js" } ``` -保持 `main`(或配置里的 `electron.entry`)与真实主进程产物路径一致。也可以设置 `output.distPath`,把产物收到共享目录(例如 `out/main`),许多应用与学习示例都这么做。 +保持 `main`(或配置里的 `electron.entry`)与真实主进程产物路径一致。入口扩展名跟随 Main 格式 / `"type"` 策略(例如 `"type": "module"` 且推导为 ESM 时使用 `index.mjs`)。只有需要自定义布局时才显式设置 `output.distPath`——早期 beta 在未设置 `distPath` 时会回落到 `/dist`;请把 `main` 指到 `out/...`,或有意设置 `distPath`(例如相对 Role `root` 的 `'dist'`)。 ## 从示例起步 diff --git a/website/docs/zh/guide/migration.md b/website/docs/zh/guide/migration.md index 50e3d5b..4be0bd0 100644 --- a/website/docs/zh/guide/migration.md +++ b/website/docs/zh/guide/migration.md @@ -48,6 +48,7 @@ Rselectron 追求**能力对等**,而不是 Vite 配置的一比一重命名 1. 把 Vite 插件换成 Rsbuild 插件。 2. 去掉 bytecode / SWC-helper 用法;剩余需求在 Rselectron 外处理。 3. 把各进程 `root` 与入口映射到 [配置](/config/) 下的 Rsbuild 配置。 -4. 在受支持 peer 范围内安装项目本地 Electron([兼容性](./compatibility))。 -5. 用 `rselectron inspect` 校验,再跑 `dev` / `build` / `preview`。 -6. 优先从 [`examples/`](https://github.com/guangzan/rselectron/tree/main/examples) 复制,不要从 `tests/fixtures/` 学。 +4. 把 `package.json#main` 指到约定角色产物下的计划 Main 输出(未设置 `distPath` 时为 `out/main/...`)。早期 beta 未设置时会落到 `/dist`——若仍要该布局,请显式设置 `distPath`。 +5. 在受支持 peer 范围内安装项目本地 Electron([兼容性](./compatibility))。 +6. 用 `rselectron inspect` 校验,再跑 `dev` / `build` / `preview`。 +7. 优先从 [`examples/`](https://github.com/guangzan/rselectron/tree/main/examples) 复制,不要从 `tests/fixtures/` 学。 From 5f06ab513c2b73bd173971dde1d942986d56e2c3 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Aug 2026 19:26:58 +0000 Subject: [PATCH 5/5] Avoid domain jargon in getting-started Electron entry copy. Keep the approachable getting-started gate free of bare Role terminology. Co-authored-by: Zane --- website/docs/en/guide/getting-started.mdx | 2 +- website/docs/zh/guide/getting-started.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/en/guide/getting-started.mdx b/website/docs/en/guide/getting-started.mdx index ae77acb..ee294b6 100644 --- a/website/docs/en/guide/getting-started.mdx +++ b/website/docs/en/guide/getting-started.mdx @@ -91,7 +91,7 @@ Point Electron’s application entry at the **main-process build output**. When } ``` -Keep `main` (or `electron.entry` in config) aligned with the actual main output path. Entry extensions follow the Main format / `"type"` policy (for example `"type": "module"` with derived ESM uses `index.mjs`). Set an explicit `output.distPath` only when you need a custom layout—early beta builds that fell back to `/dist` without setting `distPath` should either point `main` at `out/...` or set `distPath` deliberately (for example `'dist'` relative to the Role `root`). +Keep `main` (or `electron.entry` in config) aligned with the actual main output path. Entry extensions follow the Main format / `"type"` policy (for example `"type": "module"` with derived ESM uses `index.mjs`). Set an explicit `output.distPath` only when you need a custom layout—early beta builds that fell back to `/dist` without setting `distPath` should either point `main` at `out/...` or set `distPath` deliberately (for example `'dist'` relative to the process `root`). ## Start from an example diff --git a/website/docs/zh/guide/getting-started.mdx b/website/docs/zh/guide/getting-started.mdx index 9f22aee..819590d 100644 --- a/website/docs/zh/guide/getting-started.mdx +++ b/website/docs/zh/guide/getting-started.mdx @@ -91,7 +91,7 @@ export default defineConfig({ } ``` -保持 `main`(或配置里的 `electron.entry`)与真实主进程产物路径一致。入口扩展名跟随 Main 格式 / `"type"` 策略(例如 `"type": "module"` 且推导为 ESM 时使用 `index.mjs`)。只有需要自定义布局时才显式设置 `output.distPath`——早期 beta 在未设置 `distPath` 时会回落到 `/dist`;请把 `main` 指到 `out/...`,或有意设置 `distPath`(例如相对 Role `root` 的 `'dist'`)。 +保持 `main`(或配置里的 `electron.entry`)与真实主进程产物路径一致。入口扩展名跟随 Main 格式 / `"type"` 策略(例如 `"type": "module"` 且推导为 ESM 时使用 `index.mjs`)。只有需要自定义布局时才显式设置 `output.distPath`——早期 beta 在未设置 `distPath` 时会回落到 `/dist`;请把 `main` 指到 `out/...`,或有意设置 `distPath`(例如相对进程 `root` 的 `'dist'`)。 ## 从示例起步