TypeScript + Next.js 全栈开发模板:从零构建现代化Web应用
1. 项目概述:一个现代全栈开发的“瑞士军刀”
如果你正在寻找一个能让你快速上手、开箱即用,并且架构足够现代、能支撑起一个严肃商业项目前端的 TypeScript + Next.js 项目模板,那么jpedroschmitz/typescript-nextjs-starter这个仓库很可能就是你一直在找的答案。这不是一个简单的“Hello World”示例,而是一个由资深开发者精心配置的、集成了当前前端生态中诸多最佳实践的生产力启动器。
我最初接触这个项目,是因为厌倦了每次启动新项目时都要重复进行的那一套繁琐配置:安装 TypeScript、配置 ESLint 和 Prettier、设置 Tailwind CSS、集成测试框架、搞掂代码提交规范……这些工作虽然必要,但极其耗时且容易出错。而这个 Starter 模板,就像一位经验丰富的助手,帮你把这些基础且关键的“脏活累活”一次性打包处理好,让你能直接聚焦于业务逻辑的开发。它不仅仅提供了技术栈,更提供了一套经过验证的、可维护的代码组织范式和开发工作流。无论是个人 side project,还是团队协作的商业应用,它都能提供一个坚实、可靠的起点,避免你在项目初期就陷入配置地狱。
2. 技术栈深度解析:为什么是这些选择?
这个 Starter 的核心技术选型体现了对现代 Web 开发趋势的深刻理解。每一层选择都不是随意的,背后都有其针对特定问题的解决方案和权衡考量。
2.1 Next.js:全栈框架的基石
Next.js 是这个模板的绝对核心。它远不止是一个 React 框架,而是一个功能齐全的全栈应用开发平台。选择 Next.js 而非纯粹的 Create React App (CRA) 或 Vite,主要基于以下几个关键考量:
1. 服务端渲染与静态生成:Next.js 最强大的特性在于其预渲染策略。对于需要 SEO 的页面(如营销页、博客、产品列表),你可以使用getStaticProps进行静态生成(SSG),在构建时生成 HTML,获得极致的加载速度和缓存友好性。对于高度动态、用户个性化的页面(如用户仪表盘),则可以使用getServerSideProps进行服务端渲染(SSR),每次请求时生成 HTML,确保数据新鲜度。这种灵活性让你可以为不同的路由选择最优的渲染策略,这在 CRA 等纯客户端渲染方案中是难以实现的。
2. 基于文件系统的路由:在pages目录(或app目录,如果使用 App Router)下创建文件,即可自动生成对应的路由。这极大地简化了路由配置,让项目结构一目了然,降低了心智负担。对于中小型项目,这种约定大于配置的方式能显著提升开发效率。
3. 内置的优化与基础设施:Next.js 开箱即提供了图片优化(next/image)、字体优化(next/font)、脚本优化(next/script)等性能优化组件。它还内置了 API Routes 功能,允许你在同一个项目中编写后端 API,无需单独配置 Node.js 服务器,这对于全栈开发或构建 BFF(Backend for Frontend)层非常方便。
注意:该 Starter 模板默认使用了 Pages Router。虽然 Next.js 13+ 推出了功能更强大的 App Router,但 Pages Router 更加稳定、成熟,生态兼容性更好,对于大多数项目尤其是起步阶段,是一个更稳妥的选择。你可以根据项目发展情况,在后期再决定是否迁移到 App Router。
2.2 TypeScript:类型安全的守护神
在今天的 Web 开发中,TypeScript 已从“可选项”变成了“必选项”。这个模板将 TypeScript 置于首位,其价值在于:
- 开发时捕获错误:在代码运行前,TypeScript 编译器就能发现潜在的类型错误、拼写错误和接口不匹配问题,将大量运行时 Bug 扼杀在摇篮里。
- 增强代码可读性与可维护性:类型定义本身就是最好的文档。当你查看一个函数或组件时,其输入输出类型一目了然,极大降低了新成员熟悉代码的成本,也方便了未来的重构。
- 卓越的编辑器支持:配合 VS Code 等编辑器,你可以获得精准的自动补全、智能提示和代码导航,开发体验流畅无比。
模板中已经配置好了严格的tsconfig.json,启用了诸如strict: true等选项,确保你从一开始就遵循高标准的类型安全实践。
2.3 Tailwind CSS:实用至上的样式方案
关于 CSS 的方案争论从未停止,但这个 Starter 坚定地选择了 Tailwind CSS。它的核心理念是“实用优先”(Utility-First),通过一系列细粒度的、单功能的类名来直接构建样式。
为什么是 Tailwind,而不是 CSS Modules 或 Styled-components?
- 开发速度:无需在 JS/TS 文件和 CSS 文件之间来回切换,也无需为组件苦思冥想类名。直接在 HTML/JSX 中组合实用类,所见即所得,效率极高。
- 一致性约束:通过
tailwind.config.js文件定义的设计令牌(颜色、间距、字体大小等),强制整个项目遵循统一的设计系统,避免了样式散落和随意值的问题。 - 极致的包体积:Tailwind 会通过 PurgeCSS(在 JIT 模式下是内置的)自动移除所有未使用的 CSS,最终生成的 CSS 文件通常只有几 KB,性能优势明显。
- 减少命名负担:彻底告别了 BEM 等命名方法论带来的心智负担。
当然,它需要一定的学习曲线来熟悉那些类名,但一旦掌握,其开发效率的提升是巨大的。模板中已经配置好了与 Next.js 的集成,并包含了一个基本的globals.css文件来引入 Tailwind 的基础样式。
2.4 测试工具链:Jest & React Testing Library
一个没有测试的项目是脆弱的。模板集成了 Jest 作为测试运行器,以及 React Testing Library (RTL) 作为 React 组件测试工具。这套组合是目前社区公认的最佳实践。
- Jest:功能全面,开箱即用,速度快,支持快照测试、覆盖率报告等。
- React Testing Library:其哲学是“像用户一样测试你的组件”。它鼓励你通过查询 DOM 元素、触发事件来测试组件行为,而不是测试其内部实现细节(如 state 和 props)。这使得测试更加健壮,不易因重构而失败。
模板中通常会在根目录下包含一个jest.config.js和__tests__目录示例,为你铺好了测试基础设施的道路。虽然初期你可能觉得写测试麻烦,但对于任何计划长期维护或团队协作的项目,投资测试将带来巨大的长期回报。
2.5 代码质量与规范化工具:ESLint & Prettier & Husky
这是保证代码库健康、团队协作顺畅的“基础设施”。
- ESLint:静态代码分析工具,用于发现代码中的潜在问题和不符合规则的模式。模板通常会集成
eslint-config-next等规则集,确保代码符合 Next.js 和 React 的最佳实践。 - Prettier:代码格式化工具。它只关心代码风格(缩进、分号、引号等),并强制统一。它与 ESLint 分工合作(通常通过
eslint-config-prettier避免规则冲突),一个管质量,一个管颜值。 - Husky:Git 钩子工具。模板通常会配置
pre-commit钩子,在提交代码前自动运行 ESLint 检查和 Prettier 格式化(通过lint-staged只对暂存区的文件进行操作)。这确保了所有提交到仓库的代码都是符合规范的,将代码风格争论从团队中彻底消除。
这套组合拳强制建立了代码提交前的质量关卡,是任何严肃项目都应该具备的自动化流程。
3. 项目结构与核心文件详解
克隆仓库后,你会看到一个清晰、标准的目录结构。理解每个文件和文件夹的职责,是高效使用这个模板的关键。
typescript-nextjs-starter/ ├── .github/ # GitHub 工作流配置,如 CI/CD ├── .husky/ # Git 钩子配置,用于提交前检查 ├── __tests__/ # Jest 测试文件存放目录 ├── public/ # 静态资源(图片、字体、favicon等) │ └── favicon.ico ├── src/ │ ├── components/ # 可复用的 React 组件 │ │ ├── ui/ # 基础UI组件(按钮、输入框等) │ │ └── ... # 业务组件 │ ├── pages/ # Next.js 页面,文件即路由 │ │ ├── api/ # API 路由(可选) │ │ ├── _app.tsx # 自定义 App 组件,用于全局布局、状态注入 │ │ ├── _document.tsx # 自定义 Document 组件,用于扩展<html>和<body> │ │ └── index.tsx # 首页路由 (/) │ ├── styles/ # 样式文件 │ │ └── globals.css # 全局样式,导入 Tailwind │ ├── utils/ # 工具函数 │ └── types/ # 全局 TypeScript 类型定义 ├── .eslintrc.json # ESLint 配置 ├── .gitignore ├── .prettierrc # Prettier 配置 ├── jest.config.js # Jest 配置 ├── next.config.js # Next.js 配置 ├── package.json ├── postcss.config.js # PostCSS 配置(Tailwind 所需) ├── README.md # 项目详细说明 ├── tailwind.config.js # Tailwind CSS 配置 └── tsconfig.json # TypeScript 配置关键文件解析:
src/pages/_app.tsx:这是 Next.js 应用的根组件。所有页面在渲染时都会经过它。这里是放置全局布局(如导航栏、页脚)、全局状态提供者(如 React Context, Redux Provider)和全局样式引入的理想位置。模板中通常会有一个基础示例。src/pages/_document.tsx:这个文件用于自定义整个文档的 HTML 结构。你可以在这里添加第三方脚本、修改<head>中的标签(如 meta 标签)、设置字体等。它只在服务端渲染时被调用。next.config.js:Next.js 的核心配置文件。你可以在这里配置重定向、反向代理、环境变量、自定义 Webpack 规则、图片域名白名单等。对于大多数项目,模板提供的默认配置已经足够,但了解这个文件很重要,它是你深度定制 Next.js 行为的主要入口。tailwind.config.js:在这里定义你的设计系统。你可以扩展主题(如添加新的颜色、字体、间距),注册插件,或覆盖默认配置。例如,如果你想使用一套自定义的品牌色,就在这里定义。postcss.config.js:Tailwind CSS 是一个 PostCSS 插件。这个文件通常只需要包含 Tailwind 和 autoprefixer,模板已配置好。
4. 从零开始的完整实操指南
假设你现在要基于这个 Starter 启动一个名为“产品展示平台”的新项目。
4.1 环境准备与项目初始化
首先,确保你的本地环境已经就绪:
- Node.js: 版本需在 16.8 或以上(以支持 Next.js)。推荐使用 LTS 版本。可以通过
node -v检查。 - 包管理器: 可以使用
npm,yarn或pnpm。模板的package.json中通常已经定义了脚本,与主流包管理器兼容。
初始化项目:最快捷的方式是使用create-next-app并直接指向该模板仓库。
npx create-next-app@latest my-product-showcase --typescript --tailwind --eslint --app --src-dir --import-alias "@/*" --no-src-dir注意:上述命令是创建 Next.js 官方模板的。对于第三方模板如jpedroschmitz/typescript-nextjs-starter,更常见的做法是直接使用其 GitHub 仓库作为模板,或者克隆后手动安装依赖。
推荐做法(克隆与设置):
# 1. 克隆仓库(或使用 GitHub 的 'Use this template' 按钮) git clone https://github.com/jpedroschmitz/typescript-nextjs-starter.git my-product-showcase cd my-product-showcase # 2. 安装依赖 npm install # 或 yarn install 或 pnpm install # 3. 运行开发服务器 npm run dev此时,打开浏览器访问http://localhost:3000,你应该能看到模板的示例页面。
第一步操作心得:在npm install之后,我习惯先运行npm run lint和npm run test,确保所有工具链在初始状态下工作正常。有时因为 Node 版本或缓存问题,可能会报错,这时可以尝试删除node_modules和package-lock.json后重新安装。
4.2 核心配置定制化
模板提供了良好的默认配置,但每个项目都需要进行个性化调整。
1. 修改package.json:立即更新name,description,author,repository.url等字段。这是项目的身份标识。
2. 配置tailwind.config.js:这是塑造项目视觉风格的第一步。假设你的品牌色是蓝色系。
// tailwind.config.js module.exports = { content: [ './src/pages/**/*.{js,ts,jsx,tsx}', './src/components/**/*.{js,ts,jsx,tsx}', ], theme: { extend: { colors: { primary: { 50: '#eff6ff', 100: '#dbeafe', 200: '#bfdbfe', 300: '#93c5fd', 400: '#60a5fa', 500: '#3b82f6', // 你的主品牌色 600: '#2563eb', 700: '#1d4ed8', 800: '#1e40af', 900: '#1e3a8a', }, }, fontFamily: { sans: ['Inter var', ...defaultTheme.fontFamily.sans], // 使用自定义字体 }, }, }, plugins: [], }现在,你可以在组件中使用bg-primary-500、text-primary-700这样的类名了。
3. 设置环境变量:Next.js 支持从.env.local文件加载环境变量。创建这个文件(并确保它在.gitignore中),用于存储敏感或环境相关的配置,如 API 密钥、数据库连接字符串。
# .env.local NEXT_PUBLIC_API_BASE_URL=https://api.your-service.com DATABASE_URL=your_database_connection_string SECRET_KEY=your_secret_key_here以NEXT_PUBLIC_开头的变量会在构建时被内联,可以在浏览器端代码中通过process.env.NEXT_PUBLIC_XXX访问。其他变量则只在服务端可用。
4.3 开发第一个功能:产品列表页
让我们实现一个简单的产品列表页面,它从模拟的 API 获取数据并展示。
1. 创建数据类型:在src/types/index.ts中定义产品类型。
// src/types/index.ts export interface Product { id: number; name: string; description: string; price: number; imageUrl: string; category: string; }2. 创建产品卡片组件:在src/components/ProductCard.tsx中创建一个展示单个产品的组件。
// src/components/ProductCard.tsx import React from 'react'; import Image from 'next/image'; // 使用 Next.js 优化后的图片组件 import { Product } from '@/types'; interface ProductCardProps { product: Product; } const ProductCard: React.FC<ProductCardProps> = ({ product }) => { return ( <div className="group relative flex flex-col overflow-hidden rounded-lg border border-gray-200 bg-white shadow-sm transition-all hover:shadow-lg"> <div className="aspect-h-4 aspect-w-3 bg-gray-200 sm:aspect-none"> <Image src={product.imageUrl} alt={product.name} width={300} height={200} className="h-full w-full object-cover object-center group-hover:opacity-90 sm:h-full sm:w-full" /> </div> <div className="flex flex-1 flex-col space-y-2 p-4"> <h3 className="text-sm font-semibold text-gray-900"> <a href={`/products/${product.id}`}> <span aria-hidden="true" className="absolute inset-0" /> {product.name} </a> </h3> <p className="text-sm text-gray-500 line-clamp-2">{product.description}</p> <div className="mt-auto flex items-center justify-between"> <p className="text-lg font-bold text-primary-600">${product.price.toFixed(2)}</p> <span className="inline-flex items-center rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium text-gray-800"> {product.category} </span> </div> </div> </div> ); }; export default ProductCard;3. 实现产品列表页面:修改src/pages/index.tsx作为我们的首页,使用getStaticProps进行静态生成,假设我们从某个 API 获取数据。
// src/pages/index.tsx import type { GetStaticProps, NextPage } from 'next'; import Head from 'next/head'; import ProductCard from '@/components/ProductCard'; import { Product } from '@/types'; // 模拟一个API调用函数 const fetchProducts = async (): Promise<Product[]> => { // 在实际项目中,这里会是 fetch(process.env.NEXT_PUBLIC_API_URL + '/products') // 这里我们返回模拟数据 return new Promise((resolve) => { setTimeout(() => { resolve([ { id: 1, name: '优质咖啡机', description: '全自动意式咖啡机,带来咖啡馆般的体验。', price: 299.99, imageUrl: '/images/coffee-maker.jpg', category: '厨房电器' }, { id: 2, name: '无线降噪耳机', description: '顶级主动降噪技术,享受纯净音乐。', price: 199.50, imageUrl: '/images/headphones.jpg', category: '电子产品' }, // ... 更多产品 ]); }, 100); }); }; interface HomePageProps { products: Product[]; } const HomePage: NextPage<HomePageProps> = ({ products }) => { return ( <> <Head> <title>产品展示平台 | 首页</title> <meta name="description" content="发现我们精选的优质产品" /> </Head> <div className="bg-white"> <div className="mx-auto max-w-2xl px-4 py-16 sm:px-6 sm:py-24 lg:max-w-7xl lg:px-8"> <h2 className="text-2xl font-bold tracking-tight text-gray-900">热门产品</h2> <div className="mt-6 grid grid-cols-1 gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-4 xl:gap-x-8"> {products.map((product) => ( <ProductCard key={product.id} product={product} /> ))} </div> </div> </div> </> ); }; export const getStaticProps: GetStaticProps<HomePageProps> = async () => { const products = await fetchProducts(); return { props: { products, }, // 如果数据需要更新,可以设置 revalidate 进行增量静态再生 (ISR) // revalidate: 60, // 每60秒重新生成一次页面(如果收到请求) }; }; export default HomePage;4. 添加全局布局与导航:修改src/pages/_app.tsx,添加一个简单的导航栏。
// src/pages/_app.tsx import '@/styles/globals.css'; import type { AppProps } from 'next/app'; import Link from 'next/link'; function MyApp({ Component, pageProps }: AppProps) { return ( <div className="min-h-screen bg-gray-50"> {/* 简单的导航栏 */} <nav className="bg-white shadow-sm"> <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8"> <div className="flex h-16 justify-between"> <div className="flex"> <Link href="/" className="flex items-center text-xl font-bold text-primary-600"> 产品平台 </Link> <div className="ml-10 flex items-center space-x-4"> <Link href="/" className="rounded-md px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100"> 首页 </Link> <Link href="/about" className="rounded-md px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100"> 关于 </Link> </div> </div> </div> </div> </nav> {/* 页面内容 */} <main> <Component {...pageProps} /> </main> {/* 页脚可以加在这里 */} </div> ); } export default MyApp;至此,一个具备数据获取、组件化、样式美化、类型安全的基本产品列表页就完成了。运行npm run dev,你就能在本地看到一个像模像样的网站了。
5. 进阶配置与深度优化
当项目逐渐复杂,你可能需要引入更多工具和模式。
5.1 状态管理:何时引入及如何选择
对于很多 Next.js 应用,特别是大量使用服务端渲染和静态生成的应用,你可能不需要一个全局状态管理库。React 自身的 Context API 结合useState,useReducer,以及 Next.js 的 Router 和 Data Fetching 方法(getStaticProps,getServerSideProps)已经能解决大部分状态问题。
需要引入 Zustand/Redux Toolkit 的信号:
- 复杂的、跨多个不相关组件的客户端状态:例如,一个复杂的多步骤表单状态,或者一个需要在整个应用范围内响应的用户偏好设置(如主题)。
- 从多个页面组件访问的服务器状态:虽然 React Query 或 SWR 更适合服务器状态缓存,但有时你需要将其与客户端状态结合管理。
- 需要时间旅行调试或持久化状态。
如果确定需要,模板可以轻松集成。以 Zustand(一个轻量且易用的状态管理库)为例:
npm install zustand创建一个 store:
// src/store/useProductStore.ts import { create } from 'zustand'; interface ProductStore { cart: Product[]; addToCart: (product: Product) => void; removeFromCart: (productId: number) => void; clearCart: () => void; } const useProductStore = create<ProductStore>((set) => ({ cart: [], addToCart: (product) => set((state) => ({ cart: [...state.cart, product], })), removeFromCart: (productId) => set((state) => ({ cart: state.cart.filter((item) => item.id !== productId), })), clearCart: () => set({ cart: [] }), })); export default useProductStore;然后在任何组件中即可使用:const { cart, addToCart } = useProductStore();
5.2 API 路由与后端集成
Next.js 的 API Routes 让你能在/pages/api目录下创建后端接口。这对于处理表单提交、与数据库交互或集成第三方服务非常有用。
示例:创建一个产品查询 API
// src/pages/api/products/[id].ts import type { NextApiRequest, NextApiResponse } from 'next'; import { Product } from '@/types'; // 模拟数据库 const mockProducts: Product[] = [...]; export default function handler( req: NextApiRequest, res: NextApiResponse<Product | { error: string }> ) { const { id } = req.query; if (req.method !== 'GET') { return res.status(405).json({ error: 'Method not allowed' }); } const productId = parseInt(id as string, 10); const product = mockProducts.find(p => p.id === productId); if (!product) { return res.status(404).json({ error: 'Product not found' }); } // 模拟网络延迟 setTimeout(() => { res.status(200).json(product); }, 100); }现在,前端就可以通过/api/products/1来获取 ID 为 1 的产品数据了。在真实的项目中,你会在 API Route 中连接 Prisma、Drizzle 等 ORM 来操作真实的数据库。
5.3 性能监控与分析
项目上线后,监控性能至关重要。Next.js 内置了next/analytics包,可以轻松集成 Vercel Analytics(如果你部署在 Vercel)。此外,可以考虑:
- Lighthouse CI: 集成到 GitHub Actions 中,每次提交都自动运行 Lighthouse 性能测试,确保代码变更不会导致性能回归。
- Sentry / LogRocket: 用于错误监控和用户会话回放,帮助快速定位生产环境中的问题。
- 自定义性能指标: 使用
web-vitals库在客户端测量并上报真实用户的核心 Web 指标(如 LCP, FID, CLS)。
6. 部署与持续集成/持续部署
这个模板通常已经为部署做好了准备。package.json中的build脚本会运行next build,生成一个高度优化的生产版本。
部署到 Vercel(最无缝的体验):
- 将代码推送到 GitHub、GitLab 或 Bitbucket。
- 在 Vercel 上导入你的仓库。
- Vercel 会自动检测到这是一个 Next.js 项目,并使用最优配置进行构建和部署。它会自动处理环境变量、服务器less函数(API Routes)等。
- 此后,每次向主分支推送代码,都会触发自动部署。
部署到其他平台(如 AWS, GCP, 自有服务器):你需要一个能运行 Node.js 的环境。构建后,你会得到一个.next目录。你可以使用next start命令来启动生产服务器。许多平台都提供了 Docker 镜像或直接支持 Node.js 运行时的部署方式。
CI/CD 配置:模板的.github/workflows目录下可能已经包含了 CI 配置文件。一个典型的 CI 流程包括:
- 代码检查:运行
npm run lint和npm run type-check(如果配置了)。 - 运行测试:运行
npm test。 - 构建测试:运行
npm run build,确保项目能成功构建。 - (可选)E2E 测试:使用 Cypress 或 Playwright 运行端到端测试。
这些检查通过后,代码才能合并到主分支,从而保证主分支的代码质量。
7. 常见问题与避坑指南
在实际使用这个模板或开发 Next.js 应用的过程中,你肯定会遇到一些坑。以下是我总结的一些常见问题及解决方案。
问题1:getStaticProps/getServerSideProps中无法使用useRouter或其他 React Hooks。
- 原因:
getStaticProps和getServerSideProps是 Next.js 的数据获取函数,它们在组件渲染之前、在服务端运行,而 Hooks 只能在 React 函数组件内部调用。 - 解决方案:
- 如果需要路由参数,可以从
getStaticProps的context参数中获取params。
export const getStaticProps: GetStaticProps = async (context) => { const { id } = context.params!; // 对于动态路由 [id].tsx // ... 用 id 获取数据 };- 如果需要在组件内部根据路由状态做事情,就在组件内部使用
useRouter。
- 如果需要路由参数,可以从
问题2:Tailwind CSS 的样式在动态生成的类名或第三方组件中不生效。
- 原因:Tailwind 的 JIT 引擎默认只扫描
tailwind.config.js中content配置指定的文件,来寻找用到的类名并生成对应的 CSS。如果你的类名是通过字符串拼接或来自第三方库,Tailwind 可能无法检测到。 - 解决方案:
- 安全列表:在
tailwind.config.js的safelist数组中预先声明这些动态类名。
module.exports = { safelist: [ 'bg-red-500', 'text-center', 'lg:text-right', { pattern: /bg-(red|green|blue)-(100|500)/ }, // 使用正则匹配模式 ], }- 完整生成:在开发环境下,可以暂时将
content配置改为['./src/**/*.{js,ts,jsx,tsx}']以确保所有文件被扫描,但这不是生产环境的最佳实践,因为它会生成巨大的 CSS 文件。
- 安全列表:在
问题3:图片优化next/image组件在部署到非 Vercel 平台时出现问题。
- 原因:
next/image的默认优化器是为 Vercel 平台优化的。在其他平台上,你需要配置一个自定义的优化器,或者使用未优化的普通<img>标签。 - 解决方案:
- 在
next.config.js中配置images字段,指定你的图片域名和路径。
module.exports = { images: { domains: ['images.unsplash.com', 'your-cdn-domain.com'], // 允许优化的外部图片域名 // 或者使用 path 模式 // path: 'https://your-cdn.com/', }, }- 如果自定义平台不支持,可以暂时将
unoptimized: true设置为true来禁用优化,但会失去性能优势。
- 在
问题4:ESLint 报错太多,或者与 Prettier 冲突。
- 原因:模板的 ESLint 配置可能比较严格,或者 ESLint 和 Prettier 的规则有重叠冲突。
- 解决方案:
- 确保你安装了正确的依赖:
eslint,eslint-config-next,eslint-config-prettier。 - 在
.eslintrc.json中,确保extends数组里'next'或'next/core-web-vitals'在最后,并且包含了'prettier'来关闭与 Prettier 冲突的规则。 - 如果某些规则你觉得过于严格,可以在
rules对象中覆盖它们,例如'@typescript-eslint/no-explicit-any': 'warn'。
- 确保你安装了正确的依赖:
问题5:TypeScript 在引入模块或使用路径别名时报错。
- 原因:TypeScript 的路径解析 (
tsconfig.json中的paths) 需要和打包工具(Webpack,通过 Next.js 配置)的别名配置对齐。 - 解决方案:
- 检查
tsconfig.json中的compilerOptions.paths是否配置正确。模板通常配置了"@/*": ["./src/*"]。 - 检查
next.config.js中是否配置了相应的 Webpack 别名(现代 Next.js 版本通常会自动读取tsconfig.json的配置)。 - 重启你的 TypeScript 语言服务器(在 VS Code 中,可以执行命令
TypeScript: Restart TS server)。
- 检查
使用这个typescript-nextjs-starter模板,就像是获得了一辆已经调试好的赛车,你不需要再从组装发动机开始,而是可以直接坐进驾驶舱,思考你的赛道策略。它提供的稳定、现代的基础设施,能让你将宝贵的开发精力完全投入到创造业务价值本身,而不是在无穷无尽的基础配置中消耗热情。
