Skip to content

Conversation

zenios
Copy link
Contributor

@zenios zenios commented Oct 5, 2025

If not provided, the default (basename_functionName) will be used in development and sha256 of the default for production

Summary by CodeRabbit

  • New Features
    • Add optional generateFunctionId hook to produce consistent, URL-safe, deduplicated server function IDs across client/SSR/server; env options now accept the hook and envName.
  • Tests
    • Updated and added E2E tests to verify server function URL patterns and constant-ID behavior.
  • Documentation
    • New docs section explaining Function ID generation, defaults, deduplication, and customization hook.
  • Chores
    • Added dependency to improve path handling.

If not provided, the default (basename_functionName) will be used in development and sha256 of the default for production
Copy link
Contributor

coderabbitai bot commented Oct 5, 2025

Walkthrough

Adds a customizable generateFunctionId hook and threads it through directive and server function plugins, Start plugin schema/options, and E2E configs; normalizes filenames with path.relative, centralizes deduplicated URL-safe functionId generation, and adds the pathe dependency.

Changes

Cohort / File(s) Summary
Directive functions: generateFunctionId hook & ID normalization
packages/directive-functions-plugin/src/compilers.ts, packages/directive-functions-plugin/src/index.ts
Adds public type GenerateFunctionIdFn and generateFunctionId option; computes relative filenames with path.relative, invokes provided generator, applies URL-safety and deduplication, and threads the option through transform/compile flows.
Directive plugin dependency
packages/directive-functions-plugin/package.json
Adds dependency "pathe": "^2.0.3".
Server functions: centralized generateFunctionId & env options
packages/server-functions-plugin/src/index.ts
Adds generateFunctionId?: GenerateFunctionIdFnOptional and envName?: string; replaces exported env opts shape with Omit<ServerFnPluginOpts,'ssr'>; implements buildGenerateFunctionId with dev/prod seeding and collision deduplication; threads generation through client/ssr/server/manifest flows.
Start plugin core: thread generateFunctionId
packages/start-plugin-core/src/plugin.ts
Adds optional generateFunctionId to TanStackServerFnPluginEnv (sourced from startPluginOpts?.serverFns?.generateFunctionId) and passes it into manifest resolution.
Start schema: validate generateFunctionId hook
packages/start-plugin-core/src/schema.ts
Extends tanstackStartOptionsSchema.serverFns with optional generateFunctionId taking `{ filename: string, functionName: string } => string
E2E: custom basepath expectation update
e2e/react-start/custom-basepath/tests/navigation.spec.ts
Changes assertion from exact action string to regex ensuring action begins with /custom/basepath/_serverFn/.
E2E: constant ID override and tests
e2e/react-start/server-functions/tests/server-functions.spec.ts, e2e/react-start/server-functions/vite.config.ts
Adds Vite config to override select function IDs to 'constant_id' via serverFns.generateFunctionId; adds test asserting form action starts with / _serverFn/constant_id.
Directive plugin tests: deterministic ids
packages/directive-functions-plugin/tests/compiler.test.ts
Test updates: adds makeFunctionIdUrlSafe and generateFunctionId helpers; wires generateFunctionId into client/ssr/server test configs and adjusts test filenames for determinism.
Docs: Function ID generation
docs/start/framework/react/server-functions.md
Adds "Function ID generation" subsection describing dev/prod defaults, de-duplication, and customization via generateFunctionId.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Dev as Dev Config
  participant DF as Directive Plugin
  participant SF as Server Fn Plugin
  participant Gen as buildGenerateFunctionId
  participant MF as Manifest

  Dev->>DF: supply generateFunctionId? (filename, functionName)
  Dev->>SF: supply generateFunctionId? / envName?
  DF->>Gen: request id (relativeFilename, functionName)
  Gen-->>DF: candidate id (user or seeded)
  DF->>Gen: normalize URL-safe & dedupe
  DF-->>MF: register handler with final id
  SF->>Gen: same generation & dedupe flow
  SF-->>MF: include ids in manifest
  MF-->>Dev: emitted manifest with unified ids
Loading
sequenceDiagram
  autonumber
  participant Client as Client
  participant Server as Server Runtime
  participant MF as Manifest

  Client->>Server: POST /_serverFn/<id>/...
  Server->>MF: lookup <id>
  MF-->>Server: handler reference
  Server-->>Client: invoke handler -> response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • schiller-manuel
  • birkskyum

Poem

I hopped through paths and trimmed a name,
kept IDs steady, tidy, and tame.
Dev seeds are clear, prod gets its hash,
collisions nudged with a tiny dash.
A rabbit's wink — the IDs all match 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly and concisely summarizes the primary change by stating that the pull request adds support for customizable functionId generation, which directly reflects the core objective of the changeset across plugins, tests, and documentation without unnecessary detail or ambiguity.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3a67fc9 and ad7bd9d.

📒 Files selected for processing (1)
  • docs/start/framework/react/server-functions.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/start/framework/react/server-functions.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Preview
  • GitHub Check: Test

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 and usage tips.

Copy link

nx-cloud bot commented Oct 5, 2025

View your CI Pipeline Execution ↗ for commit ad7bd9d

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

☁️ Nx Cloud last updated this comment at 2025-10-05 21:33:55 UTC

Copy link

pkg-pr-new bot commented Oct 5, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@5373

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@5373

@tanstack/eslint-plugin-router

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

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@5373

@tanstack/nitro-v2-vite-plugin

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

@tanstack/react-router

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

@tanstack/react-router-devtools

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

@tanstack/react-router-ssr-query

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

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@5373

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@5373

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@5373

@tanstack/router-cli

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

@tanstack/router-core

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

@tanstack/router-devtools

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

@tanstack/router-devtools-core

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

@tanstack/router-generator

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

@tanstack/router-plugin

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

@tanstack/router-ssr-query-core

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

@tanstack/router-utils

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

@tanstack/router-vite-plugin

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

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@5373

@tanstack/solid-router

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

@tanstack/solid-router-devtools

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

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@5373

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@5373

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@5373

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@5373

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@5373

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@5373

@tanstack/start-static-server-functions

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

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@5373

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@5373

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@5373

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@5373

commit: ad7bd9d

serverFns: z
.object({
base: z.string().optional().default('/_serverFn'),
functionId: z
Copy link
Contributor

@schiller-manuel schiller-manuel Oct 5, 2025

Choose a reason for hiding this comment

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

we need a better, more descriptive name here.
functionId makes it seem this IS the function id, but it is actually a function that generated functionIds

how about:

  • generateFunctionId
  • createFunctionId

?

i think we should call it with the raw file name and raw function name as props instead of that single string argument

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

functionId = deduplicatedId
}
}
functionId = makeFunctionIdUrlSafe(functionId)
Copy link
Contributor

Choose a reason for hiding this comment

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

i wouldnt postprocess the function id anymore.
the function id that is returned by the function id generator function must be url safe. we need to document this requirement.

then the invocation of makeFunctionIdUrlSafe can simply go into the default function id generator function for dev

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. ID generation and deduplicatoin is now the responsibility of server-functions-plugin

let deduplicatedId = generatedId
let iteration = 0
do {
deduplicatedId = `${deduplicatedId}_${++iteration}`
Copy link
Contributor

Choose a reason for hiding this comment

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

i am wondering whether we should call the function id generator function a single time at the end of the build with all of the functions?

then the function id generator function is responsible to provide unique function ids.

this ensures that we dont modfiy any of the function ids supplied by the user.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need the functionId at generation time for the replacers. We cant defer this up to the end

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb6914d and f5d22d1.

📒 Files selected for processing (6)
  • e2e/react-start/custom-basepath/tests/navigation.spec.ts (1 hunks)
  • e2e/react-start/server-functions/tests/server-functions.spec.ts (1 hunks)
  • e2e/react-start/server-functions/vite.config.ts (1 hunks)
  • packages/directive-functions-plugin/src/compilers.ts (6 hunks)
  • packages/server-functions-plugin/src/index.ts (10 hunks)
  • packages/start-plugin-core/src/schema.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/start-plugin-core/src/schema.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • e2e/react-start/server-functions/tests/server-functions.spec.ts
  • packages/server-functions-plugin/src/index.ts
  • packages/directive-functions-plugin/src/compilers.ts
  • e2e/react-start/custom-basepath/tests/navigation.spec.ts
  • e2e/react-start/server-functions/vite.config.ts
e2e/**

📄 CodeRabbit inference engine (AGENTS.md)

Store end-to-end tests under the e2e/ directory

Files:

  • e2e/react-start/server-functions/tests/server-functions.spec.ts
  • e2e/react-start/custom-basepath/tests/navigation.spec.ts
  • e2e/react-start/server-functions/vite.config.ts
🧬 Code graph analysis (1)
packages/server-functions-plugin/src/index.ts (2)
packages/directive-functions-plugin/src/compilers.ts (1)
  • FunctionIdFn (26-26)
packages/directive-functions-plugin/src/index.ts (1)
  • FunctionIdFn (20-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test
  • GitHub Check: Preview

zenios added 2 commits October 5, 2025 21:54
…cy across packages. Adjust associated logic and type definitions.

Only the internal implementation converts to url safe. If a consumer wants to use their own generator, the responsibility of generating safe urls is on them
…y. Update related types, remove legacy `currentId`, and streamline deduplication logic.

directive-functions-plugin does not generate functionIds anymore. This is the responsibility of the server-functions-plugin
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/directive-functions-plugin/src/compilers.ts (1)

463-466: Consider simplifying the type assertion.

The type assertion is technically correct but verbose. Since split('?') always returns a non-empty array, you could simplify this to:

const [baseFilename = '', ..._searchParams] = opts.filename.split('?')

Or if you prefer the assertion for explicitness, the current code is fine.

packages/server-functions-plugin/src/index.ts (1)

283-322: Document GenerateFunctionIdFnOptional behavior
Add JSDoc above GenerateFunctionIdFnOptional in packages/server-functions-plugin/src/index.ts explaining that the returned ID must be URL-safe (-, _ only), returning undefined triggers the built-in default, and duplicate IDs are automatically deduplicated.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5d22d1 and db88461.

📒 Files selected for processing (6)
  • e2e/react-start/server-functions/vite.config.ts (1 hunks)
  • packages/directive-functions-plugin/src/compilers.ts (5 hunks)
  • packages/directive-functions-plugin/src/index.ts (6 hunks)
  • packages/server-functions-plugin/src/index.ts (9 hunks)
  • packages/start-plugin-core/src/plugin.ts (1 hunks)
  • packages/start-plugin-core/src/schema.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/start-plugin-core/src/plugin.ts
  • packages/directive-functions-plugin/src/index.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • e2e/react-start/server-functions/vite.config.ts
  • packages/start-plugin-core/src/schema.ts
  • packages/server-functions-plugin/src/index.ts
  • packages/directive-functions-plugin/src/compilers.ts
e2e/**

📄 CodeRabbit inference engine (AGENTS.md)

Store end-to-end tests under the e2e/ directory

Files:

  • e2e/react-start/server-functions/vite.config.ts
packages/{*-start,start-*}/**

📄 CodeRabbit inference engine (AGENTS.md)

Name and place Start framework packages under packages/-start/ or packages/start-/

Files:

  • packages/start-plugin-core/src/schema.ts
🧬 Code graph analysis (3)
e2e/react-start/server-functions/vite.config.ts (1)
packages/router-core/src/route.ts (1)
  • id (1547-1549)
packages/server-functions-plugin/src/index.ts (1)
packages/directive-functions-plugin/src/compilers.ts (1)
  • GenerateFunctionIdFn (26-29)
packages/directive-functions-plugin/src/compilers.ts (1)
packages/directive-functions-plugin/src/index.ts (1)
  • GenerateFunctionIdFn (20-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Preview
  • GitHub Check: Test
🔇 Additional comments (6)
e2e/react-start/server-functions/vite.config.ts (1)

6-24: LGTM! Clean test setup for constant ID behavior.

The E2E test configuration correctly demonstrates the customizable generateFunctionId API. The approach of returning 'constant_id' for specific functions and undefined for others (to preserve default behavior) is clear and appropriate for testing.

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

162-171: LGTM! Schema correctly defines the customizable function ID API.

The generateFunctionId field is properly defined with the correct signature: takes { filename, functionName } and returns an optional string. This matches the GenerateFunctionIdFnOptional type and allows users to customize ID generation while falling back to defaults when undefined is returned.

packages/directive-functions-plugin/src/compilers.ts (3)

8-8: Good choice using pathe for cross-platform path normalization.

Using pathe ensures consistent forward-slash separators across Windows, macOS, and Linux, which is essential for generating stable function IDs regardless of the development platform.

Based on learnings.


26-29: LGTM! Clear type definition for required function ID generator.

The GenerateFunctionIdFn type correctly defines the required variant (non-optional return) that's used internally after the user's optional function is wrapped with defaults and deduplication.


472-478: Excellent normalization strategy for consistent function IDs.

Using path.relative to compute paths relative to the project root ensures that function IDs remain consistent across different machines and environments, which is critical for matching client and server function calls.

packages/server-functions-plugin/src/index.ts (1)

275-281: LGTM! URL-safety sanitization is correct.

The makeFunctionIdUrlSafe function properly sanitizes IDs by:

  • Replacing unsafe characters with underscores
  • Collapsing multiple underscores
  • Trimming leading/trailing underscores
  • Preserving the -- joiner

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/directive-functions-plugin/tests/compiler.test.ts (1)

6-12: Add JSDoc to clarify the transformation logic.

The makeFunctionIdUrlSafe function performs several sequential transformations that work together to produce clean, URL-safe identifiers. The cleanup on line 11 (replace(/_--/g, '--')) preserves the -- separator even when the character immediately before it was sanitized to _. This logic is subtle and would benefit from a brief JSDoc comment explaining the transformation sequence and its purpose.

Consider adding documentation like:

+/**
+ * Sanitizes a location string to be URL-safe for function IDs.
+ * Transformations applied in sequence:
+ * 1. Replace non-alphanumeric characters (except `-` and `_`) with `_`
+ * 2. Collapse multiple consecutive underscores into one
+ * 3. Trim leading/trailing underscores
+ * 4. Clean up `_--` patterns to preserve the `--` separator
+ */
 function makeFunctionIdUrlSafe(location: string): string {
   return location
     .replace(/[^a-zA-Z0-9-_]/g, '_') // Replace unsafe chars with underscore
     .replace(/_{2,}/g, '_') // Collapse multiple underscores
     .replace(/^_|_$/g, '') // Trim leading/trailing underscores
     .replace(/_--/g, '--') // Clean up the joiner
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db88461 and 713975c.

📒 Files selected for processing (1)
  • packages/directive-functions-plugin/tests/compiler.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/directive-functions-plugin/tests/compiler.test.ts
🧬 Code graph analysis (1)
packages/directive-functions-plugin/tests/compiler.test.ts (1)
packages/directive-functions-plugin/src/compilers.ts (1)
  • CompileDirectivesOpts (41-52)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test
🔇 Additional comments (2)
packages/directive-functions-plugin/tests/compiler.test.ts (2)

20-55: LGTM! Config updates correctly demonstrate the feature.

The addition of the generateFunctionId option across all three config objects (client, SSR, and server) properly demonstrates the new customization capability. The filename update to ./test-files/test.ts maintains consistency with the root path, and the test snapshots confirm that the custom function ID generation is working as expected throughout all test cases.


14-18: Path normalization is already handled by core code. The default implementation calls path.relative(opts.root, …) before invoking generateFunctionId, so the test helper correctly receives normalized filenames.

@github-actions github-actions bot added the documentation Everything documentation related label Oct 5, 2025
@schiller-manuel schiller-manuel merged commit 3c0c9cc into TanStack:main Oct 5, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants