Skip to content

[feat]: Add stable IDs for server functions#7682

Open
LadyBluenotes wants to merge 10 commits into
TanStack:mainfrom
LadyBluenotes:stable-serverfn-ids
Open

[feat]: Add stable IDs for server functions#7682
LadyBluenotes wants to merge 10 commits into
TanStack:mainfrom
LadyBluenotes:stable-serverfn-ids

Conversation

@LadyBluenotes

@LadyBluenotes LadyBluenotes commented Jun 23, 2026

Copy link
Copy Markdown
Member

PR summary

This PR adds stable/manual server function IDs for TanStack Start.

It adds .id('...') to createServerFn() so users can preserve a server function’s identity across file moves or variable renames. Manual IDs are statically extracted by the compiler, validated as URL-safe path segments, stripped from emitted runtime code, and used as the server function RPC ID.

It also updates collision behavior so manual IDs take precedence over generated/custom IDs. If a generated ID collides with a manual ID, the generated ID is deduped with a suffix like _1, regardless of declaration order.

Implementation details

  • Adds the .id() builder API and type coverage.
  • Extracts and validates manual IDs at compile time.
  • Strips .id() from emitted caller/provider code.
  • Dedupes generated IDs against known and manually reserved IDs.
  • Releases manual ID reservations when the owning module is invalidated.
  • Prunes stale Vite dev serverFnsById entries during HMR invalidation.
  • Resolves registered manual IDs in dev before falling back to generated-ID decoding.

Coverage

  • Type tests for .id() builder ordering and factory behavior.
  • Unit tests for manual IDs, invalid IDs, duplicate IDs, collision ordering, known-ID dedupe, dev generated/manual collision, and invalidation reuse.
  • Vite utility tests for registered manual ID lookup and generated-ID fallback.
  • Docs for manual IDs, uniqueness, public-ID caveats, factories, and generateFunctionId precedence.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added fluent id() support for server functions (including factory-based usage) to keep function identity stable across file moves and renames.
    • Dev/build compilation now supports manual ID overrides with stricter validation and collision handling, including proper reservation release during HMR updates.
  • Documentation

    • Added a “Manual function IDs” guide with formatting rules, collision behavior, and security guidance (IDs are visible in browser/network activity).
  • Tests

    • Added type-level and compilation/Vite coverage for id() chaining, invalid/dynamic IDs, duplicate detection, deduping, and expected compiled RPC output.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds .id() chaining to the createServerFn builder, allowing users to assign stable string identifiers to server functions. The feature spans the client-side fluent API types, a Babel/AST compiler pass for compile-time validation and deduplication, and the Vite dev-server's virtual module resolution path for mapping manual IDs back to their source modules.

Changes

Manual server function ID support

