Skip to content

docs(start): createIsomorphicFn and envOnly #4806

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
8 changes: 8 additions & 0 deletions docs/start/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
"label": "Static Server Functions",
"to": "framework/react/static-server-functions"
},
{
"label": "Environment Functions",
"to": "framework/react/environment-functions"
},
{
"label": "Middleware",
"to": "framework/react/middleware"
Expand Down Expand Up @@ -122,6 +126,10 @@
"label": "Static Server Functions",
"to": "framework/solid/static-server-functions"
},
{
"label": "Environment Functions",
"to": "framework/react/environment-functions"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"to": "framework/react/environment-functions"
"to": "framework/solid/environment-functions"

},
{
"label": "Middleware",
"to": "framework/solid/middleware"
Expand Down
105 changes: 105 additions & 0 deletions docs/start/framework/react/environment-functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
id: environment-functions
title: Environment Functions
---

## What Are Environment Functions?

Environment functions are utilities designed to define and control function execution based on the runtime environment—whether the code is running on the client or the server. These utilities help ensure that environment-specific logic is executed safely and intentionally, preventing runtime errors and improving maintainability in fullstack or isomorphic applications.

Start provide three core environment functions:

- `createIsomorphicFn`: Compose a single function that adapts to both client and server environments.
- `serverOnly`: Ensures a function can only run on the server.
- `clientOnly`: Ensures a function can only run on the client.

---

## Isomorphic Functions

Use `createIsomorphicFn()` to define functions that behave differently depending on whether they are called on the client or the server. This is useful for safely sharing logic across environments while delegating environment-specific behavior to appropriate handlers.

> [!WARNING]
> Unimplemented function results in a no-op function.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of a warning, this could be a small heading like "What is a no-op?", that'd show the user the type of a no-op.

Perhaps something like this:

type NoOpFunction = () => undefined // add a comment here


### Complete Implementation

```tsx
const getEnv = createIsomorphicFn()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make those snippets complete by adding the import from '@tanstack/solid-start'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applies to all examples

.server(() => 'server')
.client(() => 'client')

const env = getEnv()
// ℹ️ On the **server**, it returns `'server'`.
// ℹ️ On the **client**, it returns `'client'`.
```

### Partial Implementation (Server)

Here is an example of `createIsomorphicFn()` with only server implementation:

```tsx
const serverImplementationOnly = createIsomorphicFn().server(() => 'server')

const server = serverImplementationOnly()
// ℹ️ On the **server**, it returns `'server'`.
// ℹ️ On the **client**, it is no-op (returns `undefined`)
```

### Partial Implementation (Client)

Here is an example of `createIsomorphicFn()` with only client implementation:

```tsx
const clientImplementationOnly = createIsomorphicFn().client(() => 'client')

const client = clientImplementationOnly()
// ℹ️ On the **server**, it is no-op (returns `undefined`)
// ℹ️ On the **client**, it returns `'client'`.
```

### No Implementation

Here is an example of `createIsomorphicFn()` without any environment specific implementation:

```tsx
const noImplementation = createIsomorphicFn()

const noop = noImplementation()
// ℹ️ On both **client** and **server**, it is no-op (returns `undefined`)
```

---

## `env`Only Functions

The `serverOnly` and `clientOnly` helpers enforce strict environment-bound execution. They ensure the decorated function is only callable in the correct runtime context. If misused, they throw descriptive runtime errors to prevent unintentional logic execution.

### `serverOnly`

```tsx
const foo = serverOnly(() => 'bar')

foo() // ✅ On server: returns "bar"
// ❌ On client: throws "serverOnly() functions can only be called on the server!"
```

### `clientOnly`

```tsx
const foo = clientOnly(() => 'bar')

foo() // ✅ On client: returns "bar"
// ❌ On server: throws "clientOnly() functions can only be called on the client!"
```

> [!NOTE]
> These functions are useful for API access, filesystem reads, using browser APIs, or other operations that are invalid or insecure outside their intended environment.

## Tree Shaking

Environment functions are tree-shaken based on the environment for each bundle produced.

On the server, functions created using `createIsomorphicFn()` are tree-shaken. So, all code used inside `.client()` are not included in server bundle, and vice-versa.

On the server, implementation of `clientOnly` functions are replaced with a function that throws an `Error`. The reverse is true for `serverOnly` functions on the client.
2 changes: 1 addition & 1 deletion docs/start/framework/react/server-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ response?: 'data' | 'full' | 'raw'
- From other server functions

> [!WARNING]
> Server functions cannot be called from API Routes. If you need to share business logic between server functions and API Routes, extract the shared logic into utility functions that can be imported by both.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we can now call server functions from API routes. please check and and if true, this text can be removed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@schiller-manuel is right. API routes as a whole became the new "Server Routes" which support calling Server Function.

This warning can be removed.

> Server functions cannot be called from API Routes. If you need to share business logic between server functions and API Routes, extract the shared logic into utility functions that can be imported by both. See [Environment Functions](../environment-functions.md) for more.

## Accepting Parameters

Expand Down
3 changes: 3 additions & 0 deletions docs/start/framework/solid/environment-functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

once we have settled on the text for react, please duplicate and change the imports to point to solid

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hokkyss see the docs in docs/router/framework/solid/devtools.md which have a syntax for performing text replacements on the ref doc. So you shouldn't need to duplicate the entire document.

ref: docs/start/framework/react/environment-functions.md
---