Skip to content

Commit

Permalink
docs: better examples
Browse files Browse the repository at this point in the history
  • Loading branch information
rossrobino committed Sep 18, 2024
1 parent fe2796e commit a151c28
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 42 deletions.
40 changes: 30 additions & 10 deletions apps/docs/src/server/content/deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,57 @@ Run `vite build` to build your application into `dist/`.
.
└── dist/
├── client/
│ ├── _immutable/
│ └── index.html
│ ├── (_immutable/) - any JS/CSS/immutable assets
│ └── (index.html) - prerendered pages
└── server/
├── app.js
└── (adapter-entry.js)
└── (adapter-entry.js) - if using an adapter
```

By default domco will generate a `app.js` module and static assets for your application.

## Example
## Manual deployment

If you are not using an [adapter](#adapters), you can import `handler` from the `app.js` module and configure your app to use in another environment.

The `dist/client/` directory holds client assets. JS and CSS assets with hashed file names will be output to `dist/client/_immutable/`, you can serve this path with immutable cache headers. Other assets like HTML files are processed and included in `dist/client/` directly.
The `dist/client/` directory holds client assets. JS and CSS assets with hashed file names will be output to `dist/client/_immutable/`, you can serve this path with immutable cache headers. Other assets like prerendered HTML files are processed and included in `dist/client/` directly.

Here's an example of how to serve your app using the result of your build using `node:http`.
### Node server example

Here's an example of how to serve your app using the result of your build using `node:http` and [`sirv`](https://github.com/lukeed/sirv/tree/master/packages/sirv).

```ts
// server.js
// import from build output
// Import the `handler` from the build output.
import { handler } from "./dist/server/app.js";
// converts web to node
// Converts web handler to a Node compatible request listener.
import { nodeListener } from "domco/listener";
import { createServer } from "node:http";
// `sirv` serves static assets.
import sirv from "sirv";

const assets = sirv("dist/client", {
etag: true,
setHeaders: (res, pathname) => {
// Serve `dist/client/_immutable/*` with immutable headers.
if (pathname.startsWith("/_immutable/")) {
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
}
},
});

const server = createServer(nodeListener(handler));
const server = createServer((req, res) =>
// First, look for a static asset.
assets(req, res, () =>
// Fallthrough to the handler if static asset is not found.
nodeListener(handler)(req, res),
),
);

server.listen(3000);
```

Run this module to start your server.
Run this module to start your server and navigate to http://localhost:3000/ to view your application.

```bash
node server.js
Expand Down
12 changes: 8 additions & 4 deletions apps/docs/src/server/content/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ If you just want to add a router, and create your own context for each route, he

```ts
import { html } from "client:page";
import type { Handler, Prerender } from "domco";
import type { Handler } from "domco";
import { Trouter, type Methods } from "trouter";

export const prerender: Prerender = ["/"];

// Custom context variable.
type Context = {
req: Request;
params: Record<string, string>;
};

// Custom handler/middleware.
type RouteHandler = (context: Context) => Promise<Response | void>;

const router = new Trouter<RouteHandler>();
Expand All @@ -82,7 +82,11 @@ export const handler: Handler = async (req) => {
const { handlers, params } = router.find(req.method as Methods, pathname);

for (const h of handlers) {
const res = await h({ req, params });
// Create context.
const context: Context = { req, params };

// Pass into handler.
const res = await h(context);

if (res instanceof Response) {
return res;
Expand Down
116 changes: 103 additions & 13 deletions apps/docs/src/server/content/migrate.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
# Migrate

This section will show you how to migrate an existing Vite single page application to become a Hono application. It will use the React template created when running `npm create vite`.
This section will show you how to server-side render an existing Vite/React single page application with domco. It will use the React template created when running `npm create vite`.

## Client
You could also import the `html` and serve your single-page application without server-rendering as well.

- Run `npm i -D domco` in your terminal to install domco as a dependency.
- Add `domco` to your `plugins` array in your `vite.config`.
## Install

Run the following command in your terminal to install domco as a dependency.

```bash
npm i -D domco
```

## Setup

Add `domco` to your `plugins` array in your `vite.config`.

<!-- // prettier-ignore -->

Expand All @@ -24,30 +33,111 @@ export default defineConfig({
});
```

- Move `index.html` into `src/client/` and rename it to `+page.html`.
- Move `main.tsx` into `src/client/` and change the `src` attribute of the `script` tag in `+page.html` linking to `/src/main.tsx` to `/client/main.tsx`.
- Add types to `/src/vite.env.d.ts`.
## Update types

Add types to `/src/vite.env.d.ts`.

```ts {3}
// /src/vite.env.d.ts
/// <reference types="vite/client" />
/// <reference types="domco/env" />
```

- Create a `src/server/+app.ts` file and serve your page from the endpoint.
## Create `app` directory