Layer / File(s) Summary
Client builder: id option, types, and fluent API
packages/start-client-core/src/createServerFn.ts, packages/start-client-core/src/tests/createServerFn.test-d.ts
ServerFnBaseOptions gains id?: string; six new fluent interfaces model the .id() chain stage; ServerFnBuilder, ServerFnAfterMiddleware, and ServerFnAfterValidator extend ServerFnId; runtime .id(id) method merges the ID into options; fun(options) strips inherited id before producing a handler; type-level tests verify chaining and factory-child behavior.
Compiler infrastructure: reserveFunctionId, methodChain.id, and context wiring
packages/start-plugin-core/src/start-compiler/types.ts, packages/start-plugin-core/src/start-compiler/compiler.ts
CompilationContext gains reserveFunctionId: (id: string) => boolean; MethodChainPaths gains `id: MethodCallInfo
Compile-time ID extraction, validation, deduplication, and AST stripping
packages/start-plugin-core/src/start-compiler/handleCreateServerFn.ts
MANUAL_SERVER_FN_ID_REGEX validates URL-safe path segment format; getManualServerFnId extracts and validates the .id() string literal argument; handleCreateServerFn prefers the manual ID over generateFunctionId, checks for duplicates/conflicts via serverFnsById/knownFns/reserveFunctionId, and strips the .id() call from the AST.
Vite dev-server: ViteDevServerFnImport and validate virtual module
packages/start-plugin-core/src/vite/start-compiler-plugin/module-specifier.ts, packages/start-plugin-core/src/vite/start-compiler-plugin/plugin.ts
Exports ViteDevServerFnImport type and getViteDevServerFnImport (resolves via serverFnsById or base64url-JSON fallback); the validate-server-fn-id virtual module now returns export const devServerFn = ... for both already-registered and post-lazy-compilation paths; the dev validator template imports { devServerFn } directly instead of inline-decoding.
Tests and documentation
packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts, packages/start-plugin-core/tests/vite/start-compiler-utils.test.ts, docs/start/framework/react/guide/server-functions.md
Compiler tests cover output format, metadata registration, dynamic-ID rejection, invalid-ID rejection, duplicate rejection, and auto-ID deduplication in both standard and dev-mode collision scenarios; Vite util tests cover registered and fallback resolution; docs add a "Manual function IDs" section with factory guidance and a public-ID security warning.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

package: start-plugin-core, package: start-client-core, documentation

Poem

🐇 Hopping through the AST with glee,
I planted .id('my-fn') just for thee.
No more secret paths in base64 disguise—
A stable name that builders recognize!
Duplicates? The compiler shouts "No way!"
One bunny, one ID, here to stay. 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title '[feat]: Add stable IDs for server functions' directly and clearly describes the main feature being introduced: stable identifiers for server functions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nx-cloud

nx-cloud Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit b8bdb89

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 13m 16s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 47s View ↗

☁️ Nx Cloud last updated this comment at 2026-06-24 00:25:58 UTC

@codspeed-hq

codspeed-hq Bot commented Jun 23, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 3.18%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 3 improved benchmarks
❌ 3 regressed benchmarks
✅ 138 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory mem serialization-payload (solid) 6.8 MB 7.1 MB -3.59%
Memory mem request-churn (solid) 1.1 MB 1.2 MB -3.29%
Memory mem streaming-peak chunked (vue) 11.9 MB 12.3 MB -3.26%
Memory mem peak-large-page (solid) 3.9 MB 3.4 MB +14.16%
Memory mem aborted-requests (solid) 2.4 MB 2.1 MB +12.53%
Memory mem aborted-requests (vue) 1,021 KB 980.3 KB +4.15%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing LadyBluenotes:stable-serverfn-ids (599f31b) with main (ba52d2b)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (80d098f) during the generation of this report, so ba52d2b was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/start-plugin-core/src/vite/start-compiler-plugin/module-specifier.ts (1)

67-77: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Tighten typing of the decoded payload.

JSON.parse(...) returns any, so decoded.file/decoded.export accesses bypass strict checks. Type it as unknown and narrow explicitly to keep the validation type-safe.

♻️ Optional: narrow from unknown
-    const decoded = JSON.parse(Buffer.from(id, 'base64url').toString('utf8'))
-    if (
-      typeof decoded.file === 'string' &&
-      typeof decoded.export === 'string'
-    ) {
+    const decoded: unknown = JSON.parse(
+      Buffer.from(id, 'base64url').toString('utf8'),
+    )
+    if (
+      decoded !== null &&
+      typeof decoded === 'object' &&
+      typeof (decoded as Record<string, unknown>).file === 'string' &&
+      typeof (decoded as Record<string, unknown>).export === 'string'
+    ) {
       return {
-        file: decoded.file,
-        export: decoded.export,
+        file: (decoded as { file: string }).file,
+        export: (decoded as { export: string }).export,
       }
     }

As per coding guidelines: "Use TypeScript strict mode with extensive type safety".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/start-plugin-core/src/vite/start-compiler-plugin/module-specifier.ts`
around lines 67 - 77, The variable `decoded` from `JSON.parse()` currently has
type `any`, which bypasses TypeScript's strict mode checks. Change the code to
explicitly type `decoded` as `unknown` instead of relying on the implicit `any`
type from JSON.parse, then use the existing typeof checks to narrow the type
safely. This ensures the property accesses to `decoded.file` and
`decoded.export` are properly validated before use and maintain type safety
throughout the validation block.

Source: Coding guidelines

packages/start-plugin-core/src/vite/start-compiler-plugin/plugin.ts (1)

552-559: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate devServerFn module construction.

Lines 553-559 and 600-606 are identical. Extract a small local helper to avoid drift since both build the same virtual module source.

