diff --git a/.changeset/fuzzy-ravens-route.md b/.changeset/fuzzy-ravens-route.md new file mode 100644 index 00000000..3920e838 --- /dev/null +++ b/.changeset/fuzzy-ravens-route.md @@ -0,0 +1,5 @@ +--- +'@tanstack/create': patch +--- + +Configure the Paraglide add-on with TanStack Router URL rewrites and request-scoped server middleware. diff --git a/packages/create/src/frameworks/react/add-ons/paraglide/assets/src/server.ts.ejs b/packages/create/src/frameworks/react/add-ons/paraglide/assets/src/server.ts.ejs new file mode 100644 index 00000000..d4dc80a8 --- /dev/null +++ b/packages/create/src/frameworks/react/add-ons/paraglide/assets/src/server.ts.ejs @@ -0,0 +1,8 @@ +import { paraglideMiddleware } from './paraglide/server.js' +import handler from '@tanstack/react-start/server-entry' + +export default { + fetch(req: Request): Promise { + return paraglideMiddleware(req, () => handler.fetch(req)) + }, +} diff --git a/packages/create/src/frameworks/react/project/base/src/router.tsx.ejs b/packages/create/src/frameworks/react/project/base/src/router.tsx.ejs index 96459e0c..6a01f0d2 100644 --- a/packages/create/src/frameworks/react/project/base/src/router.tsx.ejs +++ b/packages/create/src/frameworks/react/project/base/src/router.tsx.ejs @@ -1,5 +1,8 @@ import { createRouter as createTanStackRouter } from '@tanstack/react-router' import { routeTree } from './routeTree.gen' +<% if (addOnEnabled.paraglide) { %> +import { deLocalizeUrl, localizeUrl } from './paraglide/runtime' +<% } %> <% if (addOnEnabled['tanstack-query']) { %> import type { ReactNode } from 'react' import { QueryClient } from '@tanstack/react-query' @@ -20,6 +23,12 @@ export function getRouter() { scrollRestoration: true, defaultPreload: 'intent', defaultPreloadStaleTime: 0, + <% if (addOnEnabled.paraglide) { %> + rewrite: { + input: ({ url }) => deLocalizeUrl(url), + output: ({ url }) => localizeUrl(url), + }, + <% } %> <% if (addOnEnabled.tRPC) { %> Wrap: (props: { children: ReactNode }) => { return ( diff --git a/packages/create/tests/paraglide-addon.test.ts b/packages/create/tests/paraglide-addon.test.ts new file mode 100644 index 00000000..4e2b13c8 --- /dev/null +++ b/packages/create/tests/paraglide-addon.test.ts @@ -0,0 +1,80 @@ +import { afterEach, describe, expect, it, vi } from 'vitest' + +import { + finalizeAddOns, + populateAddOnOptionsDefaults, +} from '../src/add-ons.js' +import { createApp } from '../src/create-app.js' +import { createMemoryEnvironment } from '../src/environment.js' +import { createFrameworkDefinition } from '../src/frameworks/react/index.js' + +import type { Framework, FrameworkDefinition, Options } from '../src/types.js' + +function frameworkFromDefinition(definition: FrameworkDefinition): Framework { + const { addOns, base, ...framework } = definition + + return { + ...framework, + getFiles: () => Promise.resolve(Object.keys(base)), + getFileContents: (path: string) => Promise.resolve(base[path]), + getDeletedFiles: () => Promise.resolve([]), + getAddOns: () => addOns, + } +} + +afterEach(() => { + vi.unstubAllGlobals() +}) + +describe('Paraglide add-on', () => { + it('configures localized routing and request-scoped SSR', async () => { + vi.stubGlobal( + 'fetch', + vi.fn( + async () => + new Response(JSON.stringify({ version: '1.0.0' }), { status: 200 }), + ), + ) + + const framework = frameworkFromDefinition(createFrameworkDefinition()) + const chosenAddOns = await finalizeAddOns(framework, 'file-router', [ + 'paraglide', + ]) + const options = { + projectName: 'paraglide-app', + targetDir: '/paraglide-app', + framework, + mode: 'file-router', + typescript: true, + tailwind: true, + packageManager: 'pnpm', + git: false, + install: false, + intent: false, + includeExamples: true, + chosenAddOns, + addOnOptions: populateAddOnOptionsDefaults(chosenAddOns), + } as Options + const { environment, output } = createMemoryEnvironment() + + await createApp(environment, options) + + const router = output.files['/paraglide-app/src/router.tsx'] + expect(router).toContain( + "import { deLocalizeUrl, localizeUrl } from './paraglide/runtime'", + ) + expect(router).toContain('input: ({ url }) => deLocalizeUrl(url)') + expect(router).toContain('output: ({ url }) => localizeUrl(url)') + + const server = output.files['/paraglide-app/src/server.ts'] + expect(server).toContain( + "import { paraglideMiddleware } from './paraglide/server.js'", + ) + expect(server).toContain( + "import handler from '@tanstack/react-start/server-entry'", + ) + expect(server).toContain( + 'return paraglideMiddleware(req, () => handler.fetch(req))', + ) + }) +})