Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .notes/justin/worklogs/2025-10-09-add-define-links-docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# 2025-10-09: Add defineLinks Documentation

## Problem

The `defineLinks` function is a useful utility for creating type-safe links, but it is not documented. This makes it hard for users to discover and understand its purpose.

## Plan

1. Create a new section in `docs/src/content/docs/core/routing.mdx` called "Generating Links".
2. Explain the purpose of `defineLinks`: centralized route definition, type safety, and dynamic parameter handling.
3. Include code examples for each of these points.
4. Add an API reference for `defineLinks` within the new section.
5. Keep the style consistent with the rest of the document.
6. Update the API reference to be more descriptive, following the style of `renderToStream` in `react-server-components.mdx`.
7. Move the "Generating Links" section to the end of the document.

## Create Conditional Router Entry Points

### Problem

The `rwsdk/router` module includes server-side routing logic that is unnecessary in the client bundle. We need to provide a client-specific entry point that only exports `defineLinks` to reduce bundle size.

### Plan

1. Create a client-specific entry point for the router at `sdk/src/runtime/entries/routerClient.ts` that only exports `defineLinks`.
2. Update `sdk/package.json` to:
- Add the new client entry point to the `tsup` build configuration.
- Modify the `exports` map for `"./router"` to use conditional exports. The `workerd` condition will point to the full router, and the `default` condition will point to the client-specific bundle.
3. Update `sdk/src/vite/configPlugin.mts` to add `"rwsdk/router"` to the `optimizeDeps.include` list for the client build configuration.

---

## PR Title

feat: Add defineLinks documentation and optimize router entry points

## PR Description

This PR introduces documentation for the `defineLinks` function and optimizes the router module by creating conditional entry points for different environments.

### Changes

- **Documentation**: Adds a "Generating Links" section to the routing documentation. This new section explains how to use `defineLinks` for type-safe URL generation and includes a detailed API reference.
- **Router Entry Points**: The router module now has separate entry points for client and server environments. A client-specific entry point (`routerClient.ts`) is introduced, which only exports the `defineLinks` function. This change reduces the client bundle size by excluding server-side routing logic.
- **Build Configuration**:
- The `package.json` `exports` map for `./router` is updated to use conditional exports, serving the appropriate bundle to either the `workerd` (`worker`+`ssr` environments) or `default` (`client` environment) condition.
- `"rwsdk/router"` is added to the `optimizeDeps.include` array in the Vite client configuration.
83 changes: 82 additions & 1 deletion docs/src/content/docs/core/routing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ route("/files/*/preview", ...)
route("/files/*/download/*", ...)
```

---

## Request Handlers

The request handler is a function, or array of functions (See [Interrupters](#interrupters)), that are executed when a request is matched.
Expand Down Expand Up @@ -337,4 +339,83 @@ export default defineApp([
return <NotFound />;
}),
]);
```
```

---

## Generating Links

While `route` handles incoming requests, `defineLinks` is used to generate the URLs for those routes. This function can be used in both server and client components to create type-safe links (e.g., in `<a>` tags or for programmatic navigation), helping prevent typos and providing compile-time errors for invalid routes.

First, define all your application's routes in a shared file:

```ts title="src/app/shared/links.ts"
import { defineLinks } from "rwsdk/router";

export const link = defineLinks([
"/",
"/about",
"/users/:id",
"/files/*"
]);
```

<Aside type="note">
It is a good practice to keep your link definitions in a file that is shared between your server and client code.
</Aside>

Now you can import and use the `link` function throughout your application to generate URLs.

### Type Safety

`defineLinks` creates a strongly-typed function. If you attempt to generate a URL for a route that was not included in the initial array, TypeScript will raise a compile-time error.

```tsx
import { link } from "@/app/shared/links";

function MyComponent() {
return (
<nav>
<a href={link("/")}>Home</a>
<a href={link("/about")}>About</a>
{/* ❌ TypeScript Error! '/contakt' is not a valid route. */}
<a href={link("/contakt")}>Contact</a>
</nav>
)
}
```

### Dynamic Parameters

The generated function also handles dynamic parameters for you.

For named parameters, pass an object with keys matching the parameter names:

```ts
// Generates: /users/123
link("/users/:id", { id: "123" });
```

For wildcard parameters, use special keys `$0`, `$1`, and so on, corresponding to the wildcards (`*`) in the route from left to right.

```ts
// Generates: /files/documents/report.pdf
link("/files/*", { $0: "documents/report.pdf" });
```

### API Reference

#### `defineLinks(routes): function`
Takes an array of route patterns and returns a type-safe link-generating function.

- **routes**: `string[]` - An array of route pattern strings.

The returned function has the following signature:

#### `link(path[, params]): string`
Generates a URL string for a given path, interpolating any dynamic parameters.

- **path**: `string` - A route pattern from the original `routes` array.
- **params** (optional): `Record<string, string>` - An object for dynamic segments.
- For named parameters (e.g., `/users/:id`), the key should match the parameter name (e.g., `{ id: '123' }`).
- For wildcard parameters (e.g., `/files/*`), keys should be `$0`, `$1`, etc., for each `*` from left to right (e.g., `{ $0: 'image.jpg' }`).
Loading
Loading