refactor(ui): unify server function dispatch across adapters#17419
Open
jacobsfletch wants to merge 10 commits into
Open
refactor(ui): unify server function dispatch across adapters#17419jacobsfletch wants to merge 10 commits into
jacobsfletch wants to merge 10 commits into
Conversation
The TanStack Start adapter dispatches server functions from sharedServerFunctions, which omitted slugify. Clicking the Slug field's regenerate button threw "Unknown Server Function: slugify" server-side (silently swallowed on the client). Next was unaffected as it registers slugify in its own handler list.
handleGenerate awaited the slugify server function with no error handling, so a failing dispatch (e.g. an unregistered handler or a thrown UnauthorizedError) was silently swallowed with no user feedback. Catch the rejection and show an error toast.
The Next.js adapter re-declared every server function instead of reusing sharedServerFunctions, so the two lists drifted — the cause of the missing slugify handler under TanStack. Spread the shared registry and declare only the RSC-only extras, so a handler added to the registry reaches both adapters.
Every adapter re-declared its own server function list and, in the case of TanStack Start, its own dispatcher. The lists drifted (e.g. slugify was missing from the TanStack registry) and the dispatch logic was duplicated. Make sharedServerFunctions the single, complete registry and turn createServerFunctionHandler into the one dispatcher for all adapters. Adapters now inject only what is genuinely framework-specific: - initReq — how the Payload request is resolved - augmentArgs — extra handler args (TanStack's mode/renderComponent) - transformResult — response post-processing (TanStack's serializeForRsc) Removes the TanStack-specific baseServerFunctions list and its duplicate switchLanguageHandler (identical to the shared one).
The augmentArgs hook only ever passed TanStack Start's { mode,
renderComponent }, and neither is read by any handler: mode has no
consumers at all, and renderComponent is redundant since handlers
import RenderServerComponent directly (RenderRSCComponent is that
same function re-exported). Next.js already runs the shared handlers
without either field, proving they are unnecessary.
Removes augmentArgs from the factory and the TanStack adapter.
TanStackComponentRenderer (exported from ./client) had no consumers, and its only dependency chain — RenderComponent -> RenderRSCComponent (renderPayloadRSC) — existed solely to re-export RenderServerComponent from @payloadcms/ui. Nothing wires it up as a renderComponent, so it was fully unreachable. Removes TanStackComponentRenderer, the RenderComponent element, renderPayloadRSC, and the RenderRSCComponent export (plus its browser stub) from the ./rsc entrypoint.
The mode field on DefaultServerFunctionArgs and the ServerFunctionMode type had no readers — no server function handler ever inspected mode. The type's doc was also misleading (claimed TanStack Start is 'data-only' while the adapter set 'rsc'). Removes both.
…tor/unified-server-fn-registry # Conflicts: # packages/ui/src/utilities/handleServerFunctions.ts
jacobsfletch
requested review from
AlessioGr,
DanRibbens,
JarrodMFlesch and
denolfe
as code owners
July 20, 2026 20:08
Contributor
📦 esbuild Bundle Analysis for payloadThis analysis was generated by esbuild-bundle-analyzer. 🤖
Largest pathsThese visualization shows top 20 largest paths in the bundle.Meta file: packages/next/meta_index.json, Out file: esbuild/index.js
Meta file: packages/payload/meta_index.json, Out file: esbuild/index.js
Meta file: packages/payload/meta_shared.json, Out file: esbuild/exports/shared.js
Meta file: packages/richtext-lexical/meta_client.json, Out file: esbuild/exports/client_optimized/index.js
Meta file: packages/ui/meta_client.json, Out file: esbuild/exports/client_optimized/index.js
Meta file: packages/ui/meta_shared.json, Out file: esbuild/exports/shared_optimized/index.js
DetailsNext to the size is how much the size has increased or decreased compared with the base branch of this PR.
|
jacobsfletch
commented
Jul 20, 2026
| * - `'rsc'`: Return React nodes (JSX) — requires RSC flight serialization (Next.js) | ||
| * - `'data-only'`: Return JSON-serializable data — for non-RSC adapters (TanStack Start) | ||
| */ | ||
| export type ServerFunctionMode = 'data-only' | 'rsc' |
Member
Author
There was a problem hiding this comment.
Leftover from pre-RSC TanStack explorations.
jacobsfletch
commented
Jul 20, 2026
| @@ -1,5 +0,0 @@ | |||
| /** | |||
| * @deprecated Import `RenderServerComponent` from `@payloadcms/ui/elements/RenderServerComponent` directly. | |||
Member
Author
There was a problem hiding this comment.
No need for deprecated exports at this time. Just remove.
jacobsfletch
commented
Jul 20, 2026
| * uses TanStack's wire format (e.g. `createServerFn`), not raw | ||
| * `JSON.stringify`. | ||
| */ | ||
| export const handleServerFunctions: ServerFunctionHandler = async (args) => { |
Member
Author
There was a problem hiding this comment.
One of the big wins of this PR: this is now standardized behind @payloadcms/ui.
jacobsfletch
commented
Jul 20, 2026
| import { serializeForRsc } from './serializeForRsc.js' | ||
| import { switchLanguageHandler } from './serverFunctionHandlers.js' | ||
|
|
||
| const baseServerFunctions: Record<string, ServerFunction<any, any>> = { |
Member
Author
There was a problem hiding this comment.
All server functions are now framework agnostic, no need provide framework-specific wrappers.
This reverts commit 8186e56.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Removes all TanStack Start-specific server function wrappers, consolidating server function dispatch into the single shared path every adapter uses.
Each adapter maintained its own handler registration. Maintained independently, the two lists were at significant risk of drifting — a handler could be added to one adapter and silently omitted from the other.
Now:
sharedServerFunctionsis now the single, complete registrycreateServerFunctionHandleris the one dispatcher for every adapter.Adapters inject only what is genuinely framework-specific:
initReq— how the Payload request is resolved (the frameworks do this differently)transformResult— response post-processing (TanStack converts React elements to RSC handles)A handler added to the registry now reaches every adapter, and the lists cannot fall out of sync again.