refactor(arch): 移除 experimental_defaults,提炼 useInvalidateTodos,闭环若干悬挂配置

- orpc.ts: 改为纯 createTanstackQueryUtils,不再依赖 experimental_ API
- 抽出 src/client/queries/todo.ts 的 useInvalidateTodos,避免 query key 散落页面
- shutdown: setTimeout 内 db.$client.end() 失败也走 process.exit
- 删除 db/index.ts 未被使用的 DB 类型导出
- 删除 env.ts 未被消费的 VITE_APP_TITLE,根 title 改为 package.json name
- 清理 routes/index.tsx 的 JSX 区段注释、compose.yaml 注释掉的端口块、robots.txt URL 注释
This commit is contained in:
2026-04-25 13:31:16 +08:00
parent 2c5bceb826
commit 830c908712
9 changed files with 20 additions and 46 deletions
-2
View File
@@ -23,8 +23,6 @@ services:
db: db:
image: postgres:18-alpine image: postgres:18-alpine
# ports:
# - "5432:5432"
volumes: volumes:
- postgres_data:/var/lib/postgresql - postgres_data:/var/lib/postgresql
environment: environment:
-1
View File
@@ -1,3 +1,2 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: * User-agent: *
Disallow: Disallow:
+1 -27
View File
@@ -24,30 +24,4 @@ const getORPCClient = createIsomorphicFn()
const client: RouterClient = getORPCClient() const client: RouterClient = getORPCClient()
export const orpc = createTanstackQueryUtils(client, { export const orpc = createTanstackQueryUtils(client)
experimental_defaults: {
todo: {
create: {
mutationOptions: {
onSuccess: (_, __, ___, ctx) => {
ctx.client.invalidateQueries({ queryKey: orpc.todo.list.key() })
},
},
},
update: {
mutationOptions: {
onSuccess: (_, __, ___, ctx) => {
ctx.client.invalidateQueries({ queryKey: orpc.todo.list.key() })
},
},
},
remove: {
mutationOptions: {
onSuccess: (_, __, ___, ctx) => {
ctx.client.invalidateQueries({ queryKey: orpc.todo.list.key() })
},
},
},
},
},
})
+7
View File
@@ -0,0 +1,7 @@
import { useQueryClient } from '@tanstack/react-query'
import { orpc } from '@/client/orpc'
export const useInvalidateTodos = () => {
const queryClient = useQueryClient()
return () => queryClient.invalidateQueries({ queryKey: orpc.todo.list.key() })
}
+1 -3
View File
@@ -6,9 +6,7 @@ export const env = createEnv({
DATABASE_URL: z.url(), DATABASE_URL: z.url(),
}, },
clientPrefix: 'VITE_', clientPrefix: 'VITE_',
client: { client: {},
VITE_APP_TITLE: z.string().min(1).optional(),
},
runtimeEnv: process.env, runtimeEnv: process.env,
emptyStringAsUndefined: true, emptyStringAsUndefined: true,
}) })
+2 -1
View File
@@ -4,6 +4,7 @@ import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools'
import { createRootRouteWithContext, HeadContent, Scripts } from '@tanstack/react-router' import { createRootRouteWithContext, HeadContent, Scripts } from '@tanstack/react-router'
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools' import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
import type { ReactNode } from 'react' import type { ReactNode } from 'react'
import { name } from '@/../package.json'
import { ErrorComponent } from '@/components/Error' import { ErrorComponent } from '@/components/Error'
import { NotFoundComponent } from '@/components/NotFound' import { NotFoundComponent } from '@/components/NotFound'
import appCss from '@/styles.css?url' import appCss from '@/styles.css?url'
@@ -23,7 +24,7 @@ export const Route = createRootRouteWithContext<RouterContext>()({
content: 'width=device-width, initial-scale=1', content: 'width=device-width, initial-scale=1',
}, },
{ {
title: 'Furtherverse', title: name,
}, },
], ],
links: [ links: [
+6 -6
View File
@@ -1,6 +1,7 @@
import { useMutation, useSuspenseQuery } from '@tanstack/react-query' import { useMutation, useSuspenseQuery } from '@tanstack/react-query'
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from '@tanstack/react-router'
import { orpc } from '@/client/orpc' import { orpc } from '@/client/orpc'
import { useInvalidateTodos } from '@/client/queries/todo'
import { TodoForm } from '@/components/TodoForm' import { TodoForm } from '@/components/TodoForm'
import { TodoItem } from '@/components/TodoItem' import { TodoItem } from '@/components/TodoItem'
@@ -13,9 +14,11 @@ export const Route = createFileRoute('/')({
function Todos() { function Todos() {
const listQuery = useSuspenseQuery(orpc.todo.list.queryOptions()) const listQuery = useSuspenseQuery(orpc.todo.list.queryOptions())
const createMutation = useMutation(orpc.todo.create.mutationOptions()) const invalidateTodos = useInvalidateTodos()
const updateMutation = useMutation(orpc.todo.update.mutationOptions())
const deleteMutation = useMutation(orpc.todo.remove.mutationOptions()) const createMutation = useMutation(orpc.todo.create.mutationOptions({ onSuccess: invalidateTodos }))
const updateMutation = useMutation(orpc.todo.update.mutationOptions({ onSuccess: invalidateTodos }))
const deleteMutation = useMutation(orpc.todo.remove.mutationOptions({ onSuccess: invalidateTodos }))
const todos = listQuery.data const todos = listQuery.data
const completedCount = todos.filter((todo) => todo.completed).length const completedCount = todos.filter((todo) => todo.completed).length
@@ -25,7 +28,6 @@ function Todos() {
return ( return (
<div className="min-h-screen bg-slate-50 py-12 px-4 sm:px-6 font-sans"> <div className="min-h-screen bg-slate-50 py-12 px-4 sm:px-6 font-sans">
<div className="max-w-2xl mx-auto space-y-8"> <div className="max-w-2xl mx-auto space-y-8">
{/* Header */}
<div className="flex items-end justify-between"> <div className="flex items-end justify-between">
<div> <div>
<h1 className="text-3xl font-bold text-slate-900 tracking-tight"></h1> <h1 className="text-3xl font-bold text-slate-900 tracking-tight"></h1>
@@ -42,7 +44,6 @@ function Todos() {
<TodoForm onSubmit={(title) => createMutation.mutate({ title })} isPending={createMutation.isPending} /> <TodoForm onSubmit={(title) => createMutation.mutate({ title })} isPending={createMutation.isPending} />
{/* Progress Bar */}
{totalCount > 0 && ( {totalCount > 0 && (
<div className="h-1.5 w-full bg-slate-200 rounded-full overflow-hidden"> <div className="h-1.5 w-full bg-slate-200 rounded-full overflow-hidden">
<div <div
@@ -52,7 +53,6 @@ function Todos() {
</div> </div>
)} )}
{/* Todo List */}
<div className="space-y-3"> <div className="space-y-3">
{todos.length === 0 ? ( {todos.length === 0 ? (
<div className="py-20 text-center"> <div className="py-20 text-center">
-2
View File
@@ -6,5 +6,3 @@ export const db = drizzle({
connection: env.DATABASE_URL, connection: env.DATABASE_URL,
schema, schema,
}) })
export type DB = typeof db
+3 -4
View File
@@ -5,15 +5,14 @@ export default () => {
let exiting = false let exiting = false
const shutdown = async () => { const shutdown = () => {
if (exiting) { if (exiting) {
process.exit(0) process.exit(0)
} }
exiting = true exiting = true
setTimeout(async () => { setTimeout(() => {
await db.$client.end() db.$client.end().finally(() => process.exit(0))
process.exit(0)
}, 500) }, 500)
} }