UNPKG

workflow

Version:

Workflow SDK - Build durable, resilient, and observable workflows

222 lines (153 loc) • 4.74 kB
--- title: React Router v7 description: Add durable workflows to a React Router v7 framework-mode app using Nitro v3. type: guide summary: Enable the Vite Environment API and configure React Router v7, Nitro v3, and Workflow SDK. prerequisites: - /docs/getting-started/react-router related: - /docs/getting-started/nitro - /docs/foundations/workflows-and-steps --- This guide starts with an existing React Router v7 framework-mode app. It is verified with v7.18.1; if your config does not recognize `v8_viteEnvironmentApi`, update to the latest v7 release. <Steps> <Step> ## Install Nitro and Workflow SDK <CodeBlockTabs defaultValue="pnpm"> ```bash tab="npm" npm install nitro workflow ``` ```bash tab="pnpm" pnpm add nitro workflow ``` ```bash tab="bun" bun add nitro workflow ``` ```bash tab="yarn" yarn add nitro workflow ``` </CodeBlockTabs> This integration requires Nitro v3. </Step> <Step> ## Enable the Vite Environment API React Router v7 keeps the Vite Environment API behind a future flag. Enable the required flag and set an explicit build directory: ```typescript title="react-router.config.ts" lineNumbers import type { Config } from "@react-router/dev/config"; export default { ssr: true, buildDirectory: "build", // [!code highlight] future: { v8_viteEnvironmentApi: true, // [!code highlight] }, } satisfies Config; ``` </Step> <Step> ## Create the React Router server handler Create `server/ssr.ts`: ```typescript title="server/ssr.ts" lineNumbers import { createRequestHandler } from "react-router"; export default { fetch: createRequestHandler( () => import("virtual:react-router/server-build"), import.meta.env.MODE, ), }; ``` This adapts React Router's generated server build to the Fetch API handler Nitro expects. </Step> <Step> ## Configure Vite Update `vite.config.ts`: ```typescript title="vite.config.ts" lineNumbers import { reactRouter } from "@react-router/dev/vite"; import { nitro } from "nitro/vite"; import { defineConfig } from "vite"; import { workflow } from "workflow/vite"; import reactRouterConfig from "./react-router.config"; export default defineConfig({ plugins: [ reactRouter(), nitro({ serverDir: "./server", output: { dir: reactRouterConfig.buildDirectory, serverDir: `${reactRouterConfig.buildDirectory}/server`, publicDir: `${reactRouterConfig.buildDirectory}/client`, }, }), workflow({ dirs: ["workflows"] }), ], environments: { ssr: { build: { rollupOptions: { input: "./server/ssr.ts", }, }, }, }, }); ``` Keep `dirs: ["workflows"]` so subsequent builds do not scan generated files under `build`. Place `reactRouter()` before `nitro()` in the plugin array. </Step> <Step> ## Create a workflow Create `workflows/greeting.ts`: ```typescript title="workflows/greeting.ts" lineNumbers export async function greetingWorkflow(name: string) { "use workflow"; return greet(name); } async function greet(name: string) { "use step"; return `Hello, ${name}!`; } ``` </Step> <Step> ## Start the workflow from a Nitro route Create `server/routes/api/greeting.post.ts`: ```typescript title="server/routes/api/greeting.post.ts" lineNumbers import { defineHandler } from "nitro"; import { start } from "workflow/api"; import { greetingWorkflow } from "../../../workflows/greeting"; export default defineHandler(async (event) => { const { name } = (await event.req.json()) as { name: string }; const run = await start(greetingWorkflow, [name]); return { runId: run.runId }; }); ``` React Router continues to handle your application routes. Nitro handles this server route at `POST /api/greeting`, as well as Workflow SDK's internal routes. </Step> <Step> ## Run the app Start the development server: ```bash pnpm vite dev ``` Then start a workflow: ```bash curl -X POST \ -H "content-type: application/json" \ -d '{"name":"Workflow"}' \ http://localhost:3000/api/greeting ``` Build and start the production server: ```bash pnpm vite build node ./build/server/index.mjs ``` You can inspect local runs with `pnpm workflow web`. </Step> </Steps> ## Troubleshooting ### Vite reports an invalid SSR input or `path.replace is not a function` Set `future.v8_viteEnvironmentApi` to `true` in `react-router.config.ts`. ### React Router pages return 404 Check that the `ssr` environment input points to `./server/ssr.ts`. ### A second build tries to compile files under `build/server` Use `workflow({ dirs: ["workflows"] })`, remove the existing `build` directory once, and rebuild. ### `vite build` finishes output but does not exit Use `workflow@5.0.0` or later with Nitro v3.