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
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# @lazarv/react-server contribution guide

We are thrilled that you are interested in contributing to this framework! You can contribute in many ways.
We are thrilled that you are interested in contributing to this runtime! You can contribute in many ways.

* as a developer
* as a technical writer
Expand All @@ -22,15 +22,15 @@ To fix an issue, to provide a new feature or create a new example app, follow th

We are using the latest [pnpm](https://pnpm.io) version as the package manager, so don't forget to enable Corepack using `corepack enable`.

The framework is written purely in 100% JavaScript, so we don't need any build steps anywhere in the core codebase. But as Vite supports both JS/TS, any app code can be implemented using plain JavaScript or using TypeScript, when needed. We leave this to the developer of the app and we provide module level TypeScript definitions to provide types for the app developer.
The runtime is written purely in 100% JavaScript, so we don't need any build steps anywhere in the core codebase. But as Vite supports both JS/TS, any app code can be implemented using plain JavaScript or using TypeScript, when needed. We leave this to the developer of the app and we provide module level TypeScript definitions to provide types for the app developer.

## Technical writers

To fix or add more content to the documentation, do the same as a developer and run the documentation site locally using `pnpm --filter ./docs dev`. Change content in the [guide](https://github.com/lazarv/react-server/tree/main/docs/src/pages/en/guide) or in the [README](https://github.com/lazarv/react-server/blob/main/README.md).

## Feedback

Feedback is extremely important! Create a new GitHub [issue](https://github.com/lazarv/react-server/issues) or get in contact on [X](https://x.com/lazarv1982) and tell us about your experience with this framework.
Feedback is extremely important! Create a new GitHub [issue](https://github.com/lazarv/react-server/issues) or get in contact on [X](https://x.com/lazarv1982) and tell us about your experience with this runtime.

## Other

Expand Down
2 changes: 1 addition & 1 deletion docs/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://inlang.com/schema/inlang-message-format",
"category_guide": "Guide",
"category_integrations": "Integrations",
"category_framework": "Framework",
"category_features": "Features",
"category_router": "Router",
"category_deploy": "Deploy",
"category_tutorials": "Tutorials",
Expand Down
2 changes: 1 addition & 1 deletion docs/messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://inlang.com/schema/inlang-message-format",
"category_guide": "ガイド",
"category_integrations": "統合",
"category_framework": "フレームワーク",
"category_features": "機能",
"category_router": "ルーター",
"category_deploy": "デプロイ",
"category_tutorials": "チュートリアル",
Expand Down
212 changes: 212 additions & 0 deletions docs/public/llms.txt

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions docs/react-server.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,21 @@ export default {
},
prerender: false,
export(paths) {
const pagePaths = paths
.map(({ path }) => path.replace(/^\/en/, ""))
.filter((p) => p !== "/" && p !== "/404" && p.length > 1);

return [
...paths.map(({ path }) => ({
path: path.replace(/^\/en/, ""),
rsc: false,
})),
// Markdown versions of all docs pages for AI usage
...pagePaths.map((path) => ({
path: `${path}.md`,
filename: `${path.slice(1)}.md`,
method: "GET",
})),
{
path: "/sitemap.xml",
filename: "sitemap.xml",
Expand Down
28 changes: 28 additions & 0 deletions docs/src/components/ViewMarkdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { FileText } from "lucide-react";

import { useLanguage } from "../i18n.mjs";

export default function ViewMarkdown({ pathname }) {
const lang = useLanguage();
const canonical = pathname.replace(new RegExp(`^/${lang}`), "");

// Don't show on the homepage or language root
if (!canonical || canonical === "/") {
return null;
}

const mdUrl = `${canonical}.md`;

return (
<a
href={mdUrl}
target="_blank"
rel="noreferrer"
title="View as Markdown (for AI/LLM usage)"
className="flex items-center gap-1 text-xs text-gray-600 hover:!text-gray-500 dark:!text-gray-500 dark:hover:!text-gray-400 hover:no-underline absolute right-4 top-5 z-50"
>
<FileText size={12} />
.md
</a>
);
}
20 changes: 13 additions & 7 deletions docs/src/pages.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@ import { join, relative } from "node:path";

import { defaultLanguage } from "./const.mjs";

export const pages = Array.from(
Object.entries(
import.meta.glob("./pages/*/\\(pages\\)/**/*.{md,mdx}", { eager: true })
)
const frontmatterLoaders = import.meta.glob(
"./pages/*/\\(pages\\)/**/*.{md,mdx}",
{ import: "frontmatter" }
);
const loaders = import.meta.glob("./pages/*/\\(pages\\)/**/*.{md,mdx}");
export const pages = await Promise.all(
Object.entries(frontmatterLoaders).map(async ([key, load]) => [
key,
{ frontmatter: await load() },
])
);

export const categories = [
"Guide",
"Integrations",
"Framework",
"Features",
"Router",
"Deploy",
"Tutorials",
Expand Down Expand Up @@ -46,7 +52,7 @@ export function getPages(pathname, lang) {
([, { frontmatter: a }], [, { frontmatter: b }]) =>
(a?.order ?? 0) - (b?.order ?? 0)
)
.reduce((availablePages, [src, { frontmatter, default: page }]) => {
.reduce((availablePages, [src, { frontmatter }]) => {
const path = relative(`./pages/${lang}`, src);
const href = join(
lang !== defaultLanguage ? `/${lang}` : "/",
Expand All @@ -68,7 +74,7 @@ export function getPages(pathname, lang) {
frontmatter,
category,
src,
page,
page: () => loaders[src]().then((m) => m.default),
};

if (
Expand Down
12 changes: 12 additions & 0 deletions docs/src/pages/(i18n).middleware.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ export default function I18n() {
return;
}

// Rewrite .md requests to the markdown API route
if (pathname.endsWith(".md")) {
const mdPath = pathname.replace(/\.md$/, "");
rewrite(`/md${mdPath}`);
return;
}

// Skip /md/ API route paths from i18n handling
if (pathname.startsWith("/md/")) {
return;
}

const { lang, slug } = useMatch("/[lang=i18n]/[[...slug]]", {
matchers: {
i18n: (lang) => languages.includes(lang),
Expand Down
12 changes: 4 additions & 8 deletions docs/src/pages/(root).layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { cookie, usePathname } from "@lazarv/react-server";
import { useMatch } from "@lazarv/react-server/router";

import EditPage from "../components/EditPage.jsx";
import ViewMarkdown from "../components/ViewMarkdown.jsx";
import { useLanguage, m } from "../i18n.mjs";
import { defaultLanguage, defaultLanguageRE, languages } from "../const.mjs";
import { categories } from "../pages.mjs";
Expand Down Expand Up @@ -73,15 +74,9 @@ export default function Layout({
<meta property="og:image:height" content="630" />
<meta property="og:url" content="https://react-server.dev" />
<meta property="twitter:card" content="summary_large_image" />
<meta
name="description"
content="The easiest way to build React apps with server-side rendering"
/>
<meta name="description" content="Run React anywhere" />
<meta property="og:title" content="@lazarv/react-server" />
<meta
property="og:description"
content="The easiest way to build React apps with server-side rendering."
/>
<meta property="og:description" content="Run React anywhere" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@docsearch/css@3"
Expand Down Expand Up @@ -117,6 +112,7 @@ export default function Layout({
<article>
{breadcrumb}
<EditPage pathname={pathname} />
<ViewMarkdown pathname={pathname} />
{children}
{navigation}
</article>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ export default function Header({ lang }) {
{m.category_integrations()}
</a>
<a
href={`${baseUrl}framework`}
className={`hidden lg:inline${activeClass("framework")}`}
href={`${baseUrl}features`}
className={`hidden lg:inline${activeClass("features")}`}
>
{m.category_framework()}
{m.category_features()}
</a>
<a
href={`${baseUrl}router`}
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/en/(pages)/deploy/bun.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ Start the production server using the CLI:
bun --bun react-server start
```

Or run it directly without the framework installed:
Or run it directly without the runtime installed:

```sh
bun --bun .bun/start.mjs
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/en/(pages)/deploy/deno.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ Start the production server using the CLI:
deno run -A npm:@lazarv/react-server start
```

Or run it directly without the framework installed:
Or run it directly without the runtime installed:

```sh
deno run --config .deno/deno.json --allow-net --allow-read --allow-env --allow-sys .deno/start.mjs
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Caching
category: Framework
category: Features
order: 1
---

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: CLI
order: -1
category: Framework
category: Features
---

import Link from "../../../../components/Link.jsx";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Cluster mode
category: Framework
category: Features
order: 10
contents: false
---
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
---
title: Configuration
category: Framework
category: Features
order: -1
---

import Link from "../../../../components/Link.jsx";

# Configuration

To configure the behavior of the framework, you need to create a `react-server.config.*` or `+*.config.*` file in the root of your project. This file is used to configure the server and the build process. The file type could be `.js`, `.mjs`, `.ts`, `.mts` or `.json`.
To configure the behavior of `@lazarv/react-server`, you need to create a `react-server.config.*` or `+*.config.*` file in the root of your project. This file is used to configure the server and the build process. The file type could be `.js`, `.mjs`, `.ts`, `.mts` or `.json`.

You can use the `+*.config.*` file to extend the configuration of the framework. The `+*.config.*` file is merged with the `react-server.config.*` file.
You can use the `+*.config.*` file to extend the configuration of `@lazarv/react-server`. The `+*.config.*` file is merged with the `react-server.config.*` file.

The `+*.config.*` file is useful when you want to extend the configuration of the framework. You can use as many `+*.config.*` files as you want. All the configuration files are merged together in the order they are loaded.
The `+*.config.*` file is useful when you want to extend the configuration of the runtime. You can use as many `+*.config.*` files as you want. All the configuration files are merged together in the order they are loaded.

If you want to only add configuration to use when running the framework in production mode, then use the `.production.config.*` extension. These configuration files only loaded in production mode.
If you want to only add configuration to use when running the runtime in production mode, then use the `.production.config.*` extension. These configuration files only loaded in production mode.

In a similar way, you can create configuration files with the `.development.config.*` extension to use a different configuration for development mode.

Expand All @@ -32,13 +32,13 @@ To provide full control over the Vite configuration, you can use the `vite` opti

You can also use a `vite.config.*` file to configure Vite as you would do in a Vite project. The `vite.config.*` file is merged with the `react-server.config.*` file.

Best practice is to use a `vite.config.*` file to configure Vite as you would do in a Vite project and use the `react-server.config.*` file to configure the framework specific options.
Best practice is to use a `vite.config.*` file to configure Vite as you would do in a Vite project and use the `react-server.config.*` file to configure the runtime specific options.

<Link name="additional-configuration">
## Additional configuration
</Link>

The following options are specific to the `@lazarv/react-server` framework.
The following options are specific to `@lazarv/react-server`.

<Link name="runtime">
#### Runtime
Expand Down Expand Up @@ -154,7 +154,7 @@ export default {
};
```

As the whole application context is available in the function, you can use all helpers or hooks provided by the framework to determine whether to preload the client components.
As the whole application context is available in the function, you can use all helpers or hooks provided by `@lazarv/react-server` to determine whether to preload the client components.

```mjs filename="react-server.config.mjs"
import { usePathname } from "@lazarv/react-server";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Error handling
category: Framework
category: Features
order: 2
---

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: HTTP context
category: Framework
category: Features
order: 0
---

Expand All @@ -12,7 +12,7 @@ With `@lazarv/react-server` you have access to everything related to the context

The following hooks / functions are available for you to access and manipulate the HTTP context.

All of these functions are available also in middlewares and route handlers with the file-system based router as these are framework specific and not related to React.
All of these functions are available also in middlewares and route handlers with the file-system based router as these are runtime specific and not related to React.

With `useHttpContext()` you can get access to the full HTTP context.

Expand Down Expand Up @@ -270,7 +270,7 @@ export default function MyComponent() {

With `redirect()` you can redirect the current request to another URL.

> **Warning:** the `redirect()` function will throw an error which will be caught by the framework and will result in a redirect. When you want to use `redirect()` in a `try`/`catch` block, make sure you rethrow the error if it's a redirect error.
> **Warning:** the `redirect()` function will throw an error which will be caught by the runtime and will result in a redirect. When you want to use `redirect()` in a `try`/`catch` block, make sure you rethrow the error if it's a redirect error.

```jsx
import { redirect } from "@lazarv/react-server";
Expand Down Expand Up @@ -415,7 +415,7 @@ export default function MyComponent() {
## Logger
</Link>

With `logger` you can log messages using the framework's built-in logger. The `logger` object provides `info`, `warn`, `error`, and `debug` methods that integrate with the framework's logging system, providing consistent and formatted output.
With `logger` you can log messages using the runtime's built-in logger. The `logger` object provides `info`, `warn`, `error`, and `debug` methods that integrate with the runtime's logging system, providing consistent and formatted output.

```jsx
import { logger } from "@lazarv/react-server";
Expand All @@ -427,7 +427,7 @@ export default function MyComponent() {
}
```

The `logger` automatically uses the framework's Vite-integrated logger in development mode for nicely formatted output, and falls back to `console` in production. It is context-aware — when called inside an `after()` callback, the log output is annotated with an `(after)` label so you can distinguish post-response logs from rendering logs.
The `logger` automatically uses the runtime's Vite-integrated logger in development mode for nicely formatted output, and falls back to `console` in production. It is context-aware — when called inside an `after()` callback, the log output is annotated with an `(after)` label so you can distinguish post-response logs from rendering logs.

```jsx
import { after, logger } from "@lazarv/react-server";
Expand Down
Loading
Loading