Create a new instance of the plugin with the following options:
const TanStackServerFnsPlugin = createTanStackServerFnPlugin({
// This is the ID that will be available to look up and import
// our server function manifest and resolve its module
manifestVirtualImportId: 'tsr:server-fn-manifest',
client: {
getRuntimeCode: () =>
`import { createClientRpc } from '@tanstack/react-start/client-runtime'`,
replacer: (opts) => `createClientRpc(${JSON.stringify(opts.functionId)})`,
},
ssr: {
getRuntimeCode: () =>
`import { createSsrRpc } from '@tanstack/react-start/ssr-runtime'`,
replacer: (opts) => `createSsrRpc(${JSON.stringify(opts.functionId)})`,
},
server: {
getRuntimeCode: () =>
`import { createServerRpc } from '@tanstack/react-start/server-runtime'`,
replacer: (opts) =>
`createServerRpc(${JSON.stringify(opts.functionId)}, ${opts.fn})`,
},
})
Then you can inject the plugin into the appropriate vite config plugin arrays:
clientVitePlugins: [TanStackServerFnsPlugin.client]
ssrVitePlugins: [TanStackServerFnsPlugin.ssr]
serverVitePlugins: [TanStackServerFnsPlugin.server]
Each runtime replacement should be implemented by your framework. Generally, on the client and SSR runtimes, you'll end up using a fetch
call to call the server function your desired endpoint, like this:
function createClientRpc(functionId: string) {
const url = `${process.env.YOUR_SERVER_BASE}/_server-fn/${functionId}`
const fn = async (...args: any[]) => {
const res = await fetch(url, {
method: 'POST',
// You'll likely want to use a better serializer here
body: JSON.stringify(args),
})
return await res.json()
}
// You can also assign any other properties you want to the function
// for things like form actions, or debugging
Object.assign(fn, {
url: url,
})
return fn
}
In your server handler, you can import the manifest and use it to look up and dynamically import the server function you want to call.
import serverFnManifest from 'tsr:server-fn-manifest'
export const handler = async (req: Request) => {
const functionId = req.url.split('/').pop()
invariant(functionId, 'No function ID provided')
const fnInfo = serverFnManifest[functionId]
invariant(fn, `Server function ${functionId} not found`)
const fnModule = await fnInfo.importer()
invariant(fnModule, `Server function ${functionId} could not be imported`)
const args = await req.json()
return await fnModule(...args)