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
4 changes: 2 additions & 2 deletions solid-v2/with-tsrx/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ Name your signals/memos/effects (the `{ name: "..." }` option) — attribution r

## TSRX modules (`.tsrx`)

This template authors the app in experimental TSRX wherever tooling allows: `src/App.tsrx`, `src/Document.tsrx`, and `src/components/*.tsrx`. Rules that differ from `.tsx`:
This template authors the whole app in experimental TSRX: `src/App.tsrx`, `src/Document.tsrx`, `src/components/*.tsrx`, and every route module under `src/routes`. Rules that differ from `.tsx`:

- The extension is the opt-in: import with it spelled out (`./Counter.tsrx`). The Vite plugin compiles these automatically; no config.
- A function body can be a statement container: `function C(props) @{ setup; <output/> }` — TypeScript statements first, then exactly one rendered output node (use a fragment for siblings).
- Template control flow is directive-based: `@if (cond) { ... } @else { ... }`, `@for (const x of list(); index i) { ... } @empty { ... }`, `@switch`, `@try`. `return`/`break` are syntax errors inside these blocks.
- A `<style>` block scopes its **sibling** elements and their descendants (not its ancestors). Unused selectors are pruned from the emitted CSS.
- Authored lazy destructuring (`&{ ... }`/`&[ ... ]`) is rejected by the Solid target — keep reads explicit.
- Type checking: `pnpm typecheck` (`tsrx-tsc`); plain `tsc` cannot resolve `.tsrx` imports. oxlint skips `.tsrx` files.
- **Route modules under `src/routes` must stay `.tsx`**: the fileRoutes scanner parses route sources with oxc-parser, which cannot read TSRX — a `.tsrx` route file breaks the build. Routes may import `.tsrx` components freely.
- Route modules are `.tsrx` too: the fileRoutes scanner (`filesystem-routing` ≥ 0.3.0) analyzes `.tsrx` route exports through `@tsrx/oxc` (a dev dependency here). Keep `route` config exports as plain top-level TypeScript statements — only the component body uses `@{ ... }`.
- Do not put a `<style>` block inside an arrow function (e.g. a render prop): the compiler only scopes a style's siblings and their descendants, and the typecheck projection rejects that placement. Component-level `<style>` in function bodies is fully supported.
8 changes: 4 additions & 4 deletions solid-v2/with-tsrx/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Solid `with-tsrx` template (experimental)

This is `basic` plus **experimental TSRX** — same routes, same demo, same tests; the app is authored in `.tsrx` instead of `.tsx` wherever the current tooling allows: the app root (`src/App.tsrx`), the document shell (`src/Document.tsrx`), and the components (`src/components/*.tsrx`). Route modules under `src/routes` stay `.tsx` for now — see "What stays `.tsx` and why" below. The diff against `basic` is the documentation of what TSRX changes.
This is `basic` plus **experimental TSRX** — same routes, same demo, same tests; the whole app is authored in `.tsrx` instead of `.tsx`: the app root (`src/App.tsrx`), the document shell (`src/Document.tsrx`), the components (`src/components/*.tsrx`), and every route module under `src/routes`. The diff against `basic` is the documentation of what TSRX changes.

TSRX support is experimental across the whole stack: the compiler frontends in `solid-js` 2.0 RC, the `.tsrx` pipeline in `@solidjs/vite-plugin`, and the third-party editor tooling are all pre-1.0 and may change. Treat this template as a preview of the format, not a stability contract.

