将 jaimebuilds.com 升级到 Astro 7、Tailwind 4 与 TypeScript 6
把作品集发布在 Astro 栈的最新版本上。迁移过程中坏了五件事。页面体积从约 100 KB 降到 13.6 KB。下面是 changelog 与修复方案。
这个站点现在运行在 Astro 7.0.3、Tailwind 4.3.1 与 TypeScript 6.0.3 上。重设计分支今天早些时候上线,主页的 live proof 条最终稳定在 13.6 KB 的总体积和 313 ms 的桌面浏览器加载时间。
升级用了一个下午。有意思的不是把 package.json 里的版本号往上调。而是版本跳跃带来的五个小型破坏性改动。我先读的 release notes 里一个都没提。它们都以构建错误或者静默坏掉的布局形式冒出来。
把 changelog 分享出来,因为肯定有人正要做同样的升级。
起点
迁移之前这个站点跑在:
- Astro 5.16.6,
output: 'server',部署在 Vercel - Tailwind 3.4,带
@astrojs/tailwind集成和tailwind.config.ts - React 19.2.3 islands
- TinaCMS 用于内容编辑
lenis平滑滚动、motion动画、深浅色切换、astro-icon、astro-i18next
同时刚在另一个分支上完成了一次彻底的重设计(瑞士编辑风格布局、暖奶油色调、Shopify Plus 导向的文案)。所以升级和重设计一起上线。
1. LegacyContentConfigError
版本升级后第一个构建失败:
[LegacyContentConfigError] Found legacy content config file in
"src/content/config.ts". Please move this file to "src/content.config.ts"
and ensure each collection has a loader defined.Astro 6 把 content collections 移出了 src/content/config.ts,并要求每个集合显式声明 loader。新位置是 src/content.config.ts(路径里没有 content/ 目录)。新的形态用从 astro/loaders 导入的 loader 替换了 type: 'content'。
之前:
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({ title: z.string(), date: z.coerce.date() }),
});
export const collections = { blog };之后:
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
schema: z.object({ title: z.string(), date: z.coerce.date() }),
});
export const collections = { blog };站点有九个集合(blog、work、lab 各三种语言),所以是九行 loader: glob(...) 加一次文件重命名。
2. post.render() 消失了
在 [slug].astro 里,旧 API 是:
const { post } = Astro.props;
const { Content } = await post.render();post.render() 在 Astro 6 被移除。替代方案是顶层的 render 函数:
import { getCollection, render } from 'astro:content';
const { post } = Astro.props;
const { Content } = await render(post);行为相同,导入不同。九个 [slug].astro 都要改。
3. post.slug 现在叫 post.id
同一次迁移。当你用新的 loader API 读取条目时,原来的 post.slug 现在叫 post.id。形态变了,因为 loaders 可以产出不来自文件的条目,那种条目谈 “slug” 没意义。
原来写:
<a href={`/blog/${post.slug}/`}>{post.data.title}</a>现在写:
<a href={`/blog/${post.id}/`}>{post.data.title}</a>对于 glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),id 就是文件相对 base 的路径去掉扩展名,和旧的 slug 一模一样。URL 不变,仅仅是一次重命名。
4. @astrojs/tailwind 不支持 Astro 6 与 7
@astrojs/tailwind 集成的 peer dependency 卡在 Astro 5。Astro 6+ 官方的路径是 Tailwind 4 的 Vite 插件:@tailwindcss/vite。
具体写法:
// astro.config.mjs(之前)
import tailwind from '@astrojs/tailwind';
export default defineConfig({
integrations: [tailwind({ applyBaseStyles: false })],
});
// astro.config.mjs(之后)
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
vite: { plugins: [tailwindcss()] },
});Tailwind 4 也放弃了 JavaScript 配置文件,改为 CSS 优先的配置方式。tailwind.config.ts 不再存在。设计 token 现在写在主 CSS 文件的 @theme 块里,Tailwind 会自动生成对应的 utility:
@import "tailwindcss";
@plugin "@tailwindcss/forms";
@plugin "@tailwindcss/typography";
@theme {
--color-v2-bg: #f4f1ea;
--color-v2-ink: #161310;
--color-v2-accent: #8a2417;
--font-v2-sans: "Geist", -apple-system, sans-serif;
--font-v2-serif: "Newsreader", Georgia, serif;
}--color-v2-bg: #f4f1ea 自动生成 bg-v2-bg、text-v2-bg、border-v2-bg 以及对应的变体。--font-v2-sans 生成 font-v2-sans。插件用同一文件中的 @plugin 指令引入。整个 JS 配置文件都没了。
5. 差点把坏掉的站点发上线那个
构建变绿、部署上线之后,我打开预览 URL,首页只有一半样式。颜色和字体生效了。栅格没生效。容器没有 max-width。导航菜单不可见。CTA 按钮上下堆叠而不是并排。
罪魁是 astro-compress。它在 Vite 之后跑第二轮 CSS 压缩。Tailwind 3 时它无害。Tailwind 4 时它似乎会丢弃或破坏它没识别为被引用的 utility,特别是那些 arbitrary value(max-w-[1280px]、lg:grid-cols-[1.4fr_1fr])和响应式变体(hidden md:flex)。font-medium 或 border 这种简单 utility 活下来了。复杂的没活。
修复:
compress({
CSS: false,
HTML: true,
Image: true,
JavaScript: true,
SVG: true,
}),Vite 本身已经正确地压缩了 CSS bundle。第二轮是多余的。把 CSS: false 一关,布局就回来了。
值得标注:构建是绿的。部署是上线状态。任何日志里都没有错误信号。唯一的提示是预览里的一张截图。
顺带掉出来的东西
升级正好是一次大扫除的时机。我移除了九个重设计已经不再需要的依赖:
lenis与motion:没有平滑滚动,没有动画库astro-icon与@iconify-json/mdi:只用内联 SVGastro-i18next与i18next:重设计用硬编码语言路径@astrojs/tailwind:由@tailwindcss/vite替代- 深色模式 CSS 与主题切换:重设计只走亮色
还删掉了十七个新布局已经让其过时的 V1 组件。
结果:主页 live proof 条测量到 13.6 KB 的总传输字节(HTML + CSS + JS),桌面浏览器的 domInteractive 是 313 ms。之前的站点在 80 到 120 KB 之间。差不多 7 到 9 倍的减重,而且重设计视觉上比被它替代的版本更厚重。
一行五点版的迁移
- 把
src/content/config.ts重命名为src/content.config.ts,并为每个集合加上loader: glob({...})。 - 把
await post.render()替换为await render(post),从'astro:content'导入render。 - 把
post.slug改成post.id,凡是集合条目都要改(URL 的params: { slug }不变)。 - 卸掉
@astrojs/tailwind,装@tailwindcss/vite,删tailwind.config.ts,把 token 搬到 CSS 的@theme块。 - 把
astro-compress的CSS设为false。信任 Vite。
如果你正在做同样的升级,这个顺序是行得通的。整条分支是公开的,想看 diff 可以去:github.com/jaimesolis/jaimebuilds。
剩下的笔记(以及偶尔关于 Shopify Plus 主题构建的吐槽)我都发在 X 上。如果这种调试笔记对你有用,欢迎关注:@jaimesolis。如果你正在 Astro 升级或 Hydrogen 迁移中卡住,想多一双眼睛看一下,联系表单点两下就到。