♻️ Optional helper
const buildDevServerFnModule = (fnId: string) =>
  `export const devServerFn = ${JSON.stringify(
    getViteDevServerFnImport(
      fnId,
      serverFnsById,
      createViteDevServerFnModuleSpecifierEncoder(root),
    ),
  )}`

Then return buildDevServerFnModule(fnId) in both branches.

Also applies to: 599-607

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/start-plugin-core/src/vite/start-compiler-plugin/plugin.ts` around
lines 552 - 559, The code that constructs the devServerFn export string is
duplicated in two separate locations. Extract this duplicate logic into a local
helper function named buildDevServerFnModule that accepts fnId as a parameter.
The helper should contain the logic that calls getViteDevServerFnImport with
fnId, serverFnsById, and createViteDevServerFnModuleSpecifierEncoder(root),
wraps it in JSON.stringify, and returns the template literal string. Replace
both occurrences of this duplicate code with calls to the new helper function to
eliminate code drift and improve maintainability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/start-plugin-core/src/start-compiler/compiler.ts`:
- Around line 675-681: The issue is that reserveFunctionId only checks this
compiler instance's functionIds set, but generateFunctionId returns without
consulting this set before generating an ID, allowing a manually reserved ID to
later collide with an auto-generated ID. Additionally, known IDs from
getKnownServerFns() are not included in the collision check. Update
generateFunctionId to consult both this.functionIds and the known server
function IDs from getKnownServerFns() before returning a generated ID, ensuring
auto-generated IDs follow the same collision detection path as manually reserved
IDs.

---

Nitpick comments:
In
`@packages/start-plugin-core/src/vite/start-compiler-plugin/module-specifier.ts`:
- Around line 67-77: The variable `decoded` from `JSON.parse()` currently has
type `any`, which bypasses TypeScript's strict mode checks. Change the code to
explicitly type `decoded` as `unknown` instead of relying on the implicit `any`
type from JSON.parse, then use the existing typeof checks to narrow the type
safely. This ensures the property accesses to `decoded.file` and
`decoded.export` are properly validated before use and maintain type safety
throughout the validation block.

In `@packages/start-plugin-core/src/vite/start-compiler-plugin/plugin.ts`:
- Around line 552-559: The code that constructs the devServerFn export string is
duplicated in two separate locations. Extract this duplicate logic into a local
helper function named buildDevServerFnModule that accepts fnId as a parameter.
The helper should contain the logic that calls getViteDevServerFnImport with
fnId, serverFnsById, and createViteDevServerFnModuleSpecifierEncoder(root),
wraps it in JSON.stringify, and returns the template literal string. Replace
both occurrences of this duplicate code with calls to the new helper function to
eliminate code drift and improve maintainability.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d34eb9e0-a53d-48c9-ab74-8f67b9b7ad49

📥 Commits

Reviewing files that changed from the base of the PR and between 80d098f and 4a35266.

📒 Files selected for processing (10)
  • docs/start/framework/react/guide/server-functions.md
  • packages/start-client-core/src/createServerFn.ts
  • packages/start-client-core/src/tests/createServerFn.test-d.ts
  • packages/start-plugin-core/src/start-compiler/compiler.ts
  • packages/start-plugin-core/src/start-compiler/handleCreateServerFn.ts
  • packages/start-plugin-core/src/start-compiler/types.ts
  • packages/start-plugin-core/src/vite/start-compiler-plugin/module-specifier.ts
  • packages/start-plugin-core/src/vite/start-compiler-plugin/plugin.ts
  • packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts
  • packages/start-plugin-core/tests/vite/start-compiler-utils.test.ts

Comment thread packages/start-plugin-core/src/start-compiler/compiler.ts Outdated
@pkg-pr-new

pkg-pr-new Bot commented Jun 23, 2026

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/@tanstack/arktype-adapter@7682

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/@tanstack/eslint-plugin-router@7682

@tanstack/eslint-plugin-start

npm i https://pkg.pr.new/@tanstack/eslint-plugin-start@7682

@tanstack/history

npm i https://pkg.pr.new/@tanstack/history@7682

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/@tanstack/nitro-v2-vite-plugin@7682

@tanstack/react-router

npm i https://pkg.pr.new/@tanstack/react-router@7682