Expand All @@ -18,10 +18,10 @@ TSRX support is experimental across the whole stack: the compiler frontends in `
- **`src/Document.tsrx`** — the document shell, picked up by the `src/Document.*` convention and compiled only into the prerendered static shell.
- **`src/components/Counter.tsrx`** — the statement-container body with setup (`@{` TypeScript first, then exactly one rendered output), a scoped `<style>` block, and an `@if` block that renders a milestone message (it lowers to Solid's `<Show>`).
- **`src/components/Guestbook.tsrx`** — `@for (const guest of guests(); index i) { ... } @empty { ... }` over a reactive list (it lowers to Solid's `<For>`; item reads stay deferred, so a replaced row updates in place) plus descendant selectors in its scoped styles.
- **`src/routes/*.tsrx`** — route modules are TSRX too. The `fileRoutes()` scanner (`filesystem-routing` ≥ 0.3.0) statically analyzes every route module's exports to apply the page convention (default export = page, `route` export = config); for `.tsrx` routes it does that through [`@tsrx/oxc`](https://www.npmjs.com/package/@tsrx/oxc), which this template installs as a dev dependency (it is an optional peer of `filesystem-routing`, needed only when routes are `.tsrx`). `src/routes/users/[id].tsrx` shows the full shape: a `query` + `route.preload` config export next to a statement-container page component.

## What stays `.tsx` and why
## What stays `.tsx`/`.ts`

- **Route modules (`src/routes/**`)** — the `fileRoutes()` scanner (`filesystem-routing`) statically analyzes every route module's exports to apply the page convention (default export = page, `route` export = config), and its parser (`oxc-parser`) cannot parse TSRX syntax yet: a `.tsrx`route fails the build at the first`@{`. Route pages can freely *import* `.tsrx` components (the home route imports both), so only the thin route modules themselves wait on the scanner.
- **Test files (`*.test.tsx`)** — by design: vitest never needs to parse TSRX-authored source, the tests import the compiled `.tsrx` components and stay ordinary TSX.
- **`src/router.ts`, `vite.config.ts`, `vitest-setup.ts`** — no JSX, nothing to convert.

Expand All @@ -45,7 +45,7 @@ Plain `tsc` cannot resolve `.tsrx` imports. `pnpm typecheck` runs `tsrx-tsc --no

## Linting and formatting

`oxlint` cannot parse TSRX syntax; `.tsrx` is excluded in `oxlint.config.mjs` (the files are outside oxlint's extension set today — the ignore entry makes the posture explicit). `pnpm lint` still covers every `.ts`/`.tsx` file. The TSRX project publishes [`@tsrx/oxc`](https://www.npmjs.com/package/@tsrx/oxc) (`.tsrx`-aware oxlint/oxfmt) and `@tsrx/prettier-plugin`; `eslint-plugin-solid` coverage for `.tsrx` is future work, so this template keeps the stock toolchain and leaves those opt-in.
`oxlint` cannot parse TSRX syntax; `.tsrx` is excluded in `oxlint.config.mjs` (the files are outside oxlint's extension set today — the ignore entry makes the posture explicit). `pnpm lint` still covers every `.ts`/`.tsx` file. `@tsrx/oxc` (installed here for route export analysis) also ships a `.tsrx`-aware `oxlint`/`oxfmt`, but this template keeps the stock `oxlint` for linting (its own bin wins in `node_modules/.bin`); `eslint-plugin-solid` coverage for `.tsrx` is future work, so `.tsrx`-aware linting stays opt-in.

## Current limits

Expand Down
24 changes: 12 additions & 12 deletions solid-v2/with-tsrx/file-routes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,26 @@ declare module "virtual:file-routes" {
{
path: "/*404";
page: true;
$component: FileRouteLazyRef<typeof import("./src/routes/[...404]")>;
$$route: FileRouteEagerRef<typeof import("./src/routes/[...404]")>;
$component: FileRouteLazyRef;
$$route: FileRouteEagerRef;
},
{
path: "/";
page: true;
$component: FileRouteLazyRef<typeof import("./src/routes/index")>;
$component: FileRouteLazyRef;
$$route?: undefined;
},
{
path: "/users";
page: true;
$component: FileRouteLazyRef<typeof import("./src/routes/users")>;
$component: FileRouteLazyRef;
$$route?: undefined;
},
{
path: "/users/:id";
page: true;
$component: FileRouteLazyRef<typeof import("./src/routes/users/[id]")>;
$$route: FileRouteEagerRef<typeof import("./src/routes/users/[id]")>;
$component: FileRouteLazyRef;
$$route: FileRouteEagerRef;
}
];
export default routes;
Expand All @@ -65,31 +65,31 @@ declare module "virtual:file-routes" {
path: "/";
id: "/";
page: true;
$component: FileRouteLazyRef<typeof import("./src/routes/index")>;
$component: FileRouteLazyRef;
$$route?: undefined;
children?: undefined;
},
{
path: "/*404";
id: "/*404";
page: true;
$component: FileRouteLazyRef<typeof import("./src/routes/[...404]")>;
$$route: FileRouteEagerRef<typeof import("./src/routes/[...404]")>;
$component: FileRouteLazyRef;
$$route: FileRouteEagerRef;
children?: undefined;
},
{
path: "/users";
id: "/users";
page: true;
$component: FileRouteLazyRef<typeof import("./src/routes/users")>;
$component: FileRouteLazyRef;
$$route?: undefined;
children: readonly [
{
path: "/:id";
id: "/:id";
page: true;
$component: FileRouteLazyRef<typeof import("./src/routes/users/[id]")>;
$$route: FileRouteEagerRef<typeof import("./src/routes/users/[id]")>;
$component: FileRouteLazyRef;
$$route: FileRouteEagerRef;
children?: undefined;
}
];
Expand Down
3 changes: 2 additions & 1 deletion solid-v2/with-tsrx/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
"@solidjs/testing-library": "^1.0.0-beta.2",
"@solidjs/vite-plugin": "^3.0.0-next.38",
"@testing-library/jest-dom": "^6.6.3",
"@tsrx/oxc": "^0.9.0",
"@tsrx/solid": "^0.1.64",
"@tsrx/typescript-plugin": "^0.3.129",
"eslint-plugin-solid": "~0.17.0",
"filesystem-routing": "0.2.1",
"filesystem-routing": "0.3.0",
"jsdom": "^25.0.1",
"oxlint": "~1.79.0",
"typescript": "^5.9.3",
Expand Down
Loading