From cbfc83c21618618c02ad357ea1b88bf0f1fe1153 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 1 Nov 2026 00:36:11 +0800 Subject: [PATCH 1/6] Migrate MyApp.Client to the Vite+ toolchain Next.js keeps building the app (next dev/build/start unchanged). Vite+ (vite-plus 1.4.0) takes over the rest of the tooling: Vitest 5, Oxlint (type-aware, via tsgolint) and Oxfmt, configured in one vite.config.ts. npm scripts stay the entry points, so no global `vp` install is required. - vite-plus pinned with npm overrides for vite -> @voidzero-dev/vite-plus-core - vitest.config.ts merged into vite.config.ts; tests import from vite-plus/test - new check/lint/fmt scripts; typecheck now runs `vp check --no-fmt --no-lint` - lint: eslint:recommended + typescript-eslint recommended equivalents, plus react hooks and nextjs rules (the template had no ESLint before) - fix lint findings: unused imports/vars, `extends {}`, ValidateAuth hook naming/order in lib/auth.tsx; suppress useMetadata and appAuth() false positives without changing the shared appAuth() API - remove postinstall.mjs (empty DBs are migrated on app startup), autoprefixer - drop tsconfig baseUrl (removed in TypeScript Go) - add seed tests (gateway, HelloApi component) - upgrade deps, incl. TypeScript 7, @vitejs/plugin-react 6, Next.js 16.4 Co-Authored-By: Claude Opus 5.5 --- MyApp.Client/.gitignore | 1 + MyApp.Client/AGENTS.md | 9 + MyApp.Client/app/bookings-auto/page.tsx | 2 +- MyApp.Client/app/signin/page.tsx | 1 - MyApp.Client/components/intro.test.tsx | 22 + MyApp.Client/components/intro.tsx | 2 +- MyApp.Client/components/layout.tsx | 2 +- MyApp.Client/components/nav.tsx | 10 +- MyApp.Client/lib/auth.tsx | 23 +- MyApp.Client/lib/gateway.test.ts | 26 + MyApp.Client/lib/gateway.ts | 3 +- MyApp.Client/lib/utils.test.ts | 4 +- MyApp.Client/next-env.d.ts | 1 + MyApp.Client/package-lock.json | 5423 +++++++++++++---------- MyApp.Client/package.json | 58 +- MyApp.Client/postinstall.mjs | 50 - MyApp.Client/tsconfig.json | 1 - MyApp.Client/vite.config.ts | 71 + MyApp.Client/vitest.config.ts | 18 - MyApp.Client/vitest.setup.ts | 2 +- 20 files changed, 3313 insertions(+), 2416 deletions(-) create mode 100644 MyApp.Client/AGENTS.md create mode 100644 MyApp.Client/components/intro.test.tsx create mode 100644 MyApp.Client/lib/gateway.test.ts delete mode 100644 MyApp.Client/postinstall.mjs create mode 100644 MyApp.Client/vite.config.ts delete mode 100644 MyApp.Client/vitest.config.ts diff --git a/MyApp.Client/.gitignore b/MyApp.Client/.gitignore index 046716d..02ec697 100644 --- a/MyApp.Client/.gitignore +++ b/MyApp.Client/.gitignore @@ -33,3 +33,4 @@ yarn-error.log* # vercel .vercel +.vitest/ diff --git a/MyApp.Client/AGENTS.md b/MyApp.Client/AGENTS.md new file mode 100644 index 0000000..af3b7c8 --- /dev/null +++ b/MyApp.Client/AGENTS.md @@ -0,0 +1,9 @@ + + +## This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices. + +This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean. + + diff --git a/MyApp.Client/app/bookings-auto/page.tsx b/MyApp.Client/app/bookings-auto/page.tsx index d2df118..e6ca128 100644 --- a/MyApp.Client/app/bookings-auto/page.tsx +++ b/MyApp.Client/app/bookings-auto/page.tsx @@ -7,7 +7,7 @@ import { ValidateAuth } from "@/lib/auth" function BookingsCustom() { const { currency } = useFormatters() - const [coupon, setCoupon] = useState(null) + const [, setCoupon] = useState(null) return ( diff --git a/MyApp.Client/app/signin/page.tsx b/MyApp.Client/app/signin/page.tsx index add938a..5b6f3f5 100644 --- a/MyApp.Client/app/signin/page.tsx +++ b/MyApp.Client/app/signin/page.tsx @@ -1,6 +1,5 @@ 'use client' -import {serializeToObject} from "@servicestack/client" import {SyntheticEvent, Suspense, useEffect, useState} from "react" import {useRouter, useSearchParams} from "next/navigation" import Link from "next/link" diff --git a/MyApp.Client/components/intro.test.tsx b/MyApp.Client/components/intro.test.tsx new file mode 100644 index 0000000..cd8b5c2 --- /dev/null +++ b/MyApp.Client/components/intro.test.tsx @@ -0,0 +1,22 @@ +import { describe, expect, it, vi } from 'vite-plus/test' +import { render, screen } from '@testing-library/react' +import { ClientContext } from '@servicestack/react' +import { ApiResult, JsonServiceClient } from '@servicestack/client' +import { HelloResponse } from '@/lib/dtos' +import { HelloApi } from './intro' + +describe('HelloApi', () => { + it('renders the API response', async () => { + const client = new JsonServiceClient() + const api = vi.spyOn(client, 'api').mockResolvedValue(new ApiResult({ response: new HelloResponse({ result: 'Hello, Vite+!' }) })) + + render( + + + , + ) + + expect(await screen.findByText('Hello, Vite+!')).toBeTruthy() + expect(api).toHaveBeenCalledOnce() + }) +}) diff --git a/MyApp.Client/components/intro.tsx b/MyApp.Client/components/intro.tsx index 019af66..acebd82 100644 --- a/MyApp.Client/components/intro.tsx +++ b/MyApp.Client/components/intro.tsx @@ -7,7 +7,7 @@ import { GettingStarted, AutoUis } from "react-net-templates" import { CMS_NAME } from "@/lib/constants" import { Hello, HelloResponse } from "@/lib/dtos" -const HelloApi = ({ name }:any) => { +export const HelloApi = ({ name }:any) => { const client = useClient() const [api, setApi] = useState>(new ApiResult()) diff --git a/MyApp.Client/components/layout.tsx b/MyApp.Client/components/layout.tsx index 95b355e..368b5ba 100644 --- a/MyApp.Client/components/layout.tsx +++ b/MyApp.Client/components/layout.tsx @@ -7,7 +7,7 @@ type Props = { children: React.ReactNode } -const Layout = ({ preview, children }: Props) => { +const Layout = ({ children }: Props) => { return ( <> diff --git a/MyApp.Client/components/nav.tsx b/MyApp.Client/components/nav.tsx index 112c5e8..718f1a6 100644 --- a/MyApp.Client/components/nav.tsx +++ b/MyApp.Client/components/nav.tsx @@ -2,7 +2,7 @@ import Link from "next/link" import { usePathname } from "next/navigation" -import { useAuth, PrimaryButton, SecondaryButton, DarkModeToggle } from "@servicestack/react" +import { PrimaryButton, SecondaryButton, DarkModeToggle } from "@servicestack/react" import { appAuth } from "@/lib/auth" type NavItem = { @@ -21,11 +21,7 @@ export default function Nav() { { href: '/bookings-auto', name: 'Bookings'}, ] - const { user, hasRole, signOut } = appAuth() - const navClass = (path:string) => [ - "p-4 flex items-center justify-start mw-full hover:text-sky-500 dark:hover:text-sky-400", - pathname === path || pathname.startsWith(path + '/') ? "text-link-dark dark:text-link-dark" : "", - ].join(" ") + const { user, signOut } = appAuth() return (
@@ -53,6 +49,8 @@ export default function Nav() {
  • + {/* Razor Page, not a Next.js page */} + {/* oxlint-disable-next-line nextjs/no-html-link-for-pages */}