Repository navigation
feat(web): a server function reference can declare its own client send - #4170
Conversation
…the app's fetch
An integration that answers some server-function requests itself (a
prerendered build's static artifacts) had to install itself as the
transport fetch, so it and an app's own configureServerFunctionsClient
({ fetch }) replaced each other depending on which ran last. A layer wraps
a send that reads the configured fetch at call time, so the order no
longer matters.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NkjGmX4hAoiU9VhXNt7j3E
🦋 Changeset detectedLatest commit: 27b6f34 The changes in this PR will be included in the next version bump. This PR includes changesets to release 14 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Size (brotli, eager entry chunk)
|
Artifacts lived at the same url in every build, so a CDN or browser cache
could serve the previous deploy's answer. The crawl now takes a buildId
(the Vite plugin mints one per process and defines it as
import.meta.env.PRERENDER_BUILD); integrations get it as context.buildId and
@solidjs/prerender writes _static/<build>/<label>.<key>.txt.
prerendered() installed staticFetch as the transport fetch, so it and an
app's own configureServerFunctionsClient({ fetch }) replaced each other by
order. On a runtime with wrapServerFunctionsFetch (solidjs/solid#4170) it now
installs a send layer instead, which composes in either order; older
runtimes keep the previous behavior.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NkjGmX4hAoiU9VhXNt7j3E
…s added An unlayered app now ships no extra bytes: with wrapServerFunctionsFetch tree-shaken, the send variable is never assigned and minifies away. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NkjGmX4hAoiU9VhXNt7j3E
Coverage Report for CI Build 39456084970Warning Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes. Coverage remained the same at 77.555%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
Merging this PR will improve performance by 11.81%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ⚡ |
build + consume |
776.3 µs | 694.3 µs | +11.81% |
Tip
Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.
Comparing claude/project-thread-4achkk (27b6f34) with next (a2743fa)
Footnotes
-
5 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
wrapServerFunctionsFetch added a second, global transport hook. A
reference can now declare its own send in its metadata instead
(withMeta(fn, { fetch: (address, init, next) => ... })): the transport uses
it for that function's requests with the app's configured send as next.
The intent lives on the declaration, the app's fetch stays the app's, and
there is nothing to order.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NkjGmX4hAoiU9VhXNt7j3E
Instead of a global send layer, prerendered() declares the artifact send on
its reference (withMeta(fn, { fetch }), solidjs/solid#4170). The runtime
calls it for that function's requests with the app's transport fetch as
next, so the app's fetch is never displaced and carries the hybrid
fallback. Runtimes without reference sends wire staticFetch() by hand; on
current ones a wired staticFetch passes through, so artifacts are looked up
once.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NkjGmX4hAoiU9VhXNt7j3E
rc.16 ships reference sends (solidjs/solid#4170), so prerendered() serves artifacts on its own. The hand-wired staticFetch transport only existed for older runtimes; remove it along with its server stub and the test probe. Bump the SSG example and dev deps to rc.16 / router next.41. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NkjGmX4hAoiU9VhXNt7j3E
Summary
Before: an integration that answers some server-function requests itself had to install itself as the transport
fetch.@solidjs/prerenderdoes this to serve prerendered calls from static artifacts. It and an app's ownconfigureServerFunctionsClient({ fetch })then replaced each other, depending on which ran last. In the common order, data modules evaluateprerendered()before the client entry configures its fetch, so the artifacts were silently bypassed.After: a reference can declare its own send in its metadata,
withMeta(fn, { fetch: (address, init, next) => ... }). The transport uses it for that function's requests, with the configured send (the app'sfetch, or the global) asnext. The intent lives on the declaration and the app'sfetchstays the app's, so there is nothing to order and no new global hook.How:
createRequestalready has the reference's metadata, so the send becomes(meta.fetch || send)(base, init, send). The configured send receives a trailing third argument, which it ignores, as the globalfetchdoes. This is documented on thefetchoption.ServerFunctionMetadata.fetchis typed and documented, and the send's shape is exported asServerFunctionsSend.Size: +19 B minified on the server-component page scenarios and 0 B elsewhere, within the gate's 20 B allowance. The first cut was a global
wrapServerFunctionsFetchlayer; it was replaced by this per-reference send on review.How did you test this change?
test/server/server-functions-extensions.spec.tsx, with the reference's send declared before the app configures itsfetch:next.packages/web:server-functions-adapter-request"rebuild failure", which fails only on Node 22.22 locally and passes on CI's Node 24.pnpm test-typespasses.scripts/size: head vs base is +19 B minified on SC pages only.Consumer: solidjs/prerender-crawler#11 declares its artifact send this way. Its SSG example, built against rc.15 patched with this one-line change, navigates from artifacts only in a browser.
🤖 Generated with Claude Code
https://claude.ai/code/session_01NkjGmX4hAoiU9VhXNt7j3E