
Blog底层更新记录
把博客底层从 Astro 5 + Tailwind 3 + DaisyUI 4 升级到 Astro 7 + Tailwind 4 + DaisyUI 5 的记录与踩坑
前几天脑子发昏闲的无聊突然想把这个blog的底层库更新一下,再加上我这个人纯闲的和喜欢追求最新版,这里就纯当记录了。(写的页非常简单,仅供参考吧,慎重更新)
刚好过blog一周年了,权当“庆生😂”了
先说一下之前的情况,之前是Astro 5 + Tailwind 3 + DaisyUI 4的架构,升级后变为Astro 7 + Tailwind 4 + DaisyUI 5,Astro的配套组件全部最新,但是注意的是俺在写的时候TypeScript 7还没有支持Astro,因此只用了TypeScript 6最新版。
这里说一下更新会导致的浏览器适配问题,Tailwind v4要求Chrome ≥111、Edge ≥111、Firefox ≥128、Safari ≥16.4,更新会导致旧机型的不适配
更新开始
简单更新版本
package.json
// 新增依赖 "@astrojs/markdown-remark": "^7.2.2" // 独立 markdown 处理 "@iconify/tailwind4": "^1.2.3" // Tailwind 4 版 Iconify "@tailwindcss/vite": "^4.3.3" // Tailwind Vite 插件(替代 @astrojs/tailwind)
// 移除依赖 "@astrojs/tailwind": "^6.0.2" // 不再需要 "@iconify/tailwind": "^1.2.0" // 替换为 tailwind4 版本 "@typescript-eslint/parser": "^8.48.1" // 不再需要 "sass-embedded": "^1.93.3" // SCSS → CSS 迁移 "medium-zoom": "^1.1.0" // 移除 "remark": "^15.0.1" // 由 @astrojs/markdown-remark 替代
"typescript": "^5.9.3" "typescript": "^6.0.3"
// 其余均为直接版本升级pnpm-workspace.yaml
allowBuilds: sharp: true swup: false unrs-resolver: true // Astro 7 需要astro.config.mjs Astro 配置迁移
import tailwind from "@astrojs/tailwind"; const playformCompress = (await import("@playform/compress")).default; // 同步 import import tailwindcss from "@tailwindcss/vite"; // Tailwind 4 使用 Vite 插件 import { unified } from "@astrojs/markdown-remark"; // 独立 markdown processor
export default defineConfig({ integrations: [ // ... 其他 integrations tailwind({ configFile: "./tailwind.config.mjs", }), // Tailwind 4 不再需要 integration playformCompress(), playformCompress({ Image: false, // 必须禁用,sharp 版本不兼容 JavaScript: false, // JS 由 terser 处理 }), ], markdown: { remarkPlugins: [...], rehypePlugins: [...], processor: unified({ // 新的 markdown processor API remarkPlugins: [...], rehypePlugins: [...], }), }, vite: { plugins: [tailwindcss()], // Tailwind 4 Vite 插件 build: { cssMinify: "esbuild", // 必须!lightningcss 不支持 @apply }, css: { preprocessorOptions: { scss: { api: "modern-compiler" }, // SCSS 配置移除 }, }, }, style: { scss: { includePaths: ["./src/styles"], // 移除 SCSS 配置 }, },});cssMinify: "esbuild":这是 Tailwind 4 迁移的必选项。Vite 默认使用 lightningcss 压缩 CSS,但不识别 Tailwind 的@apply指令,会输出约 120+ 条警告。esbuild 对于未知 at-rule 保持静默。@playform/compress禁用 Image: 该插件捆绑的 sharp 0.34.5 在处理不含 ICC 配置文件的 PNG 时抛出colourspace: parameter space not set错误。建议项目中图片预优化,无需二次压缩。@playform/compress禁用 JavaScript: JS 压缩已由@rollup/plugin-terser负责,避免重复处理。
Tailwind 4 改为 CSS-first 配置,不再需要 tailwind.config.mjs:建议参考Tailwind 4官方升级指南↗,里面有更新插件,理论上可以省去部分废弃/修改的css样式的适配(后面会提到)
// 删除 tailwind.config.mjs /** @type {import('tailwindcss').Config} */ export default { content: ["./src/**/*.{astro,html,js,md,mdx,svelte,ts,tsx,vue}"], plugins: [daisyUI, typography, addDynamicIconSelectors()], daisyui: { themes: ["winter", "night"], darkTheme: "night", logs: false, }, };新建 src/styles/tailwind.css
@import "tailwindcss";@import "./global.css"; /* 导入自定义全局样式 */
@theme { --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";}
@plugin "@tailwindcss/typography";@plugin "@iconify/tailwind4";@plugin "daisyui" { themes: winter --default, night --prefersdark; logs: false;}@theme指令替代theme.extend— 自定义主题值在@theme块中定义@plugin指令替代plugins: [...]— Tailwind 插件使用@plugin导入- 无需
content配置 — Tailwind 4 自动检测模板文件 @import替代@tailwind base/components/utilities
DaisyUI 配置变化
// DaisyUI v4 (tailwind.config.mjs) daisyui: { themes: ["winter", "night"], darkTheme: "night", logs: false, }
// DaisyUI v5 (tailwind.css)@plugin "daisyui" { themes: winter --default, night --prefersdark; logs: false;}部分破坏性变更,更多参见官方文档↗
| 特性 | v4 | v5 |
|---|---|---|
| 配置方式 | JS 对象 | CSS @plugin 指令 |
input-bordered | ✅ 存在 | ❌ 移除,input 默认有边框 |
btn-outline | 正常 | 行为略有不同 |
shadow-sm | ✅ | ❌ 改为 shadow-xs |
collapse 组件 | HTML 结构 | ❌ 移除,需自行实现 |
- DaisyUI 5 中很多组件样式行为有微妙变化,需要逐个组件检查
详细更新适配
Content Layer API 变更
Astro 7 的 Content Layer API 与 Astro 5 有显著不同。
新建 src/content.config.ts,将原来的src/content/config.ts可以直接重命名并易懂
import { defineCollection } from "astro:content";import { z } from "astro/zod";import { glob } from "astro/loaders";
const blog = defineCollection({ loader: glob({ pattern: ["**/*.{md,mdx}"], base: "./src/content/blog", }), schema: z.object({ title: z.string(), description: z.string(), pubDate: z.coerce.date(), updated: z.coerce.date().optional(), // ... 其他字段 }),});
export const collections = { blog };| 旧 API (Astro 5) | 新 API (Astro 7) | 说明 |
|---|---|---|
blog.slug | blog.id | slug 改名为 id |
blog.render() | render(blog) | render 变为独立函数 |
getCollection() from astro:content | 不变 | 但需单独导入 render |
代码迁移示例
import { getCollection } from "astro:content"; import { getCollection, render } from "astro:content";
// slug → id <a href={`/blog/${post.slug}`}> <a href={`/blog/${post.id}`}>
// render() 调用 const { Content } = await blog.render(); const { Content } = await render(blog);
// getStaticPaths params: { slug: blog.slug }, params: { slug: blog.id },CSS 系统迁移:SCSS → Tailwind CSS
项目原先使用 SCSS(global.scss),现迁移为纯 CSS(global.css),利用 Tailwind 4 的 @apply + CSS nesting。
文件结构变化
src/styles/global.scss (719 行, SCSS)tailwind.config.mjs (JS 配置)src/styles/global.css (1207 行, 纯 CSS)src/styles/tailwind.css (Tailwind 4 入口)@tailwind指令移除 — 全局样式中不再需要@tailwind base/components/utilities- SCSS 特性替换:
@mixin/@include→ CSS@layer+ 复用类$variable→ CSS 自定义属性--variable- 嵌套选择器 → 原生 CSS Nesting(已广泛支持)
@apply保持可用 — 在global.css中仍然可以使用@apply
astro.config.mjs 中移除 SCSS 配置(部分上面已经修改过了)
style: { scss: { includePaths: ["./src/styles"], },},vite.css.preprocessorOptions.scss: { api: "modern-compiler",},Tailwind组件的切换在上面说过理论上可以使用官方提供的一个插件进行,但是这里需要注意的是插件似乎是简单的检索替换,如果在部分文件中使用了检索到的相同的变量名也会被错误替换,建议构建重试再提交。
其他
js-yaml ^4 → ^5
import yaml from "js-yaml";import * as yaml from "js-yaml";Waline 组件的 define:vars 写法变化(Astro 7 不支持在 define:vars 中内联引用 Astro.props.X)
serverURL: Astro.props.serverURL,lang: Astro.props.lang ?? "zh",// 改为先解构再传入变量名const { serverURL, lang = "zh" } = Astro.props;// define:vars 中直接引用变量serverURL,lang,其他的就是 Astro 7 的空白符(whitespace)规则改动多行 inline 元素换行,旧版自动生成空格;新版 JSX 模式,不生成空格,行内文字直接贴在一起。最直接的可能就是license的作者和证书之间没有空格了,还有其他的地方可以自行调整一下。
另外,对于字体的,tailwind似乎在4的时候更新了字体(又或者是系统字体放在了前面),如果要维持3的字体可以在tailwind.css中添加
@theme { --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";}还有一件事,在之前似乎会出现md:xx lg:xx,会使部分组件之前的lg屏幕也是以md屏幕的样式进行展示,更新后会进行修正,使lg屏幕版本正确显示组件样式,这样会导致看起来大小似乎不一样。如果要维持可对部分组件进行调整(我直接将lg改为2xl才修改就可以了()
再再再的事,对于global.css中还可以添加:
@layer base { *, ::after, ::before, ::backdrop, ::file-selector-button { border-color: var(--color-gray-200, currentColor); }
input::placeholder, textarea::placeholder { color: var(--color-gray-400); } /*(可选)可点击元素鼠标指针样式*/ button:not(:disabled), [role="button"]:not(:disabled) { cursor: pointer; } /*(建议)分割线 hr 上下外边距强制统一,主要是license的区域*/ hr { margin-block: 1rem !important; }}如果你更新了pagefind从1.4.0到1.5.x,可能还需要更新search页面,可能会报错Pagefind: WASM Error (No pointer)
- bundlePath 路径解析失败:@pagefind/default-ui 包通过检查 document.currentScript 来判断 pagefind.js 的位置。但当通过动态 import() 加载时(而且 Astro 通过 Vite 打包时),document.currentScript 永远为 null。所以 bundlePath 变成了 undefined。
- 构建产物中使用了错误的 baseUrl:当前的 dist/ 构建产物传入的是 baseUrl: “/pagefind/“,这会构造出类似 /pagefind/blog/文章路径 这样的错误链接(应该用 / 作为 baseUrl),但这并非问题的根源——根源在于缺少 bundlePath。
即需要
const search = new PagefindUI({ element: "#pagefind-search", bundlePath: "/pagefind/", showImages: false, ...});如果想的话还可以将pagefind default-ui 迁移为 component-ui,闲的话可以折腾一下
后记
见鬼了部署更新后无论怎么刷新都会报错,在本地还正常,我还以为是我组件的问题,结果发现是浏览器缓存的问题。删缓存又删了半天,一开始以为是vercel/cloudflare端的,结果发现就edge不能正常看,后面在Service Worker里搞了半天也不行,最后可以直接开发工具-应用-储存里直接全部清理掉就正常了,整了一天…
总结
- 更新
package.json中的所有依赖版本 - 更新
pnpm-workspace.yaml添加unrs-resolver: true - 执行
pnpm install - 创建
src/styles/tailwind.css作为 Tailwind 4 入口 - 删除
tailwind.config.mjs - 迁移
global.scss→global.css(移除@tailwind指令) - 更新
astro.config.mjs(Tailwind Vite 插件、Markdown processor、cssMinify 等) - 创建
src/content.config.ts - 批量替换所有
.svelte和.astro文件中的 Tailwind 工具类 - 替换
blog.slug→blog.id,blog.render()→render(blog) - 运行
pnpm build验证构建成功
写在最后:累死我了,纯属吃力不讨好,纯属闲的。个人感觉就是构建的时候提速了一下,在vercel上原本需要两分半构建时间现在只要两分钟不到吧。但是这个和我有什么关系…适配的机型还变少了