oedotme / generouted

Generated file-based routes for Vite
https://stackblitz.com/github.com/oedotme/generouted/tree/main/explorer
MIT License
1.04k stars 48 forks source link
actions code-splitting data-loaders file-based-routing generate nested-layouts nextjs pages pre-loading react react-location react-router react-router-dom remix router routes solid solid-router typescript vite


generouted


Generouted

Generated file-based routes for Vite

Motivation
I enjoyed using file-based routing since I tried Next.js (pages directory). After applying the same concept with Vite and client-side applications, I started writing blog posts covering the implementation of [client-side file-based routing with React Router](https://omarelhawary.me/blog/file-based-routing-with-react-router) which was packaged later as `generouted`. Today `generouted` brings many features, supports multiple frameworks and routers, and inspires ideas and conventions from Next.js, Remix, Expo, Docusaurus, SvelteKit and more.
How does it work?
`generouted` uses [Vite's glob import API](https://vitejs.dev/guide/features.html#glob-import) to list the routes within the `src/pages` directory and generates the routes tree and modals based on `generouted`'s conventions. There are also Vite plugins available for some integrations to provide type-safe components/hooks/utils through code-generation.


Features


Online explorer


Getting started

React Router ### React Router In case you don't have a Vite project with React and TypeScript, check [Vite documentation to start a new project](https://vitejs.dev/guide/#scaffolding-your-first-vite-project). #### Installation ```shell pnpm add @generouted/react-router react-router-dom ``` #### Setup ```ts // vite.config.ts import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import generouted from '@generouted/react-router/plugin' export default defineConfig({ plugins: [react(), generouted()] }) ``` #### Usage ```tsx // src/main.tsx import { createRoot } from 'react-dom/client' import { Routes } from '@generouted/react-router' createRoot(document.getElementById('root')!).render() ``` #### Adding pages Add the home page by creating a new file `src/pages/index.tsx` โ†’ `/`, then export a default component: ```tsx export default function Home() { return

Home

} ``` Check the [routing conventions section below](#conventions). #### Docs You can find more details about type-safe navigation and global modals at [`@generouted/react-router` docs](/packages/react-router). #### Examples - [Type-safe navigation + global modals](/examples/react-router) - [Custom integration](/examples/react-router-custom) - [Custom integration with custom path](/examples/react-router-custom-path) - [MDX routes](/examples/react-router-mdx)
Solid Router ### Solid Router In case you don't have a Vite project with Solid and TypeScript, check [Vite documentation to start a new project](https://vitejs.dev/guide/#scaffolding-your-first-vite-project). #### Installation ```shell pnpm add @generouted/solid-router @solidjs/router ``` #### Setup ```ts // vite.config.ts import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' import generouted from '@generouted/solid-router/plugin' export default defineConfig({ plugins: [solid(), generouted()] }) ``` #### Usage ```tsx // src/main.tsx import { render } from 'solid-js/web' import { Routes } from '@generouted/solid-router' render(Routes, document.getElementById('root')!) ``` #### Adding pages Add the home page by creating a new file `src/pages/index.tsx` โ†’ `/`, then export a default component: ```tsx export default function Home() { return

Home

} ``` See more about `generouted` [routing conventions below](#conventions). #### Docs You can find more details about type-safe navigation and global modals at [`@generouted/solid-router` docs](/packages/solid-router). #### Examples - [Type-safe navigation + global modals](/examples/solid-router)
TanStack React Router โ€” In-progress experimental support ๐Ÿงช ### TanStack React Router โ€” In-progress experimental support ๐Ÿงช [Check out the docs here](/packages/tanstack-react-router) #### Examples - [Basic](/examples/tanstack-react-router)
React Location โ€” Deprecated ๐Ÿšจ ### React Location โ€” Deprecated ๐Ÿšจ In case you don't have a Vite project with React and TypeScript, check [Vite documentation to start a new project](https://vitejs.dev/guide/#scaffolding-your-first-vite-project). #### Installation ```shell pnpm add generouted @tanstack/react-location ``` #### Usage ```tsx // src/main.tsx import { createRoot } from 'react-dom/client' import { Routes } from 'generouted/react-location' createRoot(document.getElementById('root')!).render() ``` #### Adding pages Add the home page by creating a new file `src/pages/index.tsx` โ†’ `/`, then export a default component: ```tsx export default function Home() { return

