Skip to content

Commit d5ce04c

Browse files
authored
docs(solid-router): esbuild guide/example (#5831)
1 parent 80a9923 commit d5ce04c

File tree

15 files changed

+473
-0
lines changed

15 files changed

+473
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
---
2+
title: Installation with Esbuild
3+
---
4+
5+
[//]: # 'BundlerConfiguration'
6+
7+
To use file-based routing with **Esbuild**, you'll need to install the `@tanstack/router-plugin` package.
8+
9+
```sh
10+
npm install -D @tanstack/router-plugin
11+
```
12+
13+
Once installed, you'll need to add the plugin to your configuration.
14+
15+
```tsx
16+
// build.js
17+
import * as esbuild from 'esbuild'
18+
import { solidPlugin } from 'esbuild-plugin-solid'
19+
import { tanstackRouter } from '@tanstack/router-plugin/esbuild'
20+
21+
const isDev = process.argv.includes('--dev')
22+
23+
const ctx = await esbuild.context({
24+
entryPoints: ['src/main.tsx'],
25+
outfile: 'dist/main.js',
26+
minify: !isDev,
27+
bundle: true,
28+
format: 'esm',
29+
target: ['esnext'],
30+
sourcemap: true,
31+
plugins: [
32+
solidPlugin(),
33+
tanstackRouter({ target: 'solid', autoCodeSplitting: true }),
34+
],
35+
})
36+
37+
if (isDev) {
38+
await ctx.watch()
39+
const { host, port } = await ctx.serve({ servedir: '.', port: 3005 })
40+
console.log(`Server running at http://${host || 'localhost'}:${port}`)
41+
} else {
42+
await ctx.rebuild()
43+
await ctx.dispose()
44+
}
45+
```
46+
47+
Or, you can clone our [Quickstart Esbuild example](https://github.com/TanStack/router/tree/main/examples/solid/quickstart-esbuild-file-based) and get started.
48+
49+
Now that you've added the plugin to your Esbuild configuration, you're all set to start using file-based routing with TanStack Router.
50+
51+
[//]: # 'BundlerConfiguration'
52+
53+
## Ignoring the generated route tree file
54+
55+
If your project is configured to use a linter and/or formatter, you may want to ignore the generated route tree file. This file is managed by TanStack Router and therefore shouldn't be changed by your linter or formatter.
56+
57+
Here are some resources to help you ignore the generated route tree file:
58+
59+
- Prettier - [https://prettier.io/docs/en/ignore.html#ignoring-files-prettierignore](https://prettier.io/docs/en/ignore.html#ignoring-files-prettierignore)
60+
- ESLint - [https://eslint.org/docs/latest/use/configure/ignore#ignoring-files](https://eslint.org/docs/latest/use/configure/ignore#ignoring-files)
61+
- Biome - [https://biomejs.dev/reference/configuration/#filesignore](https://biomejs.dev/reference/configuration/#filesignore)
62+
63+
> [!WARNING]
64+
> If you are using VSCode, you may experience the route tree file unexpectedly open (with errors) after renaming a route.
65+
66+
You can prevent that from the VSCode settings by marking the file as readonly. Our recommendation is to also exclude it from search results and file watcher with the following settings:
67+
68+
```json
69+
{
70+
"files.readonlyInclude": {
71+
"**/routeTree.gen.ts": true
72+
},
73+
"files.watcherExclude": {
74+
"**/routeTree.gen.ts": true
75+
},
76+
"search.exclude": {
77+
"**/routeTree.gen.ts": true
78+
}
79+
}
80+
```
81+
82+
You can use those settings either at a user level or only for a single workspace by creating the file `.vscode/settings.json` at the root of your project.
83+
84+
## Configuration
85+
86+
When using the TanStack Router Plugin with Esbuild for File-based routing, it comes with some sane defaults that should work for most projects:
87+
88+
```json
89+
{
90+
"routesDirectory": "./src/routes",
91+
"generatedRouteTree": "./src/routeTree.gen.ts",
92+
"routeFileIgnorePrefix": "-",
93+
"quoteStyle": "single"
94+
}
95+
```
96+
97+
If these defaults work for your project, you don't need to configure anything at all! However, if you need to customize the configuration, you can do so by editing the configuration object passed into the `tanstackRouter` function.
98+
99+
You can find all the available configuration options in the [File-based Routing API Reference](../../../../api/file-based-routing.md).
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
.DS_Store
3+
dist
4+
dist-ssr
5+
*.local
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"files.watcherExclude": {
3+
"**/routeTree.gen.ts": true
4+
},
5+
"search.exclude": {
6+
"**/routeTree.gen.ts": true
7+
},
8+
"files.readonlyInclude": {
9+
"**/routeTree.gen.ts": true
10+
}
11+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Example
2+
3+
To run this example:
4+
5+
- `npm install` or `yarn`
6+
- `npm start` or `yarn start`
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env node
2+
import * as esbuild from 'esbuild'
3+
import { solidPlugin } from 'esbuild-plugin-solid'
4+
import { tanstackRouter } from '@tanstack/router-plugin/esbuild'
5+
6+
const isDev = process.argv.includes('--dev')
7+
8+
const ctx = await esbuild.context({
9+
entryPoints: ['src/main.tsx'],
10+
outfile: 'dist/main.js',
11+
minify: !isDev,
12+
bundle: true,
13+
format: 'esm',
14+
target: ['esnext'],
15+
sourcemap: true,
16+
plugins: [
17+
solidPlugin(),
18+
tanstackRouter({ target: 'solid', autoCodeSplitting: true }),
19+
],
20+
})
21+
22+
if (isDev) {
23+
await ctx.watch()
24+
const { host, port } = await ctx.serve({ servedir: '.', port: 3005 })
25+
console.log(`Server running at http://${host || 'localhost'}:${port}`)
26+
} else {
27+
await ctx.rebuild()
28+
await ctx.dispose()
29+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Vite App</title>
7+
<script src="https://unpkg.com/@tailwindcss/browser@4"></script>
8+
<style type="text/tailwindcss">
9+
html {
10+
color-scheme: light dark;
11+
}
12+
* {
13+
@apply border-gray-200 dark:border-gray-800;
14+
}
15+
body {
16+
@apply bg-gray-50 text-gray-950 dark:bg-gray-900 dark:text-gray-200;
17+
}
18+
</style>
19+
</head>
20+
<body>
21+
<div id="app"></div>
22+
<script type="module" src="/dist/main.js"></script>
23+
</body>
24+
</html>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "tanstack-router-solid-example-quickstart-esbuild-file-based",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"dev": "node build.js --dev",
7+
"build": "node build.js",
8+
"serve": "node build.js --dev",
9+
"start": "dev"
10+
},
11+
"dependencies": {
12+
"@tanstack/solid-router": "^1.135.2",
13+
"@tanstack/solid-router-devtools": "^1.135.2",
14+
"@tanstack/router-plugin": "^1.135.2",
15+
"solid-js": "^1.9.10",
16+
"redaxios": "^0.5.1",
17+
"zod": "^3.24.2"
18+
},
19+
"devDependencies": {
20+
"esbuild": "^0.25.0",
21+
"esbuild-plugin-solid": "^0.6.0"
22+
}
23+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { render } from 'solid-js/web'
2+
import { RouterProvider, createRouter } from '@tanstack/solid-router'
3+
import { routeTree } from './routeTree.gen'
4+
5+
// Set up a Router instance
6+
const router = createRouter({
7+
routeTree,
8+
defaultPreload: 'intent',
9+
scrollRestoration: true,
10+
})
11+
12+
// Register things for typesafety
13+
declare module '@tanstack/solid-router' {
14+
interface Register {
15+
router: typeof router
16+
}
17+
}
18+
19+
const rootElement = document.getElementById('app')!
20+
21+
if (!rootElement.innerHTML) {
22+
render(() => <RouterProvider router={router} />, rootElement)
23+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import axios from 'redaxios'
2+
3+
export type PostType = {
4+
id: string
5+
title: string
6+
body: string
7+
}
8+
9+
export class PostNotFoundError extends Error {}
10+
11+
export const fetchPost = async (postId: string) => {
12+
console.info(`Fetching post with id ${postId}...`)
13+
await new Promise((r) => setTimeout(r, 500))
14+
const post = await axios
15+
.get<PostType>(`https://jsonplaceholder.typicode.com/posts/${postId}`)
16+
.then((r) => r.data)
17+
.catch((err) => {
18+
if (err.status === 404) {
19+
throw new PostNotFoundError(`Post with id "${postId}" not found!`)
20+
}
21+
throw err
22+
})
23+
24+
return post
25+
}
26+
27+
export const fetchPosts = async () => {
28+
console.info('Fetching posts...')
29+
await new Promise((r) => setTimeout(r, 500))
30+
return axios
31+
.get<Array<PostType>>('https://jsonplaceholder.typicode.com/posts')
32+
.then((r) => r.data.slice(0, 10))
33+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/* prettier-ignore-start */
2+
3+
/* eslint-disable */
4+
5+
// @ts-nocheck
6+
7+
// noinspection JSUnusedGlobalSymbols
8+
9+
// This file is auto-generated by TanStack Router
10+
11+
// Import Routes
12+
13+
import { Route as rootRoute } from './routes/__root'
14+
import { Route as AboutImport } from './routes/about'
15+
import { Route as IndexImport } from './routes/index'
16+
17+
// Create/Update Routes
18+
19+
const AboutRoute = AboutImport.update({
20+
path: '/about',
21+
getParentRoute: () => rootRoute,
22+
} as any)
23+
24+
const IndexRoute = IndexImport.update({
25+
path: '/',
26+
getParentRoute: () => rootRoute,
27+
} as any)
28+
29+
// Populate the FileRoutesByPath interface
30+
31+
declare module '@tanstack/solid-router' {
32+
interface FileRoutesByPath {
33+
'/': {
34+
id: '/'
35+
path: '/'
36+
fullPath: '/'
37+
preLoaderRoute: typeof IndexImport
38+
parentRoute: typeof rootRoute
39+
}
40+
'/about': {
41+
id: '/about'
42+
path: '/about'
43+
fullPath: '/about'
44+
preLoaderRoute: typeof AboutImport
45+
parentRoute: typeof rootRoute
46+
}
47+
}
48+
}
49+
50+
// Create and export the route tree
51+
52+
export interface FileRoutesByFullPath {
53+
'/': typeof IndexRoute
54+
'/about': typeof AboutRoute
55+
}
56+
57+
export interface FileRoutesByTo {
58+
'/': typeof IndexRoute
59+
'/about': typeof AboutRoute
60+
}
61+
62+
export interface FileRoutesById {
63+
__root__: typeof rootRoute
64+
'/': typeof IndexRoute
65+
'/about': typeof AboutRoute
66+
}
67+
68+
export interface FileRouteTypes {
69+
fileRoutesByFullPath: FileRoutesByFullPath
70+
fullPaths: '/' | '/about'
71+
fileRoutesByTo: FileRoutesByTo
72+
to: '/' | '/about'
73+
id: '__root__' | '/' | '/about'
74+
fileRoutesById: FileRoutesById
75+
}
76+
77+
export interface RootRouteChildren {
78+
IndexRoute: typeof IndexRoute
79+
AboutRoute: typeof AboutRoute
80+
}
81+
82+
const rootRouteChildren: RootRouteChildren = {
83+
IndexRoute: IndexRoute,
84+
AboutRoute: AboutRoute,
85+
}
86+
87+
export const routeTree = rootRoute
88+
._addFileChildren(rootRouteChildren)
89+
._addFileTypes<FileRouteTypes>()
90+
91+
/* prettier-ignore-end */
92+
93+
/* ROUTE_MANIFEST_START
94+
{
95+
"routes": {
96+
"__root__": {
97+
"filePath": "__root.tsx",
98+
"children": [
99+
"/",
100+
"/about"
101+
]
102+
},
103+
"/": {
104+
"filePath": "index.tsx"
105+
},
106+
"/about": {
107+
"filePath": "about.tsx"
108+
}
109+
}
110+
}
111+
ROUTE_MANIFEST_END */

0 commit comments

Comments
 (0)