注意
如果您选择快速启动一个示例项目或克隆项目,可以跳过本指南,直接进入 学习基础知识 指南。
您想从零开始构建一个 TanStack Start 项目吗?
本指南将帮助您构建一个非常基础的 TanStack Start Web 应用程序。我们将一起使用 TanStack Start 来
让我们创建一个新的项目目录并进行初始化。
mkdir myApp
cd myApp
npm init -y
mkdir myApp
cd myApp
npm init -y
注意
> 在所有这些示例中,我们都使用 npm,但您也可以使用您选择的包管理器。
我们强烈建议使用 TypeScript 和 TanStack Start。创建一个 tsconfig.json 文件,至少包含以下设置
{
"compilerOptions": {
"jsx": "preserve",
"jsxImportSource": "solid-js",
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ES2022",
"skipLibCheck": true,
"strictNullChecks": true
}
}
{
"compilerOptions": {
"jsx": "preserve",
"jsxImportSource": "solid-js",
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ES2022",
"skipLibCheck": true,
"strictNullChecks": true
}
}
注意
> 启用 verbatimModuleSyntax 可能会导致服务器包泄漏到客户端包中。建议保持此选项禁用。
TanStack Start 由 Vite 和 TanStack Router 提供支持,并将它们作为依赖项。
要安装它们,请运行
npm i @tanstack/solid-start @tanstack/solid-router vite
npm i @tanstack/solid-start @tanstack/solid-router vite
您还需要 Solid
npm i solid-js
npm i solid-js
以及一些 TypeScript
npm i -D typescript vite-tsconfig-paths
npm i -D typescript vite-tsconfig-paths
然后我们将更新我们的 package.json 以使用 Vite 的 CLI 并设置 "type": "module"
{
// ...
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build"
}
}
{
// ...
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build"
}
}
然后在 vite.config.ts 中配置 TanStack Start 的 Vite 插件
注意
TanStack Start 将停止自动配置 React/Solid Vite 插件。您将拥有完全的控制权——选择 vite-plugin-solid。设置 customViteSolidPlugin: true 以立即选择此功能!
// vite.config.ts
import { defineConfig } from 'vite'
import tsConfigPaths from 'vite-tsconfig-paths'
import { tanstackStart } from '@tanstack/solid-start/plugin/vite'
import viteSolid from 'vite-plugin-solid'
export default defineConfig({
server: {
port: 3000,
},
plugins: [
tsConfigPaths(),
tanstackStart({ customViteSolidPlugin: true }),
viteSolid({ ssr: true }),
],
})
// vite.config.ts
import { defineConfig } from 'vite'
import tsConfigPaths from 'vite-tsconfig-paths'
import { tanstackStart } from '@tanstack/solid-start/plugin/vite'
import viteSolid from 'vite-plugin-solid'
export default defineConfig({
server: {
port: 3000,
},
plugins: [
tsConfigPaths(),
tanstackStart({ customViteSolidPlugin: true }),
viteSolid({ ssr: true }),
],
})
TanStack Start 的使用需要 2 个必需文件
配置完成后,我们的文件树将如下所示
.
├── src/
│ ├── routes/
│ │ └── `__root.tsx`
│ ├── `router.tsx`
│ ├── `routeTree.gen.ts`
├── `.gitignore`
├── `vite.config.ts`
├── `package.json`
└── `tsconfig.json`
.
├── src/
│ ├── routes/
│ │ └── `__root.tsx`
│ ├── `router.tsx`
│ ├── `routeTree.gen.ts`
├── `.gitignore`
├── `vite.config.ts`
├── `package.json`
└── `tsconfig.json`
这是决定 Start 中 TanStack Router 行为的文件。在这里,您可以配置从默认的 预加载功能 到 缓存陈旧度 的所有内容。
注意
此时您还没有 routeTree.gen.ts 文件。当您第一次运行 TanStack Start 时,该文件将被生成。
// src/router.tsx
import { createRouter as createTanStackRouter } from '@tanstack/solid-router'
import { routeTree } from './routeTree.gen'
export function createRouter() {
const router = createTanStackRouter({
routeTree,
scrollRestoration: true,
})
return router
}
declare module '@tanstack/solid-router' {
interface Register {
router: ReturnType<typeof createRouter>
}
}
// src/router.tsx
import { createRouter as createTanStackRouter } from '@tanstack/solid-router'
import { routeTree } from './routeTree.gen'
export function createRouter() {
const router = createTanStackRouter({
routeTree,
scrollRestoration: true,
})
return router
}
declare module '@tanstack/solid-router' {
interface Register {
router: ReturnType<typeof createRouter>
}
}
注意
TanStack Start 提供了默认的服务器和客户端入口点来处理请求和客户端入口 + 水合。您可以通过在项目根目录添加 server.ts 和/或 client.tsx 文件来自定义这些入口点,但目前我们将使用默认设置。
最后,我们需要创建应用程序的根文件。这是所有其他路由的入口点。此文件中的代码将包装应用程序中的所有其他路由。
// src/routes/__root.tsx
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from '@tanstack/solid-router'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
title: 'TanStack Start Starter',
},
],
}),
component: RootComponent,
})
function RootComponent() {
return <Outlet />
}
// src/routes/__root.tsx
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from '@tanstack/solid-router'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
title: 'TanStack Start Starter',
},
],
}),
component: RootComponent,
})
function RootComponent() {
return <Outlet />
}
现在我们已经设置了基础模板,我们可以编写第一个路由了。这可以通过在 app/routes 目录中创建一个新文件来完成。
// src/routes/index.tsx
import * as fs from 'node:fs'
import { createFileRoute, useRouter } from '@tanstack/solid-router'
import { createServerFn } from '@tanstack/solid-start'
const filePath = 'count.txt'
async function readCount() {
return parseInt(
await fs.promises.readFile(filePath, 'utf-8').catch(() => '0'),
)
}
const getCount = createServerFn({
method: 'GET',
}).handler(() => {
return readCount()
})
const updateCount = createServerFn({ method: 'POST' })
.validator((d: number) => d)
.handler(async ({ data }) => {
const count = await readCount()
await fs.promises.writeFile(filePath, `${count + data}`)
})
export const Route = createFileRoute('/')({
component: Home,
loader: async () => await getCount(),
})
function Home() {
const router = useRouter()
const state = Route.useLoaderData()
return (
<button
type="button"
onClick={() => {
updateCount({ data: 1 }).then(() => {
router.invalidate()
})
}}
>
Add 1 to {state()}?
</button>
)
}
// src/routes/index.tsx
import * as fs from 'node:fs'
import { createFileRoute, useRouter } from '@tanstack/solid-router'
import { createServerFn } from '@tanstack/solid-start'
const filePath = 'count.txt'
async function readCount() {
return parseInt(
await fs.promises.readFile(filePath, 'utf-8').catch(() => '0'),
)
}
const getCount = createServerFn({
method: 'GET',
}).handler(() => {
return readCount()
})
const updateCount = createServerFn({ method: 'POST' })
.validator((d: number) => d)
.handler(async ({ data }) => {
const count = await readCount()
await fs.promises.writeFile(filePath, `${count + data}`)
})
export const Route = createFileRoute('/')({
component: Home,
loader: async () => await getCount(),
})
function Home() {
const router = useRouter()
const state = Route.useLoaderData()
return (
<button
type="button"
onClick={() => {
updateCount({ data: 1 }).then(() => {
router.invalidate()
})
}}
>
Add 1 to {state()}?
</button>
)
}
就是这样!🤯 您现在已经设置了一个 TanStack Start 项目并编写了您的第一个路由。🎉
您现在可以运行 npm run dev 来启动您的服务器,然后导航到 https://:3000 来查看您的路由运行情况。
您想部署您的应用程序吗?请查看 托管指南。
您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。