@rivetjs/nx 0.0.0-stage → 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +63 -2
  3. package/executors/build/executor.d.ts +12 -0
  4. package/executors/build/executor.js +50 -0
  5. package/executors/build/schema.d.ts +18 -0
  6. package/executors/build/schema.json +18 -0
  7. package/executors/check/executor.d.ts +11 -0
  8. package/executors/check/executor.js +31 -0
  9. package/executors/check/schema.d.ts +12 -0
  10. package/executors/check/schema.json +18 -0
  11. package/executors/dev/executor.d.ts +14 -0
  12. package/executors/dev/executor.js +32 -0
  13. package/executors/dev/schema.d.ts +16 -0
  14. package/executors/dev/schema.json +17 -0
  15. package/executors/package/executor.d.ts +20 -0
  16. package/executors/package/executor.js +65 -0
  17. package/executors/package/schema.d.ts +10 -0
  18. package/executors/package/schema.json +18 -0
  19. package/executors/prerender/executor.d.ts +8 -0
  20. package/executors/prerender/executor.js +13 -0
  21. package/executors/prerender/schema.d.ts +6 -0
  22. package/executors/prerender/schema.json +12 -0
  23. package/executors/preview/executor.d.ts +12 -0
  24. package/executors/preview/executor.js +52 -0
  25. package/executors/preview/schema.d.ts +10 -0
  26. package/executors/preview/schema.json +14 -0
  27. package/executors/run.d.ts +33 -0
  28. package/executors/run.js +88 -0
  29. package/executors/test/executor.d.ts +8 -0
  30. package/executors/test/executor.js +27 -0
  31. package/executors/test/schema.d.ts +24 -0
  32. package/executors/test/schema.json +21 -0
  33. package/executors/typecheck/executor.d.ts +9 -0
  34. package/executors/typecheck/executor.js +14 -0
  35. package/executors/typecheck/schema.d.ts +6 -0
  36. package/executors/typecheck/schema.json +12 -0
  37. package/executors.json +49 -0
  38. package/generators/api-route/files/__fileName__.ts.template +11 -0
  39. package/generators/api-route/generator.d.ts +5 -0
  40. package/generators/api-route/generator.js +30 -0
  41. package/generators/api-route/schema.d.ts +9 -0
  42. package/generators/api-route/schema.json +31 -0
  43. package/generators/application/files/tests/minimal/src/routes/index.test.tsx.template +9 -0
  44. package/generators/application/files/tests/server/src/routes/index.server.test.tsx.template +8 -0
  45. package/generators/application/files/tests/static/src/components/Counter.test.tsx.template +10 -0
  46. package/generators/application/files/tests/ui/src/components/LikeButton.server.test.tsx.template +7 -0
  47. package/generators/application/files/vitest/vitest.config.ts.template +16 -0
  48. package/generators/application/generator.d.ts +20 -0
  49. package/generators/application/generator.js +161 -0
  50. package/generators/application/schema.d.ts +24 -0
  51. package/generators/application/schema.json +57 -0
  52. package/generators/component/files/basic/__fileName__.tsx.template +24 -0
  53. package/generators/component/files/overlay/__fileName__.tsx.template +32 -0
  54. package/generators/component/files/story/__storyName__.tsx.template +24 -0
  55. package/generators/component/files/test-basic/__fileName__.test.tsx.template +10 -0
  56. package/generators/component/files/test-overlay/__fileName__.test.tsx.template +10 -0
  57. package/generators/component/generator.d.ts +5 -0
  58. package/generators/component/generator.js +45 -0
  59. package/generators/component/schema.d.ts +17 -0
  60. package/generators/component/schema.json +35 -0
  61. package/generators/i18n-setup/files/i18n.config.ts.template +10 -0
  62. package/generators/i18n-setup/generator.d.ts +7 -0
  63. package/generators/i18n-setup/generator.js +65 -0
  64. package/generators/i18n-setup/schema.d.ts +13 -0
  65. package/generators/i18n-setup/schema.json +24 -0
  66. package/generators/init/generator.d.ts +8 -0
  67. package/generators/init/generator.js +48 -0
  68. package/generators/init/schema.d.ts +13 -0
  69. package/generators/init/schema.json +19 -0
  70. package/generators/layout/files/_layout.tsx.template +12 -0
  71. package/generators/layout/generator.d.ts +5 -0
  72. package/generators/layout/generator.js +23 -0
  73. package/generators/layout/schema.d.ts +9 -0
  74. package/generators/layout/schema.json +26 -0
  75. package/generators/library/files/lib/README.md.template +18 -0
  76. package/generators/library/files/lib/package.json.template +12 -0
  77. package/generators/library/files/lib/src/__className__.tsx.template +16 -0
  78. package/generators/library/files/lib/src/index.ts.template +1 -0
  79. package/generators/library/files/lib/tsconfig.json.template +21 -0
  80. package/generators/library/files/publishable/tsconfig.lib.json.template +13 -0
  81. package/generators/library/files/subpath/src/__subpath__/__subpathClass__.tsx.template +10 -0
  82. package/generators/library/files/subpath/src/__subpath__/index.ts.template +1 -0
  83. package/generators/library/files/vitest/src/__className__.test.tsx.template +13 -0
  84. package/generators/library/generator.d.ts +13 -0
  85. package/generators/library/generator.js +116 -0
  86. package/generators/library/schema.d.ts +19 -0
  87. package/generators/library/schema.json +32 -0
  88. package/generators/preset/generator.d.ts +5 -0
  89. package/generators/preset/generator.js +29 -0
  90. package/generators/preset/schema.d.ts +16 -0
  91. package/generators/preset/schema.json +30 -0
  92. package/generators/route/files/__fileName__.tsx.template +43 -0
  93. package/generators/route/generator.d.ts +10 -0
  94. package/generators/route/generator.js +67 -0
  95. package/generators/route/schema.d.ts +15 -0
  96. package/generators/route/schema.json +29 -0
  97. package/generators/ui-setup/generator.d.ts +7 -0
  98. package/generators/ui-setup/generator.js +55 -0
  99. package/generators/ui-setup/schema.d.ts +7 -0
  100. package/generators/ui-setup/schema.json +21 -0
  101. package/generators.json +66 -0
  102. package/index.d.ts +22 -0
  103. package/index.js +24 -0
  104. package/migrations/0.0.1/example-noop.d.ts +2 -0
  105. package/migrations/0.0.1/example-noop.js +3 -0
  106. package/migrations.json +10 -0
  107. package/package.json +74 -4
  108. package/plugin.d.ts +12 -0
  109. package/plugin.js +44 -0
  110. package/utils/deploy.d.ts +14 -0
  111. package/utils/deploy.js +86 -0
  112. package/utils/detect.d.ts +42 -0
  113. package/utils/detect.js +60 -0
  114. package/utils/facts.d.ts +8 -0
  115. package/utils/facts.js +42 -0
  116. package/utils/project.d.ts +28 -0
  117. package/utils/project.js +67 -0
  118. package/utils/starter.d.ts +9 -0
  119. package/utils/starter.js +34 -0
  120. package/utils/targets.d.ts +22 -0
  121. package/utils/targets.js +117 -0
  122. package/utils/versions.d.ts +13 -0
  123. package/utils/versions.js +31 -0
  124. package/utils/vite-config.d.ts +8 -0
  125. package/utils/vite-config.js +104 -0
  126. package/utils/workspace.d.ts +13 -0
  127. package/utils/workspace.js +63 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Denys Severyn
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,64 @@
1
- # Temporary Holding Version
1
+ # @rivetjs/nx
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [Nx](https://nx.dev) plugin for [Rivet](https://github.com/rivetjs/rivet): a workspace preset, generators for apps,
4
+ libraries, routes and components, executors, and inferred `build` / `dev` / `preview` / `test` / `check` /
5
+ `typecheck` targets with Nx caching.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ # New workspace with a first Rivet app
11
+ npx create-nx-workspace@latest my-org --preset=@rivetjs/nx --template=static
12
+
13
+ # Existing workspace: installs the plugin and runs its init generator
14
+ npx nx add @rivetjs/nx
15
+ npx nx g @rivetjs/nx:app apps/web
16
+ ```
17
+
18
+ Node.js 24 or newer, Nx 23.
19
+
20
+ ## Generators
21
+
22
+ | Generator | Alias | Creates |
23
+ | --- | --- | --- |
24
+ | `application` | `app` | A Rivet app from a create-rivet starter: `--template=static\|server\|ui\|minimal`, `--adapter=node\|static`, `--deploy=vercel\|netlify\|cloudflare\|bun\|deno` (create-rivet's deploy files; `deploy` / `preview` targets), `--tailwind`, `--unitTestRunner=vitest\|none`, `--tags`. |
25
+ | `library` | `lib` | A component library: source exports per subpath (`--subpaths=button,card`, `sideEffects: false`), Vitest, `--publishable` package build, `--importPath`. |
26
+ | `component` | `c` | A resumable component + test: `--kind=basic\|overlay` (render-function children), `--story` (a `/stories/<name>` page), `--directory`, `--export`. |
27
+ | `route` | `r`, `page` | A file route: `blog/[slug]`, `docs/[[lang]]/[...path]`, `(group)/page`; `--loader`, `--action`, `--guard`, `--layout`. |
28
+ | `layout` | | `src/routes/<dir>/_layout.tsx`, `--guard`. |
29
+ | `api-route` | `endpoint` | An endpoint route with `onGet` / `onPost` / … (`--methods=get,post`). |
30
+ | `ui-setup` | | `@rivetjs/ui` + Tailwind v4 + its styles (Rivet theme; other looks = `@rivetjs/ui/theme` presets). |
31
+ | `i18n-setup` | | `@rivetjs/i18n`: `i18n.config.ts`, catalogs, the Vite plugin (`--locales=en,de`, `--prefix`). |
32
+ | `init` | | Plugin in `nx.json`, shared tooling dependencies, `.rivet` in `.gitignore`. |
33
+ | `preset` | | `create-nx-workspace --preset=@rivetjs/nx`. |
34
+
35
+ All generators write through the Nx tree: `--dry-run` shows the files without writing them.
36
+
37
+ ## Executors
38
+
39
+ | Executor | Runs |
40
+ | --- | --- |
41
+ | `@rivetjs/nx:build` | `vite build` (per locale with i18n) → `vite build --ssr` → prerender (static apps). |
42
+ | `@rivetjs/nx:dev` / `serve` | `vite` (continuous). |
43
+ | `@rivetjs/nx:preview` | The project's `serve.js`, the router's Node server, or `vite preview` (continuous). |
44
+ | `@rivetjs/nx:prerender` | `prerenderBuild()` over an existing build. |
45
+ | `@rivetjs/nx:check` | `rivet sync` + `rivet-check`. |
46
+ | `@rivetjs/nx:test` | `vitest run` with the project's `rivetTest()` config. |
47
+ | `@rivetjs/nx:typecheck` | `rivet sync` + `tsc --noEmit`. |
48
+ | `@rivetjs/nx:package` | Publishable library: `.js` / `.jsx` (JSX preserved) + `.d.ts`, mapped `package.json`. |
49
+
50
+ ## Inferred targets
51
+
52
+ ```json
53
+ { "plugins": [{ "plugin": "@rivetjs/nx/plugin", "options": { "buildTargetName": "build" } }] }
54
+ ```
55
+
56
+ Every folder with a `package.json` or `project.json` and a Rivet Vite config (`rivetRouter()` /
57
+ `@rivetjs/compiler/vite`) gets `build`, `dev`, `preview`; a Vitest config with `rivetTest()` adds `test`; a
58
+ `tsconfig.json` adds `check` and `typecheck`. Option names: `buildTargetName`, `devTargetName`, `previewTargetName`,
59
+ `testTargetName`, `checkTargetName`, `typecheckTargetName`, `deployTargetName`. A `rivetRouter({ adapter })` of
60
+ `vercel` / `cloudflare` adds `deploy` (`vercel deploy --prebuilt` / `wrangler deploy`); `cloudflare` / `bun` / `deno`
61
+ make `preview` run `wrangler dev` / Bun / Deno. `build`, `test`, `check`, `typecheck` are cached; `.rivet/`,
62
+ `dist/` and `coverage/` are never inputs; `build` outputs `{projectRoot}/dist`.
63
+
64
+ Docs: [Nx guide](https://github.com/rivetjs/rivet/blob/main/apps/docs/content/guides/tooling/nx.md).
@@ -0,0 +1,12 @@
1
+ import type { ExecutorContext } from "@nx/devkit";
2
+ import type { ProjectFacts } from "../../utils/detect.js";
3
+ import { type BinResolver, type Step } from "../run.js";
4
+ import type { BuildExecutorSchema } from "./schema.js";
5
+ export type { BuildExecutorSchema } from "./schema.js";
6
+ /** Node code of the default prerender step (projects without their own `prerender.js`). */
7
+ export declare function prerenderCode(dist: string): string;
8
+ /** The build steps for a project (pure: `facts` and `bin` are passed in). */
9
+ export declare function buildSteps(options: BuildExecutorSchema, root: string, facts: ProjectFacts | undefined, bin: BinResolver): Step[];
10
+ export default function buildExecutor(options: BuildExecutorSchema, context: ExecutorContext): Promise<{
11
+ success: boolean;
12
+ }>;
@@ -0,0 +1,50 @@
1
+ // `@rivetjs/nx:build`: `vite build` (per locale with i18n) → `vite build --ssr` → prerender (static apps). The same
2
+ // steps as the starter templates' `build` script, run from the project folder.
3
+ import { existsSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { projectFacts } from "../../utils/facts.js";
6
+ import { flags, projectRoot, resolverFrom, runSteps } from "../run.js";
7
+ /** Node code of the default prerender step (projects without their own `prerender.js`). */
8
+ export function prerenderCode(dist) {
9
+ return (`import { prerenderBuild } from "@rivetjs/router/static";\n` +
10
+ `const report = await prerenderBuild({ dist: ${JSON.stringify(dist)} });\n` +
11
+ `console.log("Prerendered " + report.pages.length + " page(s) into " + ${JSON.stringify(dist + "/client")});\n`);
12
+ }
13
+ /** The build steps for a project (pure: `facts` and `bin` are passed in). */
14
+ export function buildSteps(options, root, facts, bin) {
15
+ const vite = bin("vite");
16
+ const dist = options.outputPath ?? "dist";
17
+ const common = flags([
18
+ ["--config", options.config],
19
+ ["--mode", options.mode],
20
+ ["--logLevel", options.logLevel],
21
+ ]);
22
+ const env = options.env ?? {};
23
+ const steps = [];
24
+ const locales = options.locales ?? facts?.locales;
25
+ if (locales?.length) {
26
+ for (const locale of locales)
27
+ steps.push({ label: `vite build (client, ${locale})`, args: [vite, "build", ...common], cwd: root, env: { ...env, RIVET_LOCALE: locale } });
28
+ }
29
+ else {
30
+ steps.push({ label: "vite build (client)", args: [vite, "build", ...common], cwd: root, env });
31
+ }
32
+ const ssr = options.ssr ?? (facts ? facts.kind === "app" && !facts.csr : false);
33
+ if (ssr)
34
+ steps.push({ label: "vite build --ssr (server)", args: [vite, "build", "--ssr", ...common], cwd: root, env });
35
+ const prerender = options.prerender ?? Boolean(facts?.static);
36
+ if (prerender) {
37
+ if (!ssr)
38
+ throw new Error("@rivetjs/nx:build: prerender needs the server build (ssr: true)");
39
+ steps.push(facts?.prerenderScript && dist === "dist"
40
+ ? { label: "node prerender.js", args: [join(root, "prerender.js")], cwd: root, env }
41
+ : { label: "prerender", args: ["--input-type=module", "-e", prerenderCode(dist)], cwd: root, env });
42
+ }
43
+ return steps;
44
+ }
45
+ export default async function buildExecutor(options, context) {
46
+ const root = projectRoot(context);
47
+ if (options.config && !existsSync(join(root, options.config)))
48
+ throw new Error(`@rivetjs/nx:build: ${options.config} not found in ${root}`);
49
+ return runSteps(buildSteps(options, root, projectFacts(root), resolverFrom(root)));
50
+ }
@@ -0,0 +1,18 @@
1
+ export interface BuildExecutorSchema {
2
+ /** Vite config file, relative to the project (default: Vite's lookup). */
3
+ config?: string;
4
+ /** Vite mode (`--mode`). */
5
+ mode?: string;
6
+ /** Also run the server build (`vite build --ssr`). Default: true, except `rivetRouter({ mode: "csr" })` apps. */
7
+ ssr?: boolean;
8
+ /** Prerender every page after the builds. Default: true for `rivetRouter({ mode: "static" })` apps. */
9
+ prerender?: boolean;
10
+ /** One client build per locale (`RIVET_LOCALE`), for `@rivetjs/i18n` apps. Inferred from `i18n.config.ts`. */
11
+ locales?: string[];
12
+ /** Build output folder, relative to the project (must match the router's `dist`). Default `dist`. */
13
+ outputPath?: string;
14
+ /** Vite `--logLevel`. */
15
+ logLevel?: "info" | "warn" | "error" | "silent";
16
+ /** Extra environment variables for every step. */
17
+ env?: Record<string, string>;
18
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "version": 2,
4
+ "title": "Rivet build",
5
+ "description": "Builds a Rivet app with Vite: the client build (one per locale with @rivetjs/i18n), the server build, then the prerender step for static apps.",
6
+ "type": "object",
7
+ "properties": {
8
+ "config": { "type": "string", "description": "Vite config file, relative to the project (default: Vite's lookup)." },
9
+ "mode": { "type": "string", "description": "Vite mode (--mode)." },
10
+ "ssr": { "type": "boolean", "description": "Also run the server build (vite build --ssr). Default: true, except csr-mode apps." },
11
+ "prerender": { "type": "boolean", "description": "Prerender every page after the builds. Default: true for rivetRouter({ mode: \"static\" }) apps." },
12
+ "locales": { "type": "array", "items": { "type": "string" }, "description": "One client build per locale (RIVET_LOCALE). Inferred from i18n.config.ts." },
13
+ "outputPath": { "type": "string", "default": "dist", "description": "Build output folder, relative to the project." },
14
+ "logLevel": { "type": "string", "enum": ["info", "warn", "error", "silent"], "description": "Vite log level." },
15
+ "env": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Extra environment variables for every step." }
16
+ },
17
+ "additionalProperties": false
18
+ }
@@ -0,0 +1,11 @@
1
+ import type { ExecutorContext } from "@nx/devkit";
2
+ import type { ProjectFacts } from "../../utils/detect.js";
3
+ import { type BinResolver, type Step } from "../run.js";
4
+ import type { CheckExecutorSchema } from "./schema.js";
5
+ export type { CheckExecutorSchema } from "./schema.js";
6
+ /** `rivet sync` for projects with a Vite config (the router / compiler plugin writes `.rivet/`). */
7
+ export declare function syncStep(root: string, bin: BinResolver): Step;
8
+ export declare function checkSteps(options: CheckExecutorSchema, root: string, facts: ProjectFacts | undefined, bin: BinResolver): Step[];
9
+ export default function checkExecutor(options: CheckExecutorSchema, context: ExecutorContext): Promise<{
10
+ success: boolean;
11
+ }>;
@@ -0,0 +1,31 @@
1
+ import { projectFacts } from "../../utils/facts.js";
2
+ import { flags, projectRoot, resolverFrom, runSteps } from "../run.js";
3
+ /** `rivet sync` for projects with a Vite config (the router / compiler plugin writes `.rivet/`). */
4
+ export function syncStep(root, bin) {
5
+ return { label: "rivet sync", args: [bin("@rivetjs/router", "rivet"), "sync"], cwd: root };
6
+ }
7
+ export function checkSteps(options, root, facts, bin) {
8
+ const routed = facts?.kind === "app";
9
+ const steps = [];
10
+ if (options.sync ?? routed)
11
+ steps.push(syncStep(root, bin));
12
+ const configs = options.tsConfig === undefined ? ["tsconfig.json"] : Array.isArray(options.tsConfig) ? options.tsConfig : [options.tsConfig];
13
+ steps.push({
14
+ label: "rivet-check",
15
+ args: [
16
+ bin("@rivetjs/language-core", "rivet-check"),
17
+ ...configs.flatMap((config) => ["-p", config]),
18
+ ...flags([
19
+ ["--no-types", options.types === false],
20
+ ["--no-manifest", !(options.manifest ?? routed)],
21
+ ["--format", options.format],
22
+ ]),
23
+ ],
24
+ cwd: root,
25
+ });
26
+ return steps;
27
+ }
28
+ export default async function checkExecutor(options, context) {
29
+ const root = projectRoot(context);
30
+ return runSteps(checkSteps(options, root, projectFacts(root), resolverFrom(root)));
31
+ }
@@ -0,0 +1,12 @@
1
+ export interface CheckExecutorSchema {
2
+ /** tsconfig file(s) to check, relative to the project. Default `tsconfig.json`. */
3
+ tsConfig?: string | string[];
4
+ /** Type-aware checks (RV2101 serializability, RV3101 route links). Default true. */
5
+ types?: boolean;
6
+ /** Check `.rivet/editor.json` (RV7101 / RV7102). Default: routed apps only. */
7
+ manifest?: boolean;
8
+ /** Run `rivet sync` first (regenerates `.rivet/`). Default: routed apps only. */
9
+ sync?: boolean;
10
+ /** Output format. */
11
+ format?: "text" | "json";
12
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "version": 2,
4
+ "title": "Rivet check",
5
+ "description": "Rivet diagnostics for a project (rivet-check from @rivetjs/language-core): compiler errors of both targets, serializability, route links. Routed apps run rivet sync first.",
6
+ "type": "object",
7
+ "properties": {
8
+ "tsConfig": {
9
+ "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }],
10
+ "description": "tsconfig file(s) to check, relative to the project. Default tsconfig.json."
11
+ },
12
+ "types": { "type": "boolean", "default": true, "description": "Type-aware checks (RV2101 serializability, RV3101 route links)." },
13
+ "manifest": { "type": "boolean", "description": "Check .rivet/editor.json (RV7101 / RV7102). Default: routed apps only." },
14
+ "sync": { "type": "boolean", "description": "Run rivet sync first. Default: routed apps only." },
15
+ "format": { "type": "string", "enum": ["text", "json"], "description": "Output format." }
16
+ },
17
+ "additionalProperties": false
18
+ }
@@ -0,0 +1,14 @@
1
+ import type { ExecutorContext } from "@nx/devkit";
2
+ import { type BinResolver, type Step } from "../run.js";
3
+ import type { DevExecutorSchema } from "./schema.js";
4
+ export type { DevExecutorSchema } from "./schema.js";
5
+ export declare function devStep(options: DevExecutorSchema, root: string, bin: BinResolver): Step;
6
+ /** `http://host:port` the server is expected on (Nx shows it; Vite prints the real one). */
7
+ export declare function baseUrl(options: {
8
+ port?: number;
9
+ host?: string | boolean;
10
+ }, fallbackPort: number): string;
11
+ export default function devExecutor(options: DevExecutorSchema, context: ExecutorContext): AsyncGenerator<{
12
+ success: boolean;
13
+ baseUrl?: string;
14
+ }>;
@@ -0,0 +1,32 @@
1
+ import { flags, projectRoot, resolverFrom, start } from "../run.js";
2
+ export function devStep(options, root, bin) {
3
+ return {
4
+ label: "vite (dev server)",
5
+ args: [
6
+ bin("vite"),
7
+ ...flags([
8
+ ["--config", options.config],
9
+ ["--mode", options.mode],
10
+ ["--port", options.port],
11
+ ["--host", options.host],
12
+ ["--strictPort", options.strictPort],
13
+ ["--open", options.open],
14
+ ]),
15
+ ],
16
+ cwd: root,
17
+ env: options.env ?? {},
18
+ };
19
+ }
20
+ /** `http://host:port` the server is expected on (Nx shows it; Vite prints the real one). */
21
+ export function baseUrl(options, fallbackPort) {
22
+ const host = typeof options.host === "string" ? options.host : "localhost";
23
+ return `http://${host}:${options.port ?? fallbackPort}`;
24
+ }
25
+ export default async function* devExecutor(options, context) {
26
+ const root = projectRoot(context);
27
+ const step = devStep(options, root, resolverFrom(root));
28
+ console.log(`> ${step.label}`);
29
+ const { exit } = start(step);
30
+ yield { success: true, baseUrl: baseUrl(options, 5173) };
31
+ return { success: (await exit) === 0 };
32
+ }
@@ -0,0 +1,16 @@
1
+ export interface DevExecutorSchema {
2
+ /** Port (`--port`); Vite's default 5173. */
3
+ port?: number;
4
+ /** Host to listen on (`--host`); `true` = all addresses. */
5
+ host?: string | boolean;
6
+ /** Fail when the port is taken instead of trying the next one. */
7
+ strictPort?: boolean;
8
+ /** Open the browser. */
9
+ open?: boolean;
10
+ /** Vite config file, relative to the project. */
11
+ config?: string;
12
+ /** Vite mode. */
13
+ mode?: string;
14
+ /** Extra environment variables. */
15
+ env?: Record<string, string>;
16
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "version": 2,
4
+ "title": "Rivet dev server",
5
+ "description": "Runs the Vite dev server of a Rivet app (pages render through the production request handler and resume; hot reload keeps state).",
6
+ "type": "object",
7
+ "properties": {
8
+ "port": { "type": "number", "description": "Port (--port); Vite's default is 5173." },
9
+ "host": { "oneOf": [{ "type": "string" }, { "type": "boolean" }], "description": "Host to listen on (--host); true listens on all addresses." },
10
+ "strictPort": { "type": "boolean", "description": "Fail when the port is taken instead of trying the next one." },
11
+ "open": { "type": "boolean", "description": "Open the browser." },
12
+ "config": { "type": "string", "description": "Vite config file, relative to the project." },
13
+ "mode": { "type": "string", "description": "Vite mode." },
14
+ "env": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Extra environment variables." }
15
+ },
16
+ "additionalProperties": false
17
+ }
@@ -0,0 +1,20 @@
1
+ import type { ExecutorContext } from "@nx/devkit";
2
+ import { type BinResolver, type Step } from "../run.js";
3
+ import type { PackageExecutorSchema } from "./schema.js";
4
+ export type { PackageExecutorSchema } from "./schema.js";
5
+ export interface NormalizedPackageOptions {
6
+ root: string;
7
+ out: string;
8
+ tsConfig: string;
9
+ sourceRoot: string;
10
+ assets: string[];
11
+ }
12
+ export declare function normalizePackageOptions(options: PackageExecutorSchema, workspaceRoot: string, root: string): NormalizedPackageOptions;
13
+ export declare function emitStep(options: NormalizedPackageOptions, bin: BinResolver): Step;
14
+ /** `./src/button/index.ts` → `./button/index.js` (types: `.d.ts`); `.tsx` → `.jsx`. */
15
+ export declare function mapPath(path: string, sourceRoot: string, types: boolean): string;
16
+ /** The published manifest of a library manifest. */
17
+ export declare function distManifest(pkg: Record<string, unknown>, sourceRoot: string): Record<string, unknown>;
18
+ export default function packageExecutor(options: PackageExecutorSchema, context: ExecutorContext): Promise<{
19
+ success: boolean;
20
+ }>;
@@ -0,0 +1,65 @@
1
+ // `@rivetjs/nx:package`: publishable Rivet library. `tsc -p tsconfig.lib.json` emits `.js` / `.jsx` (JSX preserved:
2
+ // the consuming app's Rivet compiler compiles it, like every `@rivetjs/*` package) and `.d.ts`; the manifest's
3
+ // source `exports` (`./src/x.ts`) are mapped to the emitted files and workspace-only fields dropped.
4
+ import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
5
+ import { join, relative, resolve } from "node:path";
6
+ import { projectRoot, resolverFrom, runSteps } from "../run.js";
7
+ export function normalizePackageOptions(options, workspaceRoot, root) {
8
+ return {
9
+ root,
10
+ out: resolve(workspaceRoot, options.outputPath ?? join("dist", relative(workspaceRoot, root))),
11
+ tsConfig: options.tsConfig ?? "tsconfig.lib.json",
12
+ sourceRoot: (options.sourceRoot ?? "src").replace(/^\.\//, "").replace(/\/$/, ""),
13
+ assets: options.assets ?? [],
14
+ };
15
+ }
16
+ export function emitStep(options, bin) {
17
+ return { label: `tsc -p ${options.tsConfig}`, args: [bin("typescript", "tsc"), "-p", options.tsConfig, "--outDir", options.out], cwd: options.root };
18
+ }
19
+ /** `./src/button/index.ts` → `./button/index.js` (types: `.d.ts`); `.tsx` → `.jsx`. */
20
+ export function mapPath(path, sourceRoot, types) {
21
+ const prefix = `./${sourceRoot}/`;
22
+ const inside = path.startsWith(prefix) ? "./" + path.slice(prefix.length) : path;
23
+ if (/\.d\.[cm]?ts$/.test(inside) || !/\.[cm]?tsx?$/.test(inside))
24
+ return inside;
25
+ if (types)
26
+ return inside.replace(/\.([cm]?)tsx?$/, ".d.$1ts");
27
+ return inside.replace(/\.([cm]?)ts$/, ".$1js").replace(/\.tsx$/, ".jsx");
28
+ }
29
+ function mapExports(value, sourceRoot, condition = "default") {
30
+ if (typeof value === "string")
31
+ return mapPath(value, sourceRoot, condition === "types");
32
+ if (!value)
33
+ return value;
34
+ return Object.fromEntries(Object.entries(value).map(([key, inner]) => [key, mapExports(inner, sourceRoot, key.startsWith(".") ? "default" : key)]));
35
+ }
36
+ /** The published manifest of a library manifest. */
37
+ export function distManifest(pkg, sourceRoot) {
38
+ const { private: _private, scripts: _scripts, devDependencies: _dev, nx: _nx, ...rest } = pkg;
39
+ const out = { ...rest };
40
+ if (pkg["exports"])
41
+ out["exports"] = mapExports(pkg["exports"], sourceRoot);
42
+ for (const field of ["main", "module"])
43
+ if (typeof pkg[field] === "string")
44
+ out[field] = mapPath(pkg[field], sourceRoot, false);
45
+ if (typeof pkg["types"] === "string")
46
+ out["types"] = mapPath(pkg["types"], sourceRoot, true);
47
+ return out;
48
+ }
49
+ export default async function packageExecutor(options, context) {
50
+ const root = projectRoot(context);
51
+ const normalized = normalizePackageOptions(options, context.root, root);
52
+ rmSync(normalized.out, { recursive: true, force: true });
53
+ mkdirSync(normalized.out, { recursive: true });
54
+ const emitted = await runSteps([emitStep(normalized, resolverFrom(root))]);
55
+ if (!emitted.success)
56
+ return emitted;
57
+ const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
58
+ writeFileSync(join(normalized.out, "package.json"), JSON.stringify(distManifest(pkg, normalized.sourceRoot), null, 2) + "\n");
59
+ for (const asset of ["README.md", "LICENSE", ...normalized.assets]) {
60
+ if (existsSync(join(root, asset)))
61
+ cpSync(join(root, asset), join(normalized.out, asset), { recursive: true });
62
+ }
63
+ console.log(`Packaged ${String(pkg["name"])} → ${relative(context.root, normalized.out)}`);
64
+ return { success: true };
65
+ }
@@ -0,0 +1,10 @@
1
+ export interface PackageExecutorSchema {
2
+ /** tsconfig of the emit, relative to the project. Default `tsconfig.lib.json`. */
3
+ tsConfig?: string;
4
+ /** Output folder, relative to the workspace root. Default `dist/<projectRoot>`. */
5
+ outputPath?: string;
6
+ /** Source folder the emit is rooted at (= the tsconfig's `rootDir`), relative to the project. Default `src`. */
7
+ sourceRoot?: string;
8
+ /** Extra files copied from the project (README.md and LICENSE are copied when present). */
9
+ assets?: string[];
10
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "version": 2,
4
+ "title": "Rivet library package",
5
+ "description": "Builds a publishable Rivet library: tsc emits .js / .jsx (JSX preserved for the consuming app's Rivet compiler) + .d.ts, then a package.json whose exports point at the emitted files.",
6
+ "type": "object",
7
+ "properties": {
8
+ "tsConfig": { "type": "string", "default": "tsconfig.lib.json", "description": "tsconfig of the emit, relative to the project." },
9
+ "outputPath": { "type": "string", "description": "Output folder, relative to the workspace root. Default dist/<projectRoot>." },
10
+ "sourceRoot": {
11
+ "type": "string",
12
+ "default": "src",
13
+ "description": "Source folder the emit is rooted at (the tsconfig's rootDir), relative to the project."
14
+ },
15
+ "assets": { "type": "array", "items": { "type": "string" }, "description": "Extra files copied from the project." }
16
+ },
17
+ "additionalProperties": false
18
+ }
@@ -0,0 +1,8 @@
1
+ import type { ExecutorContext } from "@nx/devkit";
2
+ import { type Step } from "../run.js";
3
+ import type { PrerenderExecutorSchema } from "./schema.js";
4
+ export type { PrerenderExecutorSchema } from "./schema.js";
5
+ export declare function prerenderStep(options: PrerenderExecutorSchema, root: string): Step;
6
+ export default function prerenderExecutor(options: PrerenderExecutorSchema, context: ExecutorContext): Promise<{
7
+ success: boolean;
8
+ }>;
@@ -0,0 +1,13 @@
1
+ // `@rivetjs/nx:prerender`: `prerenderBuild()` over an existing build (pipelines that split build and prerender;
2
+ // the `build` executor already prerenders static apps).
3
+ import { join } from "node:path";
4
+ import { prerenderCode } from "../build/executor.js";
5
+ import { projectRoot, runSteps } from "../run.js";
6
+ export function prerenderStep(options, root) {
7
+ if (options.script)
8
+ return { label: `node ${options.script}`, args: [join(root, options.script)], cwd: root };
9
+ return { label: "prerender", args: ["--input-type=module", "-e", prerenderCode(options.outputPath ?? "dist")], cwd: root };
10
+ }
11
+ export default async function prerenderExecutor(options, context) {
12
+ return runSteps([prerenderStep(options, projectRoot(context))]);
13
+ }
@@ -0,0 +1,6 @@
1
+ export interface PrerenderExecutorSchema {
2
+ /** Build output folder, relative to the project (holds `client/` + `server/`). Default `dist`. */
3
+ outputPath?: string;
4
+ /** Run the project's own script instead (relative to the project, e.g. `prerender.js`). */
5
+ script?: string;
6
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "version": 2,
4
+ "title": "Rivet prerender",
5
+ "description": "Renders every page of a built Rivet app to HTML files in <outputPath>/client (prerenderBuild of @rivetjs/router/static). Run after the client + server builds.",
6
+ "type": "object",
7
+ "properties": {
8
+ "outputPath": { "type": "string", "default": "dist", "description": "Build output folder, relative to the project (holds client/ and server/)." },
9
+ "script": { "type": "string", "description": "Run the project's own script instead (relative to the project, e.g. prerender.js)." }
10
+ },
11
+ "additionalProperties": false
12
+ }
@@ -0,0 +1,12 @@
1
+ import type { ExecutorContext } from "@nx/devkit";
2
+ import type { ProjectFacts } from "../../utils/detect.js";
3
+ import { type BinResolver, type Step } from "../run.js";
4
+ import type { PreviewExecutorSchema } from "./schema.js";
5
+ export type { PreviewExecutorSchema } from "./schema.js";
6
+ /** Node code of the router's production server over `dist`. */
7
+ export declare function startCode(dist: string): string;
8
+ export declare function previewStep(options: PreviewExecutorSchema, root: string, facts: ProjectFacts | undefined, bin: BinResolver, serverBuilt: boolean): Step;
9
+ export default function previewExecutor(options: PreviewExecutorSchema, context: ExecutorContext): AsyncGenerator<{
10
+ success: boolean;
11
+ baseUrl?: string;
12
+ }>;
@@ -0,0 +1,52 @@
1
+ // `@rivetjs/nx:preview`: serves the build (continuous target, depends on `build`). The project's own `serve.js`
2
+ // wins (starters ship one); a routed app without it runs `start()` of `@rivetjs/router/node`; anything else
3
+ // gets `vite preview`.
4
+ import { existsSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { projectFacts } from "../../utils/facts.js";
7
+ import { baseUrl } from "../dev/executor.js";
8
+ import { flags, projectRoot, resolverFrom, start } from "../run.js";
9
+ /** Node code of the router's production server over `dist`. */
10
+ export function startCode(dist) {
11
+ return (`import { closeOnSignals, start } from "@rivetjs/router/node";\n` +
12
+ `const serving = await start({ dist: ${JSON.stringify(dist)}, port: Number(process.env.PORT ?? 3000), host: process.env.HOST ?? "127.0.0.1" });\n` +
13
+ `closeOnSignals(serving);\n` +
14
+ `console.log("Listening on " + serving.url);\n`);
15
+ }
16
+ export function previewStep(options, root, facts, bin, serverBuilt) {
17
+ const dist = options.outputPath ?? "dist";
18
+ const env = { ...options.env };
19
+ if (options.port !== undefined)
20
+ env["PORT"] = String(options.port);
21
+ if (options.host !== undefined)
22
+ env["HOST"] = options.host;
23
+ if (facts?.serveScript && dist === "dist")
24
+ return { label: "node serve.js", args: [join(root, "serve.js")], cwd: root, env };
25
+ if (facts?.kind === "app" && serverBuilt)
26
+ return { label: "router node server", args: ["--input-type=module", "-e", startCode(dist)], cwd: root, env };
27
+ return {
28
+ label: "vite preview",
29
+ args: [
30
+ bin("vite"),
31
+ "preview",
32
+ ...flags([
33
+ ["--port", options.port],
34
+ ["--host", options.host],
35
+ ["--outDir", facts?.kind === "app" ? `${dist}/client` : undefined],
36
+ ]),
37
+ ],
38
+ cwd: root,
39
+ env: options.env ?? {},
40
+ };
41
+ }
42
+ export default async function* previewExecutor(options, context) {
43
+ const root = projectRoot(context);
44
+ const dist = options.outputPath ?? "dist";
45
+ const facts = projectFacts(root);
46
+ const step = previewStep(options, root, facts, resolverFrom(root), existsSync(join(root, dist, "server")));
47
+ console.log(`> ${step.label}`);
48
+ const { exit } = start(step);
49
+ // Starter defaults: static serve.js and vite preview 4173, server serve.js and the router server 3000.
50
+ yield { success: true, baseUrl: baseUrl(options, step.label === "vite preview" || facts?.static ? 4173 : 3000) };
51
+ return { success: (await exit) === 0 };
52
+ }
@@ -0,0 +1,10 @@
1
+ export interface PreviewExecutorSchema {
2
+ /** Port (`PORT` for the project's `serve.js` / the router's Node server, `--port` for `vite preview`). */
3
+ port?: number;
4
+ /** Host (`HOST` / `--host`). */
5
+ host?: string;
6
+ /** Build output folder, relative to the project. Default `dist`. */
7
+ outputPath?: string;
8
+ /** Extra environment variables. */
9
+ env?: Record<string, string>;
10
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "version": 2,
4
+ "title": "Rivet preview",
5
+ "description": "Serves a built Rivet app: the project's serve.js when it has one, else the router's Node server (@rivetjs/router/node start), else vite preview.",
6
+ "type": "object",
7
+ "properties": {
8
+ "port": { "type": "number", "description": "Port (PORT for serve.js / the Node server, --port for vite preview)." },
9
+ "host": { "type": "string", "description": "Host (HOST / --host)." },
10
+ "outputPath": { "type": "string", "default": "dist", "description": "Build output folder, relative to the project." },
11
+ "env": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Extra environment variables." }
12
+ },
13
+ "additionalProperties": false
14
+ }