Home

} ``` #### Examples - [Basic](/examples/react-location/basic) - [Data loaders](/examples/react-location/data-loaders) - [Modals](/examples/react-location/modals) - [Nested layouts](/examples/react-location/nested-layouts)


Conventions

File and directories naming and conventions

Index routes

Nested routes

Dynamic routes

Nested layouts

Nested URLs without nested layouts

Pathless layouts

Global modals

Optional segments

Ignored routes


Page exports


Example

Directory structure
```shell src/pages โ”œโ”€โ”€ (auth) โ”‚ โ”œโ”€โ”€ _layout.tsx โ”‚ โ”œโ”€โ”€ login.tsx โ”‚ โ””โ”€โ”€ register.tsx โ”œโ”€โ”€ blog โ”‚ โ”œโ”€โ”€ _components โ”‚ โ”‚ โ”œโ”€โ”€ button.tsx โ”‚ โ”‚ โ””โ”€โ”€ comments.tsx โ”‚ โ”œโ”€โ”€ [...all].tsx โ”‚ โ”œโ”€โ”€ [slug].tsx โ”‚ โ”œโ”€โ”€ _layout.tsx โ”‚ โ”œโ”€โ”€ index.tsx โ”‚ โ””โ”€โ”€ tags.tsx โ”œโ”€โ”€ docs โ”‚ โ”œโ”€โ”€ -[lang] โ”‚ โ”‚ โ”œโ”€โ”€ index.tsx โ”‚ โ”‚ โ””โ”€โ”€ resources.tsx โ”‚ โ””โ”€โ”€ -en โ”‚ โ””โ”€โ”€ contributors.tsx โ”œโ”€โ”€ +info.tsx โ”œโ”€โ”€ 404.tsx โ”œโ”€โ”€ _app.tsx โ”œโ”€โ”€ _ignored.tsx โ”œโ”€โ”€ about.tsx โ”œโ”€โ”€ blog.w.o.layout.tsx โ””โ”€โ”€ index.tsx ```
Overview
| File | Path | Convention | | :------------------------------ | :----------------------- | :------------------------------------ | | `(auth)/_layout.tsx` | | Pathless Layout group | | `(auth)/login.tsx` | `/login` | Regular route | | `(auth)/register.tsx` | `/register` | Regular route | | `blog/_components/button.tsx` | | Ignored route by an ignored directory | | `blog/_components/comments.tsx` | | Ignored route by an ignored directory | | `blog/[...all].tsx` | `/blog/*` | Dynamic catch-all route | | `blog/[slug].tsx` | `/blog/:slug` | Dynamic route | | `blog/_layout.tsx` | | Layout for `/blog` routes | | `blog/index.tsx` | `/blog` | Index route | | `blog/tags.tsx` | `/blog/tags` | Regular route | | `docs/-[lang]/index.tsx` | `/docs/:lang?/index` | Optional dynamic route segment | | `docs/-[lang]/resources.tsx` | `/docs/:lang?/resources` | Optional dynamic route segment | | `docs/-en/contributors.tsx` | `/docs/en?/contributors` | Optional static route segment | | `+info.tsx` | `/info` | Modal route | | `404.tsx` | `*` | Custom `404` _(optional)_ | | `_app.tsx` | | Custom `app` layout _(optional)_ | | `_ignored.tsx` | | Ignored route | | `about.tsx` | `/about` | Regular route | | `blog.w.o.layout.tsx` | `/blog/w/o/layout` | Route without `/blog` layout | | `index.tsx` | `/` | Index route |


API

Routing

Via @generouted/react-router or @generouted/solid-router

Routing + code-splitting and lazy-loading

Via @generouted/react-router/lazy or @generouted/solid-router/lazy

Plugins

Via @generouted/react-router/plugin or @generouted/solid-router/plugin

Core

Via @generouted/react-router/core or @generouted/solid-router/core


FAQ

How to implement protected or guarded routes?
There are multiple approaches to achieve that. If you prefer handling the logic in one place, you can define the protected routes with redirection handling within a component: ```tsx // src/config/redirects.tsx import { Navigate, useLocation } from 'react-router-dom' import { useAuth } from '../context/auth' import { Path } from '../router' const PRIVATE: Path[] = ['/logout'] const PUBLIC: Path[] = ['/login'] export const Redirects = ({ children }: { children: React.ReactNode }) => { const auth = useAuth() const location = useLocation() const authenticatedOnPublicPath = auth.active && PUBLIC.includes(location.pathname as Path) const unAuthenticatedOnPrivatePath = !auth.active && PRIVATE.includes(location.pathname as Path) if (authenticatedOnPublicPath) return if (unAuthenticatedOnPrivatePath) return return children } ``` Then use that component (`` ) at the root-level layout `src/pages/_app.tsx` to wrap the `` component: ```tsx // src/pages/_app.tsx import { Outlet } from 'react-router-dom' import { Redirects } from '../config/redirects' export default function App() { return (
) } ``` You can find a full example of this approach at [Render template](https://github.com/oedotme/render/blob/main/src/config/redirects.tsx)
How to use with Hash or Memory Routers?
You can use the exported `routes` object to customize the router or to use hash/memory routers: ```tsx import { createRoot } from 'react-dom/client' import { RouterProvider, createHashRouter } from 'react-router-dom' import { routes } from '@generouted/react-router' const router = createHashRouter(routes) const Routes = () => createRoot(document.getElementById('root')!).render() ```


License

MIT