declarative-routing

repository·main·Indexed 42 days ago

https://github.com/pronextjs/declarative-routing

A typesafe and declarative routing system for NextJS, React Router, and QwikCity projects. It automates URL generation via route-tied components, providing typesafe Link components, fetch wrapping functions for API routes, and typed hooks (usePush, useParams, useSearchParams) to access routing data safely. Version 0.1.20.

Tokens
14.3K
Snippets
55
Records
68
Agent score
53%

What's inside declarative-routing

  1. Customize the routing system via makeRoute.tsx

    main

    The makeRoute.tsx file is copied into your ~/declarativeRoutes module during setup. This allows you to own and customize the routing implementation (for example, changing how the .Link component behaves).

    Warning: Do not change the parameters of the makeRoute function, as this will break compatibility with the declarative-routing build command.

  2. Customize the routing system by modifying makeRoute.tsx

    main

    The makeRoute.tsx file is copied into your ~/declarativeRoutes directory during initialization. This allows you to own and customize the routing logic (e.g., changing how the Link component behaves) without modifying the core package.

    Warning: Do not change the parameters of the makeRoute function, as this will break compatibility with the declarative-routing build command.

  3. What are Declarative Routes?

    main

    Declarative routing is a typesafe routing system that moves beyond simple URL validation. While typesafe routing ensures parameters and route handlers are correct, declarative routing ensures your navigation components (like links) are automatically synchronized with your route structure.

    Instead of manually constructing URL strings like <Link to={/product/${product.id}}>, you use route-specific components that are typed to the route itself, such as <ProductDetail.Link productId={product.id}>. If a route path or its required parameters change, the component automatically reflects these changes throughout your application, preventing broken links.

    // Traditional typesafe routing (manual URL construction)
    <Link to={`/product/${product.id}`}>Product</Link>
    
    // Declarative routing (automatic URL generation via typed components)
    <ProductDetail.Link productId={product.id}>Product</ProductDetail.Link>
  4. Understand the Qwik City project structure

    main

    This project uses Qwik with QwikCity for directory-based routing and layouts. The core directory structure is as follows:

    • src/routes: Contains the directory-based routing logic. This includes layout.tsx files for defining hierarchies and index.tsx files for pages. index.ts files are used to define endpoints.
    • src/components: The recommended location for reusable components.
    • public: A directory for static assets like images.
  5. How the automated build option works

    main

    The build command automates route generation by scanning your .src/routes/ directory for index.tsx files.

    1. For every index.tsx, it generates a routeInfo.ts file in the same directory.
    2. It imports these routeInfo.ts files into ~/declarativeRoutes/index.ts.
    3. It generates makeRoute invocations inside ~/declarativeRoutes/index.ts so all routes are available from a single entry point.

    Manual Edits: You should manually edit routeInfo.ts files to add search schemas if a page supports search parameters. The build command will not automatically detect search schema changes, but it will maintain the link between the route and the central index.

  6. How the automated build process works

    main

    The build command automates route generation by scanning page.tsx and route.tsx files in your directory.

    1. It generates a corresponding .info.ts file (e.g., page.info.ts or route.info.ts) in the same directory as the route file.
    2. It imports these .info.ts files into @/routes/index.ts.
    3. @/routes/index.ts then exports all routes, allowing them to be imported by components throughout your app.

    Note: You should manually edit .info.ts files to add search schemas for pages or result/body schemas for API routes.

  7. Initialize Declarative Routes in a React-Router project

    main

    To set up declarative routing in an existing React-Router project, follow these steps:

    1. Pull the starter: Use the starter folder as a base.
    2. Run initialization: Execute the following command in your terminal:
      npx declarative-routing init
    3. Configure route directory: When prompted, specify the location of your routes. The default is ./src/routes, which is the standard directory for React-Router.

    This process generates helper files in your routes directory, including index.ts for manual route creation and makeRoute.tsx for creating route objects for pages and APIs.

    npx declarative-routing init
  8. Initialize Declarative Routes in QwikCity

    main

    To set up typesafe routing in a QwikCity project, follow these steps:

    1. Pull the starter folder from the repository.
    2. Run the initialization command: npx declarative-routing init
    3. When prompted, provide the path to your routes directory (defaults to ./src/routes).
    4. Provide the path where you want to place the generated declarative route files (defaults to ./src/declarativeRoutes).

    This process generates a directory containing hooks.ts (providing hooks for params and search params) and index.ts (exporting route objects like HomeRoute, SearchRoute, etc.).

    npx declarative-routing init
  9. Initialize declarative-routing in a NextJS application

    main

    To set up declarative routing in an existing NextJS project, run the initialization command. This process generates a dedicated routes directory (defaulting to ./src/routes, though you can specify a custom location during the interactive installation) which serves as the source of truth for your typesafe navigation. The initialization also creates a README.md within the routes directory containing specific instructions for your generated routing structure.

    npx declarative-routing init
  10. Initialize Declarative Routes in NextJS

    main

    To set up declarative routing in a NextJS project, follow these steps:

    1. Pull the starter folder into your project.
    2. Run the initialization command: npx declarative-routing init

    During initialization, you will be prompted for:

    • Routes directory: Defaults to ./src/routes (the standard NextJS location).
    • Declarative routes file location: Defaults to ./src/routes.
    • OpenAPI usage: It is currently suggested to select No.

    After initialization, the following files are generated in ./src/routes:

    • hooks.ts: Contains hooks for accessing route parameters and search parameters.
    • index.ts: Exports the route objects (e.g., Home, Search, PokemonPokemonId).
    • makeRoute.tsx: A helper function for creating route objects for both page and API routes.
    npx declarative-routing init
  11. Install and initialize declarative-routing in QwikCity

    main

    To start using the system in a QwikCity application, run the initialization command. This creates a ~/declarativeRoutes directory containing your route definitions and a README.md guide.

    When you add new pages or change route paths, you must run the build command to synchronize the ~/declarativeRoutes directory with your actual file structure.

    # Initialize the routing system
    npx declarative-routing init
    
    # Update routes after adding pages or changing paths
    npx declarative-routing build
  12. Define Route Schemas with routeInfo.ts

    main

    Each route in your project should have a corresponding routeInfo.ts file to define its schema using Zod. This schema controls the types for path parameters (params) and URL search parameters (search).

    Defining Search Parameters

    For routes like /search that use query strings, use the search key in the Route object:

    export const Route = {
      name: "Search",
      params: z.object({}),
      search: z.object({
        q: z.string().optional(),
        limit: z.coerce.number().optional()
      })
    };

    Defining Path Parameters

    For dynamic routes like /pokemon/[pokemonId], use the params key:

    export const Route = {
      name: "PokemonPokemonId",
      params: z.object({
        pokemonId: z.coerce.number()
      })
    };

    Note: You can customize the exported name of the route object by changing the name key in routeInfo.ts. After changing the name, run pnpm dr:build to regenerate the files.