@tanstack/react-router-devtools

npm i https://pkg.pr.new/@tanstack/react-router-devtools@7682

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/@tanstack/react-router-ssr-query@7682

@tanstack/react-start

npm i https://pkg.pr.new/@tanstack/react-start@7682

@tanstack/react-start-client

npm i https://pkg.pr.new/@tanstack/react-start-client@7682

@tanstack/react-start-rsc

npm i https://pkg.pr.new/@tanstack/react-start-rsc@7682

@tanstack/react-start-server

npm i https://pkg.pr.new/@tanstack/react-start-server@7682

@tanstack/router-cli

npm i https://pkg.pr.new/@tanstack/router-cli@7682

@tanstack/router-core

npm i https://pkg.pr.new/@tanstack/router-core@7682

@tanstack/router-devtools

npm i https://pkg.pr.new/@tanstack/router-devtools@7682

@tanstack/router-devtools-core

npm i https://pkg.pr.new/@tanstack/router-devtools-core@7682

@tanstack/router-generator

npm i https://pkg.pr.new/@tanstack/router-generator@7682

@tanstack/router-plugin

npm i https://pkg.pr.new/@tanstack/router-plugin@7682

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/@tanstack/router-ssr-query-core@7682

@tanstack/router-utils

npm i https://pkg.pr.new/@tanstack/router-utils@7682

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/@tanstack/router-vite-plugin@7682

@tanstack/solid-router

npm i https://pkg.pr.new/@tanstack/solid-router@7682

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/@tanstack/solid-router-devtools@7682

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/@tanstack/solid-router-ssr-query@7682

@tanstack/solid-start

npm i https://pkg.pr.new/@tanstack/solid-start@7682

@tanstack/solid-start-client

npm i https://pkg.pr.new/@tanstack/solid-start-client@7682

@tanstack/solid-start-server

npm i https://pkg.pr.new/@tanstack/solid-start-server@7682

@tanstack/start-client-core

npm i https://pkg.pr.new/@tanstack/start-client-core@7682

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/@tanstack/start-fn-stubs@7682

@tanstack/start-plugin-core

npm i https://pkg.pr.new/@tanstack/start-plugin-core@7682

@tanstack/start-server-core

npm i https://pkg.pr.new/@tanstack/start-server-core@7682

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/@tanstack/start-static-server-functions@7682

@tanstack/start-storage-context

npm i https://pkg.pr.new/@tanstack/start-storage-context@7682

@tanstack/valibot-adapter

npm i https://pkg.pr.new/@tanstack/valibot-adapter@7682

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/@tanstack/virtual-file-routes@7682

@tanstack/vue-router

npm i https://pkg.pr.new/@tanstack/vue-router@7682

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/@tanstack/vue-router-devtools@7682

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/@tanstack/vue-router-ssr-query@7682

@tanstack/vue-start

npm i https://pkg.pr.new/@tanstack/vue-start@7682

@tanstack/vue-start-client

npm i https://pkg.pr.new/@tanstack/vue-start-client@7682

@tanstack/vue-start-server

npm i https://pkg.pr.new/@tanstack/vue-start-server@7682

@tanstack/zod-adapter

npm i https://pkg.pr.new/@tanstack/zod-adapter@7682

commit: 599f31b

@nx-cloud nx-cloud Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

At least one additional CI pipeline execution has run since the conclusion below was written and it may no longer be applicable.

Nx Cloud has identified a possible root cause for your failed CI:

We determined this failure is an environment issue unrelated to the PR changes. The error occurs inside Playwright's own FullConfigInternal constructor, where the runtime environment has a frozen/sealed object preventing Playwright from initializing its config — a problem no code change in this PR could cause or fix. We recommend re-running the CI pipeline to recover from this transient environment state.

No code changes were suggested for this issue.

You can trigger a rerun by pushing an empty commit:

git commit --allow-empty -m "chore: trigger rerun"
git push

Nx Cloud View detailed reasoning on Nx Cloud ↗


