Skip to content

chore: Rename layout() -> document() #193

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 27, 2025
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
17 changes: 5 additions & 12 deletions .github/workflows/check-starters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,14 @@ jobs:
corepack enable
pnpm install

- name: Link latest SDK
run: pnpm link-sdk

- name: Run checks for each starter
run: pnpm -r --filter="@redwoodjs/starter-*" check

- name: Test dev server for each starter
run: |
for starter in starters/*; do
if [ -d "$starter" ]; then
./scripts/check-starter-server.sh dev "$starter"
fi
done
run: pnpm check-starters:dev

- name: Test building and preview server for each starter
run: |
for starter in starters/*; do
if [ -d "$starter" ]; then
./scripts/check-starter-server.sh preview "$starter"
fi
done
run: pnpm check-starters:preview
23 changes: 11 additions & 12 deletions docs/src/content/docs/core/routing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -174,32 +174,31 @@ The `ctx` object:
---
```

## Layouts
## Documents

Layouts are a way to wrap your pages in a consistent layout. In RedwoodSDK, layouts are defined using the `layout` function in `defineApp`.
Documents are how you define the "shell" of your application's html: the `<html>`, `<head>`, `<meta>` tags, scripts, stylesheets, `<body>`, and where in the `<body>` your actual page content is rendered. In RedwoodSDK, documents are defined using the `document` function in `defineApp`.

```tsx title="src/worker.tsx" "layout"
```tsx title="src/worker.tsx" "document"
import { defineApp } from "@redwoodjs/sdk/worker";
import { route, layout } from "@redwoodjs/sdk/router";
import { route, document } from "@redwoodjs/sdk/router";

import { Document } from "@/pages/Document";
import { HomePage } from "@/pages/HomePage";

export default defineApp([
layout(
document(
Document, [route("/", HomePage)]
)]);

---
The `layout` function takes a React component and an array of route handlers. The layout will be applied to all the routes that are passed to it.
The `document` function takes a React component and an array of route handlers. The document will be applied to all the routes that are passed to it.

This component will be rendered on the server side when the page loads. When defining this component, you'd add:
* Your application's stylesheets and scripts
* A mount point for your page content (`id="root"` in the code below): this is where your actual page will be rendered - the "dynamic stuff" which updates using React Server Components.
---
```

<Aside type="tip" title="Layouts">
RedwoodSDK does not supply a default "html" template. You must supply your
own! This is so you have full control over the HTML rendered by your website.
</Aside>

```tsx title="src/pages/Document.tsx" mark={7}
export const Document = ({ children }) => (
<html lang="en">
Expand All @@ -215,6 +214,6 @@ export const Document = ({ children }) => (
```

<Aside type="caution" title="Client Side Hydration">
You must include the client side hydration script in your layout, otherwise
You must include the client side hydration script in your document, otherwise
the React components will not be hydrated.
</Aside>
4 changes: 2 additions & 2 deletions docs/src/content/docs/core/security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ headers.set(

#### Using `nonce` for inline scripts

Sometimes you need to include inline scripts in your application, but Content Security Policy (CSP) blocks them by default for security reasons. RedwoodJS automatically generates a fresh, cryptographically secure nonce value for each request You can access this nonce in layouts or page components rendered by the [router](./routing), using `rw.nonce`.
Sometimes you need to include inline scripts in your application, but Content Security Policy (CSP) blocks them by default for security reasons. RedwoodJS automatically generates a fresh, cryptographically secure nonce value for each request You can access this nonce in document or page components rendered by the [router](./routing), using `rw.nonce`.

<Aside type="caution">
Only use the nonce attribute for trusted inline scripts that you have full
Expand All @@ -75,7 +75,7 @@ export const Document = ({ rw, children }) => (

export default defineApp<Context>([
// ...
layout(Document, [
document(Document, [
// ...
]),
]);
Expand Down
12 changes: 6 additions & 6 deletions docs/src/content/docs/getting-started/first-project.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Let's walk through each file and directory to understand their purpose.

- `package.json` - Contains project configuration and dependencies.
- `src/app` - Contains the main application files.
- `src/app/Document.tsx` - The main layout component that wraps your application. This includes the header, footer, and other shared components.
- `src/app/Document.tsx` - The main document component that wraps your application. This includes the header, footer, and other shared components.
- `src/app/pages` - Contains your app's pages.
- `src/app/shared` - Contains shared utilities.
- `src/client.tsx` - The main client-side entry point.
Expand Down Expand Up @@ -75,15 +75,15 @@ export default defineApp<Context>([
// setup ctx here
ctx;
},
layout(Document, [
document(Document, [
index([
Home,
]),
]),
])
```

Here we have a `layout` function that takes the `Document` component (imported at the top of the file) and wraps our entire application. This include our basic HTML `head` and `body` tags.
Here we have a `document` function that takes the `Document` component (imported at the top of the file) and wraps our entire application. This include our basic HTML `head` and `body` tags.

```tsx
export const Document: React.FC<{ children: React.ReactNode }> = ({
Expand All @@ -109,7 +109,7 @@ You can add additional routes by:

- Creating new page components in the `src/app/pages` directory
- Importing them inside the `src/worker.tsx` file
- Add them to the layout array, using the `route` function:
- Add them to the document array, using the `route` function:

```tsx
import { About } from "src/pages/About";
Expand All @@ -119,7 +119,7 @@ export default defineApp<Context>([
// setup ctx here
ctx;
},
layout(Document, [index([Home]), route("/about", About)]),
document(Document, [index([Home]), route("/about", About)]),
]);
```

Expand All @@ -129,7 +129,7 @@ You can find additional information about dynamic routes in our [Routing Guide](

### Editing components

There is quite a bit of flexibility in how you organize your pages, layouts, and components. For example, you can co-locate page specific files together in the `src/app/pages` directory, or keep all of your components in a `src/app/components` directory (You'll need to create this folder).
There is quite a bit of flexibility in how you organize your pages, documents, and components. For example, you can co-locate page specific files together in the `src/app/pages` directory, or keep all of your components in a `src/app/components` directory (You'll need to create this folder).

By default, all the pages and components in your project are React Server components. If you want to add reactivity, you'll need to use the `"use client"` directive at the top of the file.

Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/guides/frontend/layouts.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Layouts
title: Documents
description: A guide in my new Starlight docs site.
---

Expand Down
24 changes: 12 additions & 12 deletions docs/src/content/docs/reference/routing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -173,28 +173,28 @@ This renders as simple HTML:

### Root Document

By default, RedwoodSDK only renders your component's HTML without `<html>`, `<head>`, or `<body>` tags. To add these, wrap your routes in a layout:
By default, RedwoodSDK only renders your component's HTML without `<html>`, `<head>`, or `<body>` tags. To add these, wrap your routes in a document:

<Code
language="tsx"
title="src/worker.tsx"
code={`\
import { defineApp } from "@redwoodjs/sdk/worker";
import { route, layout } from "@redwoodjs/sdk/router";
import { route, document } from "@redwoodjs/sdk/router";

function Document({ children }) {
return (

<html>
<head>
<title>RedwoodSDK App</title>
</head>
<body>{children}</body>
<head>
<title>RedwoodSDK App</title>
</head>
<body>{children}</body>
</html>
);
}
); }

export default defineApp([
layout(Document, [
document(Document, [
route("/", Homepage)
])
]);`} />
Expand All @@ -213,7 +213,7 @@ import { initClient } from "@redwoodjs/sdk/client";

initClient();`} />

2. Include it in your Document layout:
2. Include it in your Document document:

<Code
language="tsx"
Expand Down Expand Up @@ -245,13 +245,13 @@ Here's an example using both helpers:
language="tsx"
code={`\
import { defineApp } from "@redwoodjs/sdk/worker";
import { index, layout, prefix } from "@redwoodjs/sdk/router";
import { index, document, prefix } from "@redwoodjs/sdk/router";
import { authRoutes } from 'src/pages/auth/routes';
import { invoiceRoutes } from 'src/pages/invoice/routes';
import HomePage from 'src/pages/Home/HomePage';

export default defineApp([
layout(Document, [
document(Document, [
// Define root route using index
index([
HomePage,
Expand Down
4 changes: 2 additions & 2 deletions experiments/ai-stream/src/worker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineApp } from "@redwoodjs/sdk/worker";
import { index, layout } from "@redwoodjs/sdk/router";
import { index, document } from "@redwoodjs/sdk/router";
import { Document } from "src/Document";
import { Chat } from "src/pages/Chat/Chat";
import { setCommonHeaders } from "src/headers";
Expand All @@ -8,5 +8,5 @@ type Context = {};

export default defineApp<Context>([
setCommonHeaders(),
layout(Document, [index([Chat])]),
document(Document, [index([Chat])]),
]);
4 changes: 2 additions & 2 deletions experiments/billable/src/worker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineApp } from "@redwoodjs/sdk/worker";
import { index, layout, prefix } from "@redwoodjs/sdk/router";
import { index, document, prefix } from "@redwoodjs/sdk/router";
import { ExecutionContext } from "@cloudflare/workers-types";

import { link } from "src/shared/links";
Expand Down Expand Up @@ -39,7 +39,7 @@ const app = defineApp<Context>([
setupSessionStore(env);
ctx.user = await getUser(request);
},
layout(Document, [
document(Document, [
index([
({ ctx }) => {
if (ctx.user) {
Expand Down
4 changes: 2 additions & 2 deletions experiments/cutable/src/worker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineApp } from "@redwoodjs/sdk/worker";
import { index, layout } from "@redwoodjs/sdk/router";
import { index, document } from "@redwoodjs/sdk/router";
import { Document } from "src/Document";
import HomePage from "src/pages/home/HomePage";

Expand All @@ -17,5 +17,5 @@ export default defineApp<Context>([
ctx.foo = 23;
},
// @ts-ignore
layout(Document, [index([HomePage])]),
document(Document, [index([HomePage])]),
]);
36 changes: 17 additions & 19 deletions experiments/griffon/docs/Routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,23 @@ A route matches the path part of a URL to an endpoint. An endpoint is a function

## Defining routes

The interface to our router is based off of Remix-Router v7. It is very simplified in that we don't allow nesting or layouts. This might be something we consider in the future, but seems out of scope for routing.
The interface to our router is based off of Remix-Router v7. It is very simplified in that we don't allow nesting or documents. This might be something we consider in the future, but seems out of scope for routing.

We will use Hono's Routing API: https://hono.dev/docs/api/routing

```ts

import { router } from '@redwoodjs/router'
import { router } from "@redwoodjs/router";

export default router([
index(import("./index.tsx")),

route('auth/login', import('./pages/auth/Login.tsx')),
route('auth/register', import('./pages/auth/Login.tsx')),
route('auth/logout', (req, res) => {
route("auth/login", import("./pages/auth/Login.tsx")),
route("auth/register", import("./pages/auth/Login.tsx")),
route("auth/logout", (req, res) => {
// remove session cookie
res.redirect('/', 307, {
'Set-Cookie': `sessionId=${new Date().toString()}; Expires=0`
})
res.redirect("/", 307, {
"Set-Cookie": `sessionId=${new Date().toString()}; Expires=0`,
});
}),

route("invoices", import("./pages/InvoiceList.tsx")),
Expand All @@ -31,9 +30,9 @@ export default router([
route("assets/*", (req, res) => {
// find file on filesystem
// stream file back
return res.send(filestream, 200)
})
])
return res.send(filestream, 200);
}),
]);
```

## Things to consider?
Expand All @@ -43,28 +42,27 @@ export default router([
Ok. That seems like a possible way forward. What else to consider?

- Type casting? Should we consider have the ability to cast things via the router? Seems like an overreach to me.
Loaders. Stick with Suspense boundary. I kinda see the benefit of been able to declare this on the component itself... Or near the component.
Loaders. Stick with Suspense boundary. I kinda see the benefit of been able to declare this on the component itself... Or near the component.

- Don't hide files. I want to be able to follow the request-response cycle in my own code. What does that mean?
- We should expose the express (or something else) part of the framework. The user should invoke a function to pass the request off to Redwood SDK

- Do not use "magic exports" to surface functionality of the frameworL: E.g.: Loader or fetchData, etc.

- Can we chain requests, middleware is awesome? is it?
```ts


```ts
export function auth(req, res, next) {
// do some auth handling stuff...
if (req.headers.authorization !== '') {
return new Response('auth error', 403)
if (req.headers.authorization !== "") {
return new Response("auth error", 403);
}
next()
next();
}

export const r = router([
route("invoices", [auth, import("./pages/InvoiceList.tsx")]),
])
]);
```

I personally prefer using an array rather than splatting params, but I don't want to move to far from express.
4 changes: 2 additions & 2 deletions experiments/realtime-poc/src/worker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineApp } from "@redwoodjs/sdk/worker";
import { route, layout } from "@redwoodjs/sdk/router";
import { route, document } from "@redwoodjs/sdk/router";
import { Document } from "@/app/Document";
import { setCommonHeaders } from "@/app/headers";
import {
Expand All @@ -20,7 +20,7 @@ export type Context = {};
export default defineApp<Context>([
setCommonHeaders(),
realtimeRoute((env) => env.REALTIME_DURABLE_OBJECT),
layout(Document, [
document(Document, [
route("/", () => {
const randomName = uniqueNamesGenerator({
dictionaries: [adjectives, colors, animals],
Expand Down
4 changes: 2 additions & 2 deletions experiments/yt-dos/src/worker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineApp } from "@redwoodjs/sdk/worker";
import { index, layout, route } from "@redwoodjs/sdk/router";
import { index, document, route } from "@redwoodjs/sdk/router";
import { Document } from "src/Document";
import { HomePage } from "src/pages/Home";
import { fetchYoutubeVideos } from "src/pages/serverFunctions";
Expand All @@ -13,7 +13,7 @@ export default defineApp<Context>([
ctx;
},
// @ts-ignore
layout(Document, [
document(Document, [
index([HomePage]),
route("/sitemap.xml", async () => {
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
Expand Down
4 changes: 2 additions & 2 deletions experiments/zoomshare/src/worker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineApp } from "@redwoodjs/sdk/worker";
import { layout, prefix, route } from "@redwoodjs/sdk/router";
import { document, prefix, route } from "@redwoodjs/sdk/router";
import { Document } from "@/app/Document";
import { authRoutes } from "@/app/pages/auth/routes";
import { Session } from "./session/durableObject";
Expand Down Expand Up @@ -41,7 +41,7 @@ const app = defineApp<Context>([
await setupDb(env);
},

layout(Document, [
document(Document, [
route("/", function () {
return new Response("Hello World");
}),
Expand Down
Loading