Skip to content

3 招让你的 Shadcn 出海应用性能提升 40 倍 #435

@mqyqingfeng

Description

@mqyqingfeng

3 招让你的 Shadcn 出海应用性能提升 40 倍

你好,我是冴羽

Shadcn UI + Next.js 15 + Tailwind CSS 4 是最常见的构建出海网站的技术栈。

本篇和你分享 3 个技巧,让你从一开始就构建出高性能应用。

1. 第一招:Tree Shaking

Tree Shaking 会删除那些你导入了但从来没用过的代码。

而且 Shadcn UI 因为把组件源码直接复制到你的项目里,打包工具可以直接分析和优化它们。

如何操作:

步骤 1:配置 package.json

告诉打包工具哪些文件是无副作用的:

// package.json
{
  "sideEffects": false  // 所有文件都是 pure
}

// 指定
{
  "sideEffects": ["*.css", "./src/polyfills.js"]
}

因为打包工具做 Tree Shaking 通常十分保守。

如果它不确定一个模块是否有副作用,就会保守地保留整个模块,即使你只导入了其中一个函数。

步骤 2:只导入需要的内容

// You only import what you need
import { Button } from "@/components/ui/button";

// Unused variants? Automatically removed by minifier
// 在传统的组件库中,打包工具无法优化它看不到的内容。而使用 Shadcn UI,一切都是透明的。

最佳实践:

// ❌ Bad - Imports everything
import * as utils from "./utils";

// ✅ Good - Imports only needed
import { formatDate } from "./utils";

// ❌ Bad - Default export object
export default { fn1, fn2, fn3 };

// ✅ Good - Named exports
export { fn1, fn2, fn3 };

步骤 3:验证效果

npm install @next/bundle-analyzer

# next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
})

module.exports = withBundleAnalyzer({ /* config */ })

# 运行分析
ANALYZE=true npm run build

捆绑分析器2

2. 第二招:Code Splitting

Code splitting 会把代码分成更小的块,在需要时才加载。

Next.js 会自动在页面级别分割代码,你只需要用 next/dynamic 处理重型组件。

如何操作:

// ❌ Without splitting - loads immediately
import HeavyModal from '@/components/heavy-modal'

// ✅ With splitting - loads on demand
import dynamic from 'next/dynamic'

const HeavyModal = dynamic(() => import('@/components/heavy-modal'), {
  loading: () => <p>Loading...</p>,
  ssr: false  // Skip server-side rendering (see warning below)
})

分享一个实战案例:

// components/user-profile-modal.tsx
'use client'

import { Dialog, DialogContent } from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import Cropper from 'react-easy-crop'  // Heavy library

export function UserProfileModal({ open, onOpenChange, user }) {
  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent>
        <Cropper image={user.avatar} /* ... */ />
        <Button>Save</Button>
      </DialogContent>
    </Dialog>
  )
}
// app/users/page.tsx - Lazy load modal
import dynamic from 'next/dynamic'

const UserProfileModal = dynamic(
  () => import('@/components/user-profile-modal')
    .then(mod => ({ default: mod.UserProfileModal })),
  { ssr: false }
)

export default function UsersPage() {
  const [open, setOpen] = useState(false)

  return (
    <>
      <Button onClick={() => setOpen(true)}>View Profile</Button>
      {open && <UserProfileModal open={open} onOpenChange={setOpen} />}
    </>
  )
}

此时只有点击按钮时才会加载 150KB 的模态框!

3. 第三招:用 Tailwind CSS 4 优化 CSS

Tailwind CSS 4 使用 JIT 编译器,它会按需生成 CSS,只生成你实际使用的样式类。

比如你的代码是:

<button class="rounded bg-blue-500 px-4 py-2 hover:bg-blue-600">Click me</button>

它会仅生成以下类:

.bg-blue-500 {
  background-color: #3b82f6;
}
.hover\\:bg-blue-600:hover {
  background-color: #2563eb;
}
.px-4 {
  padding-left: 1rem;
  padding-right: 1rem;
}
.py-2 {
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}
.rounded {
  border-radius: 0.25rem;
}

配合 Shadcn UI 的 CSS 变量,可以实现运行时主题切换,无需重新构建。

Shadcn完美地运用了 CSS 变量:

:root {
  --primary: 222.2 47.4% 11.2%;
  --foreground: 210 40% 98%;
}

.dark {
  --primary: 210 40% 98%;
  --foreground: 222.2 84% 4.9%;
}

当组件使用这些变量:

<Button className="bg-primary text-primary-foreground">
  Click me
</Button>

Tailwind 会生成:

.bg-primary {
  background-color: hsl(var(--primary));
}
.text-primary-foreground {
  color: hsl(var(--primary-foreground));
}

这样做的好处在于 无需重建即可更改主题!

一个切换主题的示例如下:

'use client'

export function ThemeCustomizer() {
  const applyTheme = (primaryColor: string) => {
    document.documentElement.style.setProperty('--primary', primaryColor)
  }

  return (
    <div className="space-y-2">
      <Button onClick={() => applyTheme('222.2 47.4% 11.2%')}>
        Dark Theme
      </Button>
      <Button onClick={() => applyTheme('142.1 76.2% 36.3%')}>
        Green Theme
      </Button>
      <Button onClick={() => applyTheme('346.8 77.2% 49.8%')}>
        Red Theme
      </Button>
    </div>
  )
}

总结

记住: 性能是一个功能。 从第一天就把它构建进去。

用户可能不会注意到你的网站有多快,但他们绝对会注意到它有多慢。

从今天就开始:

  1. 运行 ANALYZE=true npm run build 看看你的 bundle

  2. 选最大的 chunk 优化它

  3. 测量改进

  4. 重复优化下一个最大的 chunk

小改进有复利效果。如果你每个迭代有 10% 的改进,7 个迭代后性能就能翻倍!

我是冴羽,10 年笔耕不辍,专注前端领域,更新了 10+ 系列、300+ 篇原创技术文章,翻译过 Svelte、Solid.js、TypeScript 文档,著有小册《Next.js 开发指南》、《Svelte 开发指南》、《Astro 实战指南》。

欢迎围观我的“网页版朋友圈”,关注我的公众号:冴羽(或搜索 yayujs),每天分享前端知识、AI 干货。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions