Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions e2e/start/basic/app/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Route as UsersImport } from './routes/users'
import { Route as StatusImport } from './routes/status'
import { Route as ServerFnsImport } from './routes/server-fns'
import { Route as SearchParamsImport } from './routes/search-params'
import { Route as ScriptsImport } from './routes/scripts'
import { Route as PostsImport } from './routes/posts'
import { Route as LinksImport } from './routes/links'
import { Route as IsomorphicFnsImport } from './routes/isomorphic-fns'
Expand Down Expand Up @@ -66,6 +67,12 @@ const SearchParamsRoute = SearchParamsImport.update({
getParentRoute: () => rootRoute,
} as any)

const ScriptsRoute = ScriptsImport.update({
id: '/scripts',
path: '/scripts',
getParentRoute: () => rootRoute,
} as any)

const PostsRoute = PostsImport.update({
id: '/posts',
path: '/posts',
Expand Down Expand Up @@ -266,6 +273,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof PostsImport
parentRoute: typeof rootRoute
}
'/scripts': {
id: '/scripts'
path: '/scripts'
fullPath: '/scripts'
preLoaderRoute: typeof ScriptsImport
parentRoute: typeof rootRoute
}
'/search-params': {
id: '/search-params'
path: '/search-params'
Expand Down Expand Up @@ -501,6 +515,7 @@ export interface FileRoutesByFullPath {
'/isomorphic-fns': typeof IsomorphicFnsRoute
'/links': typeof LinksRoute
'/posts': typeof PostsRouteWithChildren
'/scripts': typeof ScriptsRoute
'/search-params': typeof SearchParamsRoute
'/server-fns': typeof ServerFnsRoute
'/status': typeof StatusRoute
Expand Down Expand Up @@ -530,6 +545,7 @@ export interface FileRoutesByTo {
'/env-only': typeof EnvOnlyRoute
'/isomorphic-fns': typeof IsomorphicFnsRoute
'/links': typeof LinksRoute
'/scripts': typeof ScriptsRoute
'/search-params': typeof SearchParamsRoute
'/server-fns': typeof ServerFnsRoute
'/status': typeof StatusRoute
Expand Down Expand Up @@ -559,6 +575,7 @@ export interface FileRoutesById {
'/isomorphic-fns': typeof IsomorphicFnsRoute
'/links': typeof LinksRoute
'/posts': typeof PostsRouteWithChildren
'/scripts': typeof ScriptsRoute
'/search-params': typeof SearchParamsRoute
'/server-fns': typeof ServerFnsRoute
'/status': typeof StatusRoute
Expand Down Expand Up @@ -592,6 +609,7 @@ export interface FileRouteTypes {
| '/isomorphic-fns'
| '/links'
| '/posts'
| '/scripts'
| '/search-params'
| '/server-fns'
| '/status'
Expand Down Expand Up @@ -620,6 +638,7 @@ export interface FileRouteTypes {
| '/env-only'
| '/isomorphic-fns'
| '/links'
| '/scripts'
| '/search-params'
| '/server-fns'
| '/status'
Expand Down Expand Up @@ -647,6 +666,7 @@ export interface FileRouteTypes {
| '/isomorphic-fns'
| '/links'
| '/posts'
| '/scripts'
| '/search-params'
| '/server-fns'
| '/status'
Expand Down Expand Up @@ -679,6 +699,7 @@ export interface RootRouteChildren {
IsomorphicFnsRoute: typeof IsomorphicFnsRoute
LinksRoute: typeof LinksRoute
PostsRoute: typeof PostsRouteWithChildren
ScriptsRoute: typeof ScriptsRoute
SearchParamsRoute: typeof SearchParamsRoute
ServerFnsRoute: typeof ServerFnsRoute
StatusRoute: typeof StatusRoute
Expand All @@ -696,6 +717,7 @@ const rootRouteChildren: RootRouteChildren = {
IsomorphicFnsRoute: IsomorphicFnsRoute,
LinksRoute: LinksRoute,
PostsRoute: PostsRouteWithChildren,
ScriptsRoute: ScriptsRoute,
SearchParamsRoute: SearchParamsRoute,
ServerFnsRoute: ServerFnsRoute,
StatusRoute: StatusRoute,
Expand All @@ -722,6 +744,7 @@ export const routeTree = rootRoute
"/isomorphic-fns",
"/links",
"/posts",
"/scripts",
"/search-params",
"/server-fns",
"/status",
Expand Down Expand Up @@ -759,6 +782,9 @@ export const routeTree = rootRoute
"/posts/"
]
},
"/scripts": {
"filePath": "scripts.tsx"
},
"/search-params": {
"filePath": "search-params.tsx"
},
Expand Down
8 changes: 8 additions & 0 deletions e2e/start/basic/app/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ function RootDocument({ children }: { children: React.ReactNode }) {
>
Layout
</Link>{' '}
<Link
to="/scripts"
activeProps={{
className: 'font-bold',
}}
>
Scripts
</Link>{' '}
<Link
to="/deferred"
activeProps={{
Expand Down
33 changes: 33 additions & 0 deletions e2e/start/basic/app/routes/scripts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { createFileRoute } from '@tanstack/react-router'

const isProd = import.meta.env.PROD

export const Route = createFileRoute('/scripts')({
head: () => ({
scripts: [
{
src: 'script.js',
['data-testid']: 'script',
},
isProd
? undefined
: {
src: 'script2.js',
['data-testid']: 'script2',
},
],
}),
component: ScriptsComponent,
})

function ScriptsComponent() {
return (
<div className="p-2">
<h3>Scripts Test</h3>
<p>
Both `script.js` and `script2.js` are included in development, but only
`script.js` is included in production.
</p>
</div>
)
}
2 changes: 2 additions & 0 deletions e2e/start/basic/public/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable no-empty-file
// This empty script file is for testing purposes only
2 changes: 2 additions & 0 deletions e2e/start/basic/public/script2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable no-empty-file
// This empty script file is for testing purposes only
21 changes: 16 additions & 5 deletions e2e/start/basic/tests/base.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ test('Navigating nested layouts', async ({ page }) => {
await expect(page.locator('body')).toContainText("I'm layout B!")
})

test('Navigating to route with scripts', async ({ page }) => {
await page.goto('/')

await page.getByRole('link', { name: 'Scripts' }).click()

await expect(page.getByTestId('script')).toHaveCount(1)
await expect(page.getByTestId('script2')).toHaveCount(0)
})

test('Navigating to a not-found route', async ({ page }) => {
await page.goto('/')

Expand Down Expand Up @@ -79,10 +88,12 @@ test('invoking a server function with custom response status code', async ({
expect(response.status()).toBe(225)
expect(response.statusText()).toBe('hello')
expect(response.headers()['content-type']).toBe('application/json')
expect(await response.json()).toEqual({
result: { hello: 'world' },
context: {},
})
expect(await response.json()).toEqual(
expect.objectContaining({
result: { hello: 'world' },
context: {},
}),
)
resolve()
})
})
Expand Down Expand Up @@ -193,7 +204,7 @@ test('env-only functions can only be called on the server or client respectively
)
})

test.only('Server function can return null for GET and POST calls', async ({
test('Server function can return null for GET and POST calls', async ({
page,
}) => {
await page.goto('/server-fns')
Expand Down
2 changes: 1 addition & 1 deletion e2e/start/basic/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"include": ["**/*.ts", "**/*.tsx"],
"include": ["**/*.ts", "**/*.tsx", "public/script*.js"],
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
Expand Down
4 changes: 2 additions & 2 deletions packages/start/src/client/Scripts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export const Scripts = () => {
scripts: (
state.matches
.map((match) => match.scripts!)
.filter(Boolean)
.flat(1) as Array<RouterManagedTag>
.flat(1)
.filter(Boolean) as Array<RouterManagedTag>
).map(({ children, ...script }) => ({
tag: 'script',
attrs: {
Expand Down
49 changes: 49 additions & 0 deletions packages/start/src/client/tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,55 @@ describe('ssr scripts', () => {
`<script src="script.js"></script><script src="script2.js"></script><script src="script3.js"></script>`,
)
})

test('excludes `undefined` script values', async () => {
const rootRoute = createRootRoute({
head: () => {
return {
scripts: [
{ src: 'script.js' },
undefined, // 'script2.js' opted out by certain conditions, such as `NODE_ENV=production`.
],
}
},
component: () => {
return <Scripts />
},
})

const indexRoute = createRoute({
path: '/',
getParentRoute: () => rootRoute,
head: () => {
return {
scripts: [{ src: 'script3.js' }],
}
},
})

const router = createRouter({
history: createMemoryHistory({
initialEntries: ['/'],
}),
routeTree: rootRoute.addChildren([indexRoute]),
})

router.isServer = true

await router.load()

expect(router.state.matches.map((d) => d.scripts).flat(1)).toEqual([
{ src: 'script.js' },
undefined,
{ src: 'script3.js' },
])

const { container } = render(<RouterProvider router={router} />)

expect(container.innerHTML).toEqual(
`<script src="script.js"></script><script src="script3.js"></script>`,
)
})
})

describe('ssr meta', () => {
Expand Down