```ts
// /src/server/+app.ts
- Create a new `src/app/` directory to house the shared code that will run on the server and the client.
- Move `App.tsx` into `src/app/`.

## Create `client` directory

- Create a new `src/client/` directory to contain client side code.
- Move `index.html`, `src/App.css`, `src/index.css`, and `src/main.tsx` into `src/client/`.
- Be sure to update any import statements to the correct path if TS doesn't for you.
- Update `src/client/main.tsx` to use React's `hydrateRoot` function since the server rendered HTML will now already exist when this script is run. We will "hydrate" it instead of rendering it again from scratch.

```tsx
// src/client/main.tsx
import App from "../app/App.tsx";
import "./index.css";
import { StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";

hydrateRoot(
document.getElementById("root")!,
<StrictMode>
<App />
</StrictMode>,
);
```

### Update HTML

- Rename `index.html` to `+page.html`.
- Change the `src` attribute of the `script` tag in `+page.html` linking to `"/src/main.tsx"` to `"/client/main.tsx"`.
- Add the text `%root%` inside the `root` `div` to replace on the server.

```html {10,11}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root">%root%</div>
<script type="module" src="/client/main.tsx"></script>
</body>
</html>
```

## Add a server entry point

Create a server entry `src/server/+app.tsx` file.

```tsx
// /src/server/+app.tsx
// Import your App.
import App from "../app/App";
// Import the HTML page.
import { html } from "client:page";
import { StrictMode } from "react";
import { renderToString } from "react-dom/server";

export const handler = async (req: Request) => {
export const handler = async (_req: Request) => {
return new Response(
html, // Your Vite app.
html.replace(
"%root%", // replace the text "%root%" with the React App.
renderToString(
<StrictMode>
<App />
</StrictMode>,
),
),
{
headers: { "Content-Type": "text/html" },
},
);
};
```

- `handler` is now an API route serving your React SPA application.
`handler` is now an API route serving your React SSR application!

## Directory tree reference

```txt
src/
├── app/
│ └── App.tsx
├── assets/
│ └── react.svg
├── client/
│ ├── +page.html
│ ├── App.css
│ ├── index.css
│ └── main.tsx
├── server/
│ └── +app.tsx
└── vite-env.d.ts
```
10 changes: 5 additions & 5 deletions apps/docs/src/server/content/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The following documentation covers the basics of creating a site and all of the

## Create a new project

To get started, you'll need to have [Node](https://nodejs.org), [Bun](https://bun.sh/), or [Deno](https://deno.com) or installed on your computer. Then run the `create-domco` script to create a new project. If you already have an existing client-side Vite project check out the [migration instructions](/migrate).
To get started, you'll need to have [Node](https://nodejs.org) (recommended), [Bun](https://bun.sh/), or [Deno](https://deno.com) (experimental support) or installed on your computer. Then run the `create-domco` script to create a new project. If you already have an existing client-side Vite project check out the [migration instructions](/migrate).

### Node

Expand Down Expand Up @@ -65,7 +65,7 @@ export const handler = async (req: Request) => {
};
```

Or add a framework like [Hono](/examples#hono) to do your routing and more!
Or add a framework like [Hono](/examples#hono) to do your routing and more.

### +page

Expand Down Expand Up @@ -121,7 +121,9 @@ export const handler = async (req: Request) => {

### client:script

You can also easily get the tags for any `+script` file on the server as well. These script tags (including all imports) can be accessed via the `client:script` virtual module. They can be included in an HTML string, or inside of JSX.
You can also easily get the `<script>` tags for any `+script` module on the server as well. These script tags (including all imports) can be accessed via the `client:script` virtual module. They can be included in an HTML string, or inside of JSX.

In development, domco links the scripts to the source. In production, domco reads the manifest generated by the client build and includes the hashed version of these file names and their imports.

```ts {2,13}
// returns transformed content of `src/client/+script.ts`
Expand All @@ -148,8 +150,6 @@ export const handler = async (req: Request) => {
};
```

In development, domco links the scripts to the source. In production, domco reads the manifest generated by the client build and includes the hashed version of these file names and their imports in production.

## Prerender

Export a `prerender` variable to prerender routes that respond with HTML.
Expand Down
2 changes: 1 addition & 1 deletion apps/tester/src/client/react/+page.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
</head>
<body class="prose">
<h1>React</h1>
<div id="root">__ROOT__</div>
<div id="root">%root%</div>
</body>
</html>
10 changes: 5 additions & 5 deletions apps/tester/src/client/react/react.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import App from "./App";
import React from "react";
import ReactDOM from "react-dom/client";
import { StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";

ReactDOM.hydrateRoot(
hydrateRoot(
document.getElementById("root")!,
<React.StrictMode>
<StrictMode>
<App />
</React.StrictMode>,
</StrictMode>,
);
8 changes: 4 additions & 4 deletions apps/tester/src/server/+app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { html as reactHtml } from "client:page/react";
import type { Handler, Prerender } from "domco";
import { Injector } from "domco/injector";
import { Hono } from "hono";
import React from "react";
import { StrictMode } from "react";
import { renderToString } from "react-dom/server";

export const prerender: Prerender = ["/static-page", "/half-static/static"];
Expand Down Expand Up @@ -47,11 +47,11 @@ app.get("/api", (c) => c.json({ hello: "world" }));
app.get("/react", (c) => {
return c.html(
reactHtml.replace(
"__ROOT__",
"%root%",
renderToString(
<React.StrictMode>
<StrictMode>
<App />
</React.StrictMode>,
</StrictMode>,
),
),
);
Expand Down

0 comments on commit a151c28

Please sign in to comment.