๐Ÿงช Typed Routes

Stage: prototyping

Provides type safe way of building URLs within the application.

Installation

pnpm install github:QwikDev/qwik-labs-build#main
  1. update vite.config.ts
    // ...
    import { qwikTypes } from '@builder.io/qwik-labs/vite';
     
    export default defineConfig(() => {
      return {
        plugins: [
         // ...
         qwikTypes() // <== Add `qwikTypes()` to the list of plugins
        ],
        // ...
      };
    });
  2. Run build so that it generates ~/routes.gen.d.ts and ~/routes.config.tsx files.
  3. To create a typesafe link:
    import { AppLink } from '~/routes.config';
     
    export default component$(() => {
      // ...
      return (
        // ...
        <AppLink route="/your/[appParam]/link/" param:appParam={"some-value"}>
          Link text
        </AppLink>
      );
    });

Declarative Routing

This is a package originally created by Jack Herrington aka "The Blue Collar Coder" for type safe routing inside NextJS applications and has been adapted for use inside QwikCity

Installation

pnpm dlx declarative-routing init

Setup

The initialization process will create some important files for you.

.src/declarativeRoutes

  • makeRoute.ts - Used for defining page routes
  • index.ts - Where all of your route files will be imported from.
  • hooks.ts - A file with two custom hooks useParams & useSearchParams used to access type safe route urls, params, and searchParams

Each of your route directories

  • routeInfo.ts - Where you name the route, and provide a zod schema for the params and search (search params)

Usage

Declare Route Details

/src/routes/pokemon/[pokemonId]/routeInfo.ts
import { z } from "zod";
 
export const Route = {
  name: "PokemonDetail",
  params: z.object({
    pokemonId: z.coerce.number(),
  }),
};

Inside Component

There are a few different ways you can use Declarative Routes inside your component.

  1. Use RouteName.Link
myComponent.tsx
import { PokemonDetail } from "~/declarativeRoutes";
 
export default component$(() => {
  // ...
  return (
    // ...
    <PokemonDetail.Link pokemonId={1}>Bulbasaur</PokemonDetail.Link>
  );
});
  1. Use the standard Link and use the RouteName as a function to return the path
myComponent.tsx
import { Link } from "@builder.io/qwik-city";
import { PokemonDetail } from "~/declarativeRoutes";
 
export default component$(() => {
  // ...
  return (
    // ...
    <Link href={PokemonDetail({ pokemonId: 1 })}>Bulbasaur</Link>
  );
});
  1. Use RouteName.ParamsLink
myComponent.tsx
import { PokemonDetail } from "~/declarativeRoutes";
 
export default component$(() => {
  // ...
  return (
    // ...
    <PokemonDetail.ParamsLink params={{ pokemonId: 1 }}>Bulbasaur</PokemonDetail.ParamsLink>
  );
});
  1. Get the params from a RouteName
myComponent.tsx
import { PokemonDetail } from "~/declarativeRoutes";
 
export default component$(() => {
  // Typescript will know the correct params and their types
  const { pokemonId } = useParams(PokemonDetail);
  // ...
  return (
    // ...
  );
});

Add or Change Routes

If you add a new route, or move an existing route, simply run

pnpm dlx declarative-routing build

and this will rerun the process and update any changes needed

Contributors

Thanks to all the contributors who have helped make this documentation better!

  • mhevery
  • RumNCodeDev