{"id":25521075,"url":"https://github.com/rspack-contrib/rsbuild-plugin-react-router","last_synced_at":"2025-05-08T00:18:40.025Z","repository":{"id":275901520,"uuid":"925509769","full_name":"rspack-contrib/rsbuild-plugin-react-router","owner":"rspack-contrib","description":"A Rsbuild plugin that provides seamless integration with React Router","archived":false,"fork":false,"pushed_at":"2025-04-04T02:21:40.000Z","size":9313,"stargazers_count":106,"open_issues_count":7,"forks_count":5,"subscribers_count":15,"default_branch":"main","last_synced_at":"2025-05-08T00:18:34.846Z","etag":null,"topics":["reacr-router","react","rsbuild","rsbuild-plugin","rspack"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rspack-contrib.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-01T03:17:45.000Z","updated_at":"2025-05-07T12:12:35.000Z","dependencies_parsed_at":"2025-02-05T07:29:14.090Z","dependency_job_id":"ddb492dd-ef93-47a1-8015-777cddaaa839","html_url":"https://github.com/rspack-contrib/rsbuild-plugin-react-router","commit_stats":null,"previous_names":["rspack-contrib/rsbuild-plugin-react-router"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rspack-contrib%2Frsbuild-plugin-react-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rspack-contrib%2Frsbuild-plugin-react-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rspack-contrib%2Frsbuild-plugin-react-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rspack-contrib%2Frsbuild-plugin-react-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rspack-contrib","download_url":"https://codeload.github.com/rspack-contrib/rsbuild-plugin-react-router/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252973734,"owners_count":21834132,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["reacr-router","react","rsbuild","rsbuild-plugin","rspack"],"created_at":"2025-02-19T18:01:18.795Z","updated_at":"2025-05-08T00:18:39.997Z","avatar_url":"https://github.com/rspack-contrib.png","language":"TypeScript","readme":"# rsbuild-plugin-react-router\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://rsbuild.dev\" target=\"blank\"\u003e\u003cimg src=\"https://github.com/web-infra-dev/rsbuild/assets/7237365/84abc13e-b620-468f-a90b-dbf28e7e9427\" alt=\"Rsbuild Logo\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nA Rsbuild plugin that provides seamless integration with React Router, supporting both client-side routing and server-side rendering (SSR).\n\n## Features\n\n- 🚀 Zero-config setup with sensible defaults\n- 🔄 Automatic route generation from file system\n- 🖥️ Server-Side Rendering (SSR) support\n- 📱 Client-side navigation\n- 🛠️ TypeScript support out of the box\n- 🔧 Customizable configuration\n- 🎯 Support for route-level code splitting\n\n## Installation\n\n```bash\nnpm install rsbuild-plugin-react-router\n# or\nyarn add rsbuild-plugin-react-router\n# or\npnpm add rsbuild-plugin-react-router\n```\n\n## Usage\n\nAdd the plugin to your `rsbuild.config.ts`:\n\n```ts\nimport { defineConfig } from '@rsbuild/core';\nimport { pluginReactRouter } from 'rsbuild-plugin-react-router';\nimport { pluginReact } from '@rsbuild/plugin-react';\n\nexport default defineConfig(() =\u003e {\n  return {\n    plugins: [\n      pluginReactRouter({\n        // Optional: Enable custom server mode\n        customServer: false,\n        // Optional: Specify server output format\n        serverOutput: \"commonjs\",\n        //Optional: enable experimental support for module federation\n        federation: false\n      }), \n      pluginReact()\n    ],\n  };\n});\n```\n\n## Configuration\n\nThe plugin uses a two-part configuration system:\n\n1. **Plugin Options** (in `rsbuild.config.ts`):\n```ts\npluginReactRouter({\n  /**\n   * Whether to disable automatic middleware setup for custom server implementation.\n   * Enable this when you want to handle server setup manually.\n   * @default false\n   */\n  customServer?: boolean,\n\n  /**\n   * Specify the output format for server-side code.\n   * Options: \"commonjs\" | \"module\"\n   * @default \"module\"\n   */\n  serverOutput?: \"commonjs\" | \"module\"\n  /**\n   * Enable experimental support for module federation\n   * @default false\n   */\n  federation?: boolean\n})\n```\n\n2. **React Router Configuration** (in `react-router.config.ts`):\n```ts\nimport type { Config } from '@react-router/dev/config';\n\nexport default {\n  /**\n   * Whether to enable Server-Side Rendering (SSR) support.\n   * @default true\n   */\n  ssr: true,\n\n  /**\n   * Build directory for output files\n   * @default 'build'\n   */\n  buildDirectory: 'dist',\n\n  /**\n   * Application source directory\n   * @default 'app'\n   */\n  appDirectory: 'app',\n\n  /**\n   * Base URL path\n   * @default '/'\n   */\n  basename: '/my-app',\n} satisfies Config;\n```\n\nAll configuration options are optional and will use sensible defaults if not specified.\n\n### Default Configuration Values\n\nIf no configuration is provided, the following defaults will be used:\n\n```ts\n// Plugin defaults (rsbuild.config.ts)\n{\n  customServer: false\n}\n\n// Router defaults (react-router.config.ts)\n{\n  ssr: true,\n  buildDirectory: 'build',\n  appDirectory: 'app',\n  basename: '/'\n}\n```\n\n### Route Configuration\n\nRoutes can be defined in `app/routes.ts` using the helper functions from `@react-router/dev/routes`:\n\n```ts\nimport {\n  type RouteConfig,\n  index,\n  layout,\n  prefix,\n  route,\n} from '@react-router/dev/routes';\n\nexport default [\n  // Index route for the home page\n  index('routes/home.tsx'),\n\n  // Regular route\n  route('about', 'routes/about.tsx'),\n\n  // Nested routes with a layout\n  layout('routes/docs/layout.tsx', [\n    index('routes/docs/index.tsx'),\n    route('getting-started', 'routes/docs/getting-started.tsx'),\n    route('advanced', 'routes/docs/advanced.tsx'),\n  ]),\n\n  // Routes with dynamic segments\n  ...prefix('projects', [\n    index('routes/projects/index.tsx'),\n    layout('routes/projects/layout.tsx', [\n      route(':projectId', 'routes/projects/project.tsx'),\n      route(':projectId/edit', 'routes/projects/edit.tsx'),\n    ]),\n  ]),\n] satisfies RouteConfig;\n```\n\nThe plugin provides several helper functions for defining routes:\n- `index()` - Creates an index route\n- `route()` - Creates a regular route with a path\n- `layout()` - Creates a layout route with nested children\n- `prefix()` - Adds a URL prefix to a group of routes\n\n### Route Components\n\nRoute components support the following exports:\n\n#### Client-side Exports\n- `default` - The route component\n- `ErrorBoundary` - Error boundary component\n- `HydrateFallback` - Loading component during hydration\n- `Layout` - Layout component\n- `clientLoader` - Client-side data loading\n- `clientAction` - Client-side form actions\n- `handle` - Route handle\n- `links` - Prefetch links\n- `meta` - Route meta data\n- `shouldRevalidate` - Revalidation control\n\n#### Server-side Exports\n- `loader` - Server-side data loading\n- `action` - Server-side form actions\n- `headers` - HTTP headers\n\n## Custom Server Setup\n\nThe plugin supports two ways to handle server-side rendering:\n\n1. **Default Server Setup**: By default, the plugin automatically sets up the necessary middleware for SSR.\n\n2. **Custom Server Setup**: For more control, you can disable the automatic middleware setup by enabling custom server mode:\n\n```ts\n// rsbuild.config.ts\nimport { defineConfig } from '@rsbuild/core';\nimport { pluginReactRouter } from 'rsbuild-plugin-react-router';\nimport { pluginReact } from '@rsbuild/plugin-react';\n\nexport default defineConfig(() =\u003e {\n  return {\n    plugins: [\n      pluginReactRouter({\n        customServer: true\n      }), \n      pluginReact()\n    ],\n  };\n});\n```\n\nWhen using a custom server, you'll need to:\n\n1. Create a server handler (`server/index.ts`):\n```ts\nimport { createRequestHandler } from '@react-router/express';\n\nexport const app = createRequestHandler({\n  build: () =\u003e import('virtual/react-router/server-build'),\n  getLoadContext() {\n    // Add custom context available to your loaders/actions\n    return {\n      // ... your custom context\n    };\n  },\n});\n```\n\n2. Set up your server entry point (`server.js`):\n```js\nimport { createRsbuild, loadConfig } from '@rsbuild/core';\nimport express from 'express';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst app = express();\nconst isDev = process.env.NODE_ENV !== 'production';\n\nasync function startServer() {\n  if (isDev) {\n    const config = await loadConfig();\n    const rsbuild = await createRsbuild({\n      rsbuildConfig: config.content,\n    });\n    const devServer = await rsbuild.createDevServer();\n    app.use(devServer.middlewares);\n\n    app.use(async (req, res, next) =\u003e {\n      try {\n        const bundle = await devServer.environments.node.loadBundle('app');\n        await bundle.app(req, res, next);\n      } catch (e) {\n        next(e);\n      }\n    });\n\n    const port = Number.parseInt(process.env.PORT || '3000', 10);\n    const server = app.listen(port, () =\u003e {\n      console.log(`Development server is running on http://localhost:${port}`);\n      devServer.afterListen();\n    });\n    devServer.connectWebSocket({ server });\n  } else {\n    // Production mode\n    app.use(express.static(path.join(__dirname, 'build/client'), {\n      index: false\n    }));\n\n    // Load the server bundle\n    const serverBundle = await import('./build/server/static/js/app.js');\n    // Mount the server app after static file handling\n    app.use(async (req, res, next) =\u003e {\n      try {\n        await serverBundle.default.app(req, res, next);\n      } catch (e) {\n        next(e);\n      }\n    });\n\n    const port = Number.parseInt(process.env.PORT || '3000', 10);\n    app.listen(port, () =\u003e {\n      console.log(`Production server is running on http://localhost:${port}`);\n    });\n  }\n}\n\nstartServer().catch(console.error);\n```\n\n3. Update your `package.json` scripts:\n```json\n{\n  \"scripts\": {\n    \"dev\": \"node server.js\",\n    \"build\": \"rsbuild build\",\n    \"start\": \"NODE_ENV=production node server.js\"\n  }\n}\n```\n\nThe custom server setup allows you to:\n- Add custom middleware\n- Handle API routes\n- Integrate with databases\n- Implement custom authentication\n- Add server-side caching\n- And more!\n\n## Cloudflare Workers Deployment\n\nTo deploy your React Router app to Cloudflare Workers:\n\n1. **Configure Rsbuild** (`rsbuild.config.ts`):\n```ts\nimport { defineConfig } from '@rsbuild/core';\nimport { pluginReact } from '@rsbuild/plugin-react';\nimport { pluginReactRouter } from 'rsbuild-plugin-react-router';\n\nexport default defineConfig({\n  environments: {\n    node: {\n      performance: {\n        chunkSplit: { strategy: 'all-in-one' },\n      },\n      tools: {\n        rspack: {\n          experiments: { outputModule: true },\n          externalsType: 'module',\n          output: {\n            chunkFormat: 'module',\n            chunkLoading: 'import',\n            workerChunkLoading: 'import',\n            wasmLoading: 'fetch',\n            library: { type: 'module' },\n            module: true,\n          },\n          resolve: {\n            conditionNames: ['workerd', 'worker', 'browser', 'import', 'require'],\n          },\n        },\n      },\n    },\n  },\n  plugins: [pluginReactRouter({customServer: true}), pluginReact()],\n});\n```\n\n2. **Configure Wrangler** (`wrangler.toml`):\n```toml\nworkers_dev = true\nname = \"my-react-router-worker\"\ncompatibility_date = \"2024-11-18\"\nmain = \"./build/server/static/js/app.js\"\nassets = { directory = \"./build/client/\" }\n\n[vars]\nVALUE_FROM_CLOUDFLARE = \"Hello from Cloudflare\"\n\n# Optional build configuration\n# [build]\n# command = \"npm run build\"\n# watch_dir = \"app\"\n```\n\n3. **Create Worker Entry** (`server/index.ts`):\n```ts\nimport { createRequestHandler } from 'react-router';\n\ndeclare global {\n  interface CloudflareEnvironment extends Env {}\n  interface ImportMeta {\n    env: {\n      MODE: string;\n    };\n  }\n}\n\ndeclare module 'react-router' {\n  export interface AppLoadContext {\n    cloudflare: {\n      env: CloudflareEnvironment;\n      ctx: ExecutionContext;\n    };\n  }\n}\n\n// @ts-expect-error - virtual module provided by React Router at build time\nimport * as serverBuild from 'virtual/react-router/server-build';\n\nconst requestHandler = createRequestHandler(serverBuild, import.meta.env.MODE);\n\nexport default {\n  fetch(request, env, ctx) {\n    return requestHandler(request, {\n      cloudflare: { env, ctx },\n    });\n  },\n} satisfies ExportedHandler\u003cCloudflareEnvironment\u003e;\n```\n\n4. **Update Package Dependencies**:\n```json\n{\n  \"dependencies\": {\n    \"@react-router/node\": \"^7.1.3\",\n    \"@react-router/serve\": \"^7.1.3\",\n    \"react-router\": \"^7.1.3\"\n  },\n  \"devDependencies\": {\n    \"@cloudflare/workers-types\": \"^4.20241112.0\",\n    \"@react-router/cloudflare\": \"^7.1.3\",\n    \"@react-router/dev\": \"^7.1.3\",\n    \"wrangler\": \"^3.106.0\"\n  }\n}\n```\n\n5. **Setup Deployment Scripts** (`package.json`):\n```json\n{\n  \"scripts\": {\n    \"build\": \"rsbuild build\",\n    \"deploy\": \"npm run build \u0026\u0026 wrangler deploy\",\n    \"dev\": \"rsbuild dev\",\n    \"start\": \"wrangler dev\"\n  }\n}\n```\n\n### Key Configuration Notes:\n\n- The `workers_dev = true` setting enables deployment to workers.dev subdomain\n- `main` points to your Worker's entry point in the build output\n- `assets` directory specifies where your static client files are located\n- Environment variables can be set in the `[vars]` section\n- The `compatibility_date` should be kept up to date\n- TypeScript types are provided via `@cloudflare/workers-types`\n- Development can be done locally using `wrangler dev`\n- Deployment is handled through `wrangler deploy`\n\n### Development Workflow:\n\n1. Local Development:\n   ```bash\n   # Start local development server\n   npm run dev\n   # or\n   npm start\n   ```\n\n2. Production Deployment:\n   ```bash\n   # Build and deploy\n   npm run deploy\n   ```\n\n## Development\n\nThe plugin automatically:\n- Runs type generation during development and build\n- Sets up development server with live reload\n- Handles route-based code splitting\n- Manages client and server builds\n\n## License\n\nMIT\n","funding_links":[],"categories":["Plugins"],"sub_categories":["Rsbuild Plugins"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frspack-contrib%2Frsbuild-plugin-react-router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frspack-contrib%2Frsbuild-plugin-react-router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frspack-contrib%2Frsbuild-plugin-react-router/lists"}