🎓 Learn more about Self-Healing CI on nx.dev

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/start-plugin-core/src/start-compiler/compiler.ts`:
- Around line 713-721: The reserveFunctionId method adds function IDs to the
functionIds set, but the invalidateModules method does not clear these reserved
IDs when modules are invalidated, causing stale reservations to persist in
long-lived dev compilers. Modify the reserveFunctionId method to track which
module each function ID belongs to (e.g., store both the ID and its owning
module), and then update invalidateModules to iterate through and remove
function ID reservations that belonged to the invalidated modules from the
functionIds set.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f2d45d44-ba44-4ee9-a0ad-0c3fb0d57ddc

📥 Commits

Reviewing files that changed from the base of the PR and between 270b7c8 and e01824c.

📒 Files selected for processing (2)
  • packages/start-plugin-core/src/start-compiler/compiler.ts
  • packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts

Comment thread packages/start-plugin-core/src/start-compiler/compiler.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/start-plugin-core/src/vite/start-compiler-plugin/plugin.ts (1)

574-580: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the duplicated devServerFn module construction.

The two branches build the exact same export const devServerFn = ... string and each re-creates the module-specifier encoder via createViteDevServerFnModuleSpecifierEncoder(root). Consider a small helper to keep both registration paths in sync and avoid rebuilding the encoder twice per resolution.

♻️ Suggested helper
+        const buildDevServerFnModule = (id: string) =>
+          `export const devServerFn = ${JSON.stringify(
+            getViteDevServerFnImport(
+              id,
+              serverFnsById,
+              createViteDevServerFnModuleSpecifierEncoder(root),
+            ),
+          )}`

Then both branches become return buildDevServerFnModule(fnId).

Also applies to: 621-627

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/start-plugin-core/src/vite/start-compiler-plugin/plugin.ts` around
lines 574 - 580, The code contains duplicate construction of the `export const
devServerFn = ...` module string in two separate branches (around lines 574-580
and 621-627), and each branch independently creates the module-specifier encoder
via createViteDevServerFnModuleSpecifierEncoder(root). Extract this shared logic
into a helper function (such as buildDevServerFnModule) that takes fnId as a
parameter and handles the getViteDevServerFnImport and JSON.stringify logic,
while moving the encoder creation to a single location at a higher scope so it
is created only once and can be reused by both branches. Replace both duplicated
return statements with calls to this new helper function to keep the
registration paths in sync and avoid rebuilding the encoder twice.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/start-plugin-core/src/vite/start-compiler-plugin/plugin.ts`:
- Around line 574-580: The code contains duplicate construction of the `export
const devServerFn = ...` module string in two separate branches (around lines
574-580 and 621-627), and each branch independently creates the module-specifier
encoder via createViteDevServerFnModuleSpecifierEncoder(root). Extract this
shared logic into a helper function (such as buildDevServerFnModule) that takes
fnId as a parameter and handles the getViteDevServerFnImport and JSON.stringify
logic, while moving the encoder creation to a single location at a higher scope
so it is created only once and can be reused by both branches. Replace both
duplicated return statements with calls to this new helper function to keep the
registration paths in sync and avoid rebuilding the encoder twice.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a30191b8-8cda-4449-9772-6dce6e86de76

📥 Commits

Reviewing files that changed from the base of the PR and between e01824c and 599f31b.

📒 Files selected for processing (4)
  • packages/start-plugin-core/src/start-compiler/compiler.ts
  • packages/start-plugin-core/src/start-compiler/handleCreateServerFn.ts
  • packages/start-plugin-core/src/vite/start-compiler-plugin/plugin.ts
  • packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/start-plugin-core/src/start-compiler/compiler.ts
  • packages/start-plugin-core/src/start-compiler/handleCreateServerFn.ts
  • packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts

@LadyBluenotes

Copy link
Copy Markdown
Member Author

@schiller-manuel, one dev-mode nuance I wanted to get your 2c on:

Manual IDs are intentionally opaque, e.g. .id('get-user'). In the normal dev flow, that works because the source module transform registers the ID in serverFnsById, and the dev resolver resolves it from there.

Generated dev IDs also have a fallback path because they already encode { file, export }, so the resolver can recover if the ID is seen before registration.

For this PR, I kept manual IDs on the registration-based path rather than adding a new discovery mechanism for opaque IDs. I think that adding pre-registration discovery for manual IDs would be a separate dev-server enhancement, not required for the core stable-ID behavior.

Does that seem right, or is there an existing dev path you’d expect this to hook into?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant