Skip to content

feat(nuxt): Parametrize SSR routes #16843

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
Open

Conversation

s1gr1d
Copy link
Member

@s1gr1d s1gr1d commented Jul 8, 2025

Adds route parametrization to SSR server routes.

The parametrized route data is gathered during build time and saved in a virtual file (added with addTemplate) which can hand-over the data to be accessed during runtime.

The nuxt-3-min test (Nuxt 3.7) shows that the route parametrization does not work yet with this version. From Nuxt 3.9 onwards, it works. This is fine, as most people are on a more recent version anyways.

part of #16684

@s1gr1d s1gr1d force-pushed the sig/param-routes-nuxt-ssr branch from ea09c04 to 8492c82 Compare July 8, 2025 14:06
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

@s1gr1d
Copy link
Member Author

s1gr1d commented Jul 8, 2025

I still need to look into why this is failing in nuxt-3-min. The pages:extend hook should already be available in version 3.7, but the hook is not called 🤔

}

const method = ssrContext?.event?._method || 'GET';
const parametrizedTransactionName = `${method.toUpperCase()} ${routeInfo.parametrizedRoute}`;
Copy link
Member

Choose a reason for hiding this comment

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

m: We create the parametrizedTransactionName but don't update the span name?

Copy link
Member Author

@s1gr1d s1gr1d Jul 9, 2025

Choose a reason for hiding this comment

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

oh that's left from before the last commit 😅
was using updateSpanName before, but I only need to set 'http.route': routeInfo.parametrizedRoute to update the name.

* An array of NuxtPage objects representing the build-time pages data.
* Example: [{ name: 'some-path', path: '/some/path' }, { name: 'user-userId', path: '/user/:userId()' }]
*/
export function extractParametrizedRouteFromContext(
Copy link
Member

Choose a reason for hiding this comment

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

l: should we memoize this function?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah the function is quite expensive as the lookup is hard :/

I added some general, small optimizations for the function.

Using the currentUrl is not possible as it includes the parameters and that would blow up.
And the only way to memoize the result is using the ssrContextModules as key (which is quite complex as this can be a large Set) and this Set has a different reference, every time a request is sent. So the key has to be created on every request, as I cannot use the Set itself as a key.

However, as I think the key generation regardless its overhead still makes sense, I added it now.

});

nuxt.hooks.hook('pages:extend', pages => {
pagesDataTemplate.getContents = () => `export default ${JSON.stringify(pages, null, 2)};`;
Copy link
Member

Choose a reason for hiding this comment

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

m: So stringifying all of the pages can get pretty big from what I can see in the NuxtPage type.

Perhaps we should just save a subset? We really only need the file and the path from looking at extractParametrizedRouteFromContext.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch, I also filtered for only dynamic pages.

s1gr1d added 4 commits July 9, 2025 09:19
# Conflicts:
#	dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/tracing.test.ts
#	dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.test.ts
#	dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/tracing.test.ts
#	dev-packages/e2e-tests/test-applications/nuxt-3/tests/tracing.test.ts
#	dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts
@s1gr1d s1gr1d force-pushed the sig/param-routes-nuxt-ssr branch from 9aff99a to b3bbf0c Compare July 9, 2025 10:32
cursor[bot]

This comment was marked as outdated.

Copy link
Member

@Lms24 Lms24 left a comment

Choose a reason for hiding this comment

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

Great work! Had some questions about our matching algorithm. IIUC we need a similar logic in Next and possibly other frameworks at some point. Might make sense to think about extracing this in the future because matching routes is far from trivial. But obviously this is a something to follow up on later :)

file: '/app/pages/test-param/[param].vue',
}),
],
expected: { parametrizedRoute: '/test-param/:param()' },
Copy link
Member

Choose a reason for hiding this comment

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

l/q: what's the reason for the brackets in the parameters (:param_()_)? Is this a Nuxt routing covention/something users are used to?

});

describe('multiple routes matching', () => {
it('should find the correct route when multiple routes exist', () => {
Copy link
Member

@Lms24 Lms24 Jul 9, 2025

Choose a reason for hiding this comment

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

sticking with this example: If I have two routes,

file: '/app/pages/test-param/user/[userId].vue',
file: '/app/pages/test-param/user/abc.vue',

do we still correctly identify the respective routes for urls /test-param/user/123 and /test-param/user/abc?

(Sorry in case I missed such an example in already existing tests. If not, it might be a good test case)

Copy link
Member

Choose a reason for hiding this comment

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

Related but not also rather a question: Does this handle catch-all routes?

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.

3 participants