Skip to content

最佳实践

一些项目中的最佳实践,但未必总是需要遵循。

Vite + React 还是 Next.js

我们始终优先考虑使用 Vite + React,在明确需要 Next.js 提供的非可替代的功能时,才会考虑使用 Next.js。 与此同时,一些相关的技术栈也会有所不同。

关于依赖的选择

Next.js

  1. 异步数据请求:swr + ofetch
  2. 环境变量校验:t3-env

Vite + React

  1. 路由:react-router
  2. i18n: react-i18next

通用

  1. 状态管理:jotai
  2. CSS:UnoCSS + unocss-preset-shadcn + unocss-preset-animations / tailwindcss
  3. Icon:@unocss/preset-icons / @egoist/tailwindcss-icons
    1. icones
    2. @iconify-json/lucide
    3. @iconify-json/simple-icons
    4. @iconify-json/mdi
  4. UI 库:shadcn/ui + sonner
  5. 动画:framer-motion
  6. react hooks:foxact / usehooks
  7. 日期处理:date-fns / dayjs
  8. 数据校验:zod

关于 Tailwind CSS 和 UnoCSS

  1. Tailwind CSS 需要 postcss,而 UnoCSS 不需要额外依赖
  2. Tailwind CSS 在社区中更流行,UnoCSS 更先进

生态对比

  1. Tailwind CSS 需要 eslint-plugin-tailwindcss 来校验 CSS 类名,而 UnoCSS 的规则一般足够灵活,开发者不易犯错,且 UnoCSS 的 VSCode 插件能够校验
  2. shadcn/ui 优先支持 Tailwind CSS,UnoCSS 有 unocss-preset-shadcn 来支持
  3. 图标方案,Tailwind CSS 有 @egoist/tailwindcss-icons,UnoCSS 有 @unocss/preset-icons
  4. Tailwind CSS 的插件补全体验略好于 UnoCSS

总结:在 Next.js 项目中,优先使用 Tailwind CSS,否则优先使用 UnoCSS。

pnpm 不提升任何依赖

在使用 eslint flat config 之后,我们无需提升 eslint 或者 prettier 相关的包,所以优先开启这个配置。

txt
public-hoist-pattern[]=""

Vite 插件

进行 ESLint 和 TypeScript 检查

使用 vite-plugin-checker 插件。 在 feat: support eslint flat config 合并前,暂且需要使用 @hyoban/vite-plugin-checker

ts
import Checker from "@hyoban/vite-plugin-checker"
import { defineConfig } from "vite"

export default defineConfig({
  plugins: [
    Checker({
      typescript: true,
      eslint: {
        lintCommand: "eslint --max-warnings 0 .",
        useFlatConfig: true,
      },
      // enableBuild: false,
    }),
  ],
})

自动应用 TS Config 别名

Vite 默认不会遵循 tsconfig.json 中的别名配置,可以使用 vite-tsconfig-paths 插件来解决这个问题。

ts
import { defineConfig } from "vite"
import TsconfigPaths from "vite-tsconfig-paths"

export default defineConfig({
  plugins: [TsconfigPaths()],
})
ts
import path from "path"
import { defineConfig } from "vite"

export default defineConfig({
  resolve: {
    alias: {
      "~": path.resolve(__dirname, "./src"),
    },
  },
})