diff --git a/packages/plugin-rsc/e2e/source-map.test.ts b/packages/plugin-rsc/e2e/source-map.test.ts index 06de38eb0..9ad059dc7 100644 --- a/packages/plugin-rsc/e2e/source-map.test.ts +++ b/packages/plugin-rsc/e2e/source-map.test.ts @@ -189,6 +189,30 @@ test.describe('source map', () => { } }) } + + test('preserves Server Function names in stack traces', async ({ page }) => { + await page.goto(f.url('/server-function-name')) + await waitForHydration(page) + + const cases = [ + { + referenceName: 'module-function-name', + functionName: 'moduleFunctionName', + }, + { + referenceName: 'inline-function-name', + functionName: 'inlineFunctionName', + }, + ] + + for (const item of cases) { + const button = page.getByRole('button', { + name: new RegExp(`^${item.referenceName}:`), + }) + await button.click() + await expect(button).toContainText(`at ${item.functionName} (`) + } + }) }) async function createFunctionSourceMapResolver(page: Page, baseURL: string) { diff --git a/packages/plugin-rsc/examples/source-map/src/features/server-function-name/action.ts b/packages/plugin-rsc/examples/source-map/src/features/server-function-name/action.ts new file mode 100644 index 000000000..92b4bbb17 --- /dev/null +++ b/packages/plugin-rsc/examples/source-map/src/features/server-function-name/action.ts @@ -0,0 +1,5 @@ +'use server' + +export async function moduleFunctionName() { + return new Error().stack?.split('\n')[1] ?? '' +} diff --git a/packages/plugin-rsc/examples/source-map/src/features/server-function-name/server.tsx b/packages/plugin-rsc/examples/source-map/src/features/server-function-name/server.tsx new file mode 100644 index 000000000..3938164e3 --- /dev/null +++ b/packages/plugin-rsc/examples/source-map/src/features/server-function-name/server.tsx @@ -0,0 +1,29 @@ +import { SourceLocationCase } from '../../client' +import { moduleFunctionName } from './action' + +export function ServerFunctionName() { + async function inlineFunctionName() { + 'use server' + return new Error().stack?.split('\n')[1] ?? '' + } + + return ( +
+

Server Function names

+ +
+ ) +} diff --git a/packages/plugin-rsc/examples/source-map/src/root.tsx b/packages/plugin-rsc/examples/source-map/src/root.tsx index 100141c31..431f7396e 100644 --- a/packages/plugin-rsc/examples/source-map/src/root.tsx +++ b/packages/plugin-rsc/examples/source-map/src/root.tsx @@ -6,6 +6,7 @@ import { MultipleExports } from './features/multiple-exports/server' import { NamedFunction } from './features/named-function/server' import { ServerActionError } from './features/server-action-error/server' import { ServerComponentError } from './features/server-component-error/server' +import { ServerFunctionName } from './features/server-function-name/server' import { ServerReferenceFromClient } from './features/server-reference-from-client/server' import { Specifiers } from './features/specifiers/server' import { TypescriptTsx } from './features/typescript-tsx/server' @@ -65,6 +66,13 @@ const routes = [ description: 'Two generated registrations from one module.', render: () => , }, + { + path: '/server-function-name', + title: 'Server Function names', + description: + 'Module-level and inline Server Functions preserve their source names in stack traces.', + render: () => , + }, { path: '/server-action-error', title: 'Server Action error',