阅读视图

发现新文章,点击刷新页面。
🔲 ☆

Nuxt Content v3 中数组字段的筛选困境与性能优化

Nuxt Content 是 Nuxt 生态中用于处理 Markdown、YAML 等内容的强大模块。最近,我在使用 Nuxt v4 + Nuxt Content v3 重构博客(原为 Hexo)时,遇到了一个棘手的问题:v3 版本的默认查询 API 并未直接提供对数组字段进行“包含”($contains)操作的支持。

例如,这是我的正在写的这篇博客的 Front Matter:

---
title: Nuxt Content v3 中数组字段的筛选困境
date: 2025-10-20 21:52:59
sticky:
tags:
- Nuxt
- Nuxt Content
- JavaScript
---

我的目标是创建一个 Tag 页面,列出所有包含特定 Tag(例如 'Nuxt')的文章。

v2 的便捷与 v3 的限制

在 Nuxt Content v2 中,数据基于文件系统存储,查询方式是对文件内容的抽象,模拟了类似 MongoDB 的 JSON 文档查询语法。我们可以轻松地使用 $contains 方法获取所有包含 “Nuxt” 标签的文章:

const tag = decodeURIComponent(route.params.tag as string)

const articles = await queryContent('posts')
  .where({ tags: { $contains: tag } })  // ✅ v2 中的 MongoDB Style 查询
  .find()

但在使用 Nuxt Content v3 的 queryCollection API 时,我们很自然地会尝试使用 .where() 方法进行筛选:

const tag = decodeURIComponent(route.params.tag as string)

const { data } = await useAsyncData(`tag-${tag}`, () =>
    queryCollection('posts')
        .where(tag, 'in', 'tags')  // ❌ 这样会报错,因为第一次参数必须是字段名
        .order('date', 'DESC')
        .select('title', 'date', 'path', 'tags')
        .all()
)

遗憾的是,这样是行不通的。.where() 的方法签名要求字段名必须作为首个参数传入:where(field: keyof Collection | string, operator: SqlOperator, value?: unknown)

由于 Nuxt Content v3 底层采用 SQLite 作为本地数据库,所有查询都必须遵循类 SQL 语法。如果设计时未提供针对数组字段的内置操作符(例如 $contains 的 SQL 等价形式),最终的解决方案往往会显得比较“别扭”。

初版实现:牺牲性能的“全量拉取”

本着“尽快重构,后续优化”的思路,我写出了以下代码:

// 初版实现:全量拉取后使用 JS 筛选
const allPosts = (
    await useAsyncData(`tag-${route.params.tag}`, () =>
        queryCollection('posts')
            .order('date', 'DESC')
            .select('title', 'date', 'path', 'tags')
            .all()
    )
).data as Ref<Post[]>

const Posts = computed(() => {
    return allPosts.value.filter(post =>
        typeof post.tags?.map === 'function'
            ? post.tags?.includes(decodeURIComponent(route.params.tag as string))
            : false
    )
})

这种方法虽然满足了需求,但也带来了明显的性能代价:_payload.json 文件体积的膨胀。

在 Nuxt 项目中,_payload.json 用于存储 useAsyncData 的结果等动态数据。在全量拉取的方案下,每一个 Tag 页面 都会加载包含所有文章信息的 _payload.json,造成数据冗余。很多 Tag 页面仅需一两篇文章的数据,却被迫加载了全部文章信息,严重影响了性能。

tags 目录占据了 2.9MiB,是所有目录中最大的

_payload.json

讨巧方案:利用 SQLite 的存储特性进行优化

为了减少 useAsyncData 返回的查询结果,我查阅了 Nuxt Content 的 GitHub Discussions,发现在 v3.alpha.8 版本时就有人提出了一种“巧妙”的解决方案

由于 Nuxt Content v3 使用 SQLite 数据库,原本在 Front Matter 中定义的 tags 数组(通过 z.array() 定义)最终会以 JSON 字符串的形式存储在数据库中(具体格式可在 .nuxt/content/sql_dump.txt 文件中查看)。

sql_dump.txt

这意味着我们可以利用 SQLite 的字符串操作特性,通过 LIKE 动词配合通配符来完成数组包含的筛选,本质上是查询 JSON 字符串是否包含特定子串:

const tag = decodeURIComponent(route.params.tag as string)

const { data } = await useAsyncData(`tag-${route.params.tag}`, () =>
    queryCollection('posts')
        .where('tags', 'LIKE', `%"${tag}"%`)
        .order('date', 'DESC')
        .select('title', 'date', 'path', 'tags')
        .all()
)

下面是优化后重新生成的文件占用,体积减小还是非常显著的

  • tags 目录体积: 2.9MiB -> 1.4MiB
  • 单个 _payload.json 的体积: 23.1KiB -> 1.01 KiB

通过这种方法,我们成功将查询逻辑下推到了数据库层,避免了不必要的全量数据传输,显著降低了单个目录中 _payload.json 的体积,实现了性能优化。

tags 目录体积下降

_payload.json

参见

queryCollection - Nuxt Content

How do you query z.array() fields (e.g. tags) in the latest nuxt-content module (v3.alpha.8) · nuxt/content · Discussion #2955

🔲 ☆

草梅 Auth 与 AI 开发心得 | 2025 年第 27 周草梅周报

本文在 草梅友仁的博客 发布和更新,并在多个平台同步发布。如有更新,以博客上的版本为准。您也可以通过文末的 原文链接 查看最新版本。

前言

欢迎来到草梅周报!这是一个由草梅友仁基于 AI 整理的周报,旨在为您提供最新的博客更新、GitHub 动态、个人动态和其他周刊文章推荐等内容。


最近通过 AI 快速开发了一个项目——草梅 Auth

你也可以直接访问官网地址:https://auth.cmyr.dev/

image-20250706205136962

image-20250706205222749

项目还在开发中,在这里我想提一些我的开发心得。

相较于上次 afdian-linker 项目的开发,这次在开发流程上做了一些改进。

首先是,在正式开发之前,引入了原型图的开发。

详见《豆包 AI 编程 | 2025 年第 26 周草梅周报》

我个人的话是使用 豆包 AI 编程 来开发原型图,你也可以使用 ChatGPT、Cemini 等进行开发。

总之,开发原型图中最关键的一件事情就是快速确定产品大致的 UI,从而快速确定这个产品是否有潜力。

现在的用户对于 UI 的要求可不低,如果连界面都无法吸引人的话,恐怕用户连点进来的欲望都没有。

也就是说,先开发 UI 原型图,然后明确大致的 UI 交互,最后再去开发实际的功能(包括前端逻辑和后端接口)。

原型图先行的一个最大好处就是可以先把原型图给用户看,如果用户满意,就继续开发;如果用户不满意,就继续修改。

当然了,在原型图开发完成后,在项目的具体实现中,依旧是要用到一定的编程和软件工程相关的知识,并不能完全依靠 AI。

有关如何使用 AI 开发编程项目的方法,可以参考《普通人的 AI 自编程入门 | 2025 年第 3 周草梅周报》《方糖 AI 自编程入门》

最新 GitHub 仓库

  • caomei-auth - 2025-06-30 15:27:54
    草梅 Auth 是一个基于 Nuxt 全栈框架的统一登录平台。支持 OAuth2.0 协议,集成邮箱、用户名、手机号、验证码、社交媒体等多种登录注册方式。

最新 GitHub 加星仓库

  • CaoMeiYouRen starred ZSim - 2025-07-04 10:41:10
    绝区零模拟仿真程序采用 Python 语言开发,支持定制化手法进行伤害计算。该项目在 GitHub 上获得 509 个星标。
  • CaoMeiYouRen starred playwright-mcp - 2025-06-30 14:58:53
    Playwright MCP 服务器是一个基于 TypeScript 的项目,在 GitHub 上获得了 14017 个星标。
  • CaoMeiYouRen starred claude-task-master - 2025-06-30 14:51:01
    AI 驱动的任务管理系统,兼容 Cursor 等多款开发工具,基于 JavaScript 开发,已获 17676 星标。
  • CaoMeiYouRen starred context7 - 2025-06-30 14:48:56
    Context7 MCP Server 是一个为 LLM 和 AI 代码编辑器提供最新代码文档的项目,主要使用 JavaScript 语言开发,目前在 GitHub 上获得 18,016 个星标。

其他博客或周刊推荐

阮一峰的网络日志

HelloGitHub 热点速览

阿猫的博客

潮流周刊

总结

本周的更新和动态如上所示。感谢您的阅读!
您可以通过以下方式订阅草梅周报的更新:

往期回顾

本文作者:草梅友仁
本文地址: https://blog.cmyr.ltd/archives/2025-27-caomei-weekly-ai-development.html
版权声明:本文采用 CC BY-NC-SA 4.0 协议 进行分发,转载请注明出处!

🔲 ⭐

afdian-linker 技术选型与 Vercel 部署指南 | 2025 年第 21 周草梅周报

本文在 草梅友仁的博客 发布和更新,并在多个平台同步发布。如有更新,以博客上的版本为准。您也可以通过文末的 原文链接 查看最新版本。

前言

欢迎来到草梅周报!这是一个由草梅友仁基于 AI 整理的周报,旨在为您提供最新的博客更新、GitHub 动态、个人动态和其他周刊文章推荐等内容。


技术分享

afdian-linker 的开发工作已经告一段落,之前也分享了一些开发心得(详见:afdian-linker 正式发布 | 2025 年第 18 周草梅周报),因此现在来简单的做一下技术选型上的分享。

框架选型

从立项开始,afdian-linker 就确定了要能够在 Vercel 等云服务平台上部署的要求,因此在框架选型上,优先考虑可以部署在 Vercel 上的框架。

Vercel 为例, Vercel 平台支持的框架包括 Next.js、SvelteKit、Nuxt、Astro、Remix、Vite 等,基本上主流的 CSR 和 SSR 框架都能够支持。

其中又以 Vercel 官方出品的Next.js支持性最佳,支持 Vercel 平台全部的特性和功能。

image-20250525172423998

这也是为什么目前主流的无服务器部署方案都推荐使用 Next.js 开发,因为通过 Vercel 部署实在太方便了。

不过 Next.js 是基于 React 开发的,对 React 生态更加友好。

出于技术选型的偏好,个人还是选择了 Vue 生态下的 Nuxt 框架,对标 Next.js,该有的功能也基本上都有。

无论是 Next.js、Nuxt,还是其他框架,在开发上都是大同小异的,没有本质区别,选择自己喜欢的框架开发即可。

Next.js 和 Nuxt 框架都是全栈框架,即在一个项目中同时编写前端和后端代码,集成了网页开发和接口开发,对于中小型项目,可以极大的省去前后端联调的时间,也可以增加代码的复用,节约开发和部署的时间。

数据库选型

在选择完开发框架后,就要选择数据库了。

在 afdian-linker 中,是要记录用户和订单等数据的,所以需要一个数据库来存储这些数据。

由于前面已经选择了在 Vercel 部署项目,因此这里也选择 Vercel 提供的 PostgreSQL 数据库。

image-20250525175409011

注意:Vercel 平台的 PostgreSQL 数据库是由合作的第三方提供的,例如 Neon 和 Supabase 都提供了 PostgreSQL 数据库,详见 Neon plansSupabase pricing,分别有 500MB 和 256MB 大小。

当然,这里也稍微提一下其他类型的数据库。

由于本项目是要部署到云服务上的,没有固定的服务器,因此像 SQLite 这样的本地数据库就不再适用。不过如果是单机部署的话,那么也可以考虑使用 SQLite ,以节约数据库的空间。

就个人经验而言,大多数情况下,SQLite 的性能已经足以支撑小型项目的业务了,毕竟很多时候都没那么多的用户。

此外,还可考虑使用 MySQL ,不过相较于 PostgreSQL ,提供免费试用的 MySQL 的云服务商比较少,个人推荐两个: TiDBAiven for MySQL

但这两个服务商还各有各的问题,TiDB 虽然提供 5 个 5 GB 的兼容 MySQL 的分布式数据库集群(参考:Pricing Details),但正如官方所说,TiDB 并不是 MySQL ,也就是身说,不是完全兼容 MySQL 的,可能存在一些细节上的差异。由此带来的问题,需要小心调试。不过优点就是,TiDB 在国内可以直连,使用上还是比较方便的。

而 Aiven 就略显尴尬,Free plans 虽然提供免费的 1GB 的 PostgreSQL 和 MySQL 数据库(近期从 5GB 下调为 1GB 了),不过 Aiven 本身在国内无法直连,仅适合项目部署在境外服务器或云服务商时使用。

在本项目中,由于 Vercel 本身也是在境外的,因此可以使用 Aiven 的数据库

当然了,如果更喜欢 NoSQL 的话,也可以用MongoDB,官方也提供了 512 MB 的试用。

缓存数据库的选型上,毫无疑问的选择 Redis(Vercel 也提供了)。

项目开发

项目开发中的心得已在《afdian-linker 正式发布 | 2025 年第 18 周草梅周报》一文中进行了详细说明,此处不再赘述。

程序员使用 AI 工具写的项目水平,不会超过他自己水平的上限;反之,也不会低于自己水平的下限。

代码库中的代码质量,依旧是由程序员自己的水平决定的。

AI 工具的使用不会超越程序员自身的水平,但能显著提高效率。

开发总结

这次额外提一点,很多人以为在 AI 大模型出来后,就可以实现人人都能开发自己的软件,写自己的项目了。

这句话错也没错。

没错是因为,AI 大模型在客观上讲,将软件开发中存在技术难度的部分——代码编写——的开发难度大大降低了,可以通过自然语言去描述需求和写代码,这确实加快了很多写代码的速度。

不过,说它错,也是因为,一个完整的项目开发流程中,编码只是其中的一小部分,一个环节而已,并不代表全部。

仅以本文在之前描述的两个环节,框架选型和技术选型上,一个从未有过编程和项目部署经验的人,最大可能性是卡在哪一步呢?

答案是:在进入框架选型和技术选型前,就已经找不着方向了,因为真正的新人甚至不知道该从哪里开始。(这也是为什么出现了一些一站式集成开发的 AI 网站,提供从开发到部署的全流程服务)。

可以说,AI 大模型可以加速编程,其实是已经掌握了编程技能的程序员的特权。

此外,想必各位程序员也听说过这样一句话:接手一个老项目,往往重新开发会比接着写更快。

这是为什么呢?因为在项目开发的时候,不同的人往往有不同的思路,而接手别人的代码,就意味着要去理解当初写这段代码的思路,这实际上并不是一件容易的事情。除此之外,还有代码风格、编码习惯等小问题。

在我看来,AI 编程实际上相当于人类去接手 AI 编写的代码。虽然 AI 编写的代码质量不一定低,甚至还比人类高,但,能否让接手的人类可以理解,恐怕还是个问题。

从这个角度看,就可以理解为什么人类总是看不懂 AI 编写的代码了,因为那其实也相当于接手了 AI 开发的“屎山”。

为了避免或减少此类问题,还是需要人工手动审查 AI 编写的代码,及时纠正错误写法,或者要求 AI 重新编写。

项目部署

image-20250525183935662

在 Vercel 上部署项目是非常简单的,如果是自己的仓库的项目,只要直接import即可。

image-20250525184253679

如果是第三方项目,也只要导入对应的仓库地址即可。

此外,afdian-linker 还支持一键部署。

点击下方按钮一键部署到 Vercel。

Deploy with Vercel

image-20250525184215729

创建完项目后,就是修改构建命令和填写环境变量。

image-20250525184519065

一般来说,Vercel 默认的构建命令已经是可以用的了,无需特别修改即可正常运行。

如需修改,可以按实际情况改动。

image-20250525184625876

而环境变量,则按照文档说明填写即可。

修改环境变量之后记得重新部署

到这一步,一切顺利的话,项目已经可以正常运行了,可以尝试通过 Vercel 提供的默认域名进行访问。

以 afdian-linker 为例,可以通过 https://afdian-linker.vercel.app/ 访问(需要科学上网)

绑定域名

你可能会注意到,Vercel 提供的默认域名是无法直接访问的,vercel.app在国内无法直接连接,因此需要一个自己的域名用于直接访问。

此处不会赘述如何购买域名,可以自行在国内国外域名网站中购买(提供一个域名比价网:https://tld-list.com/)。

image-20250525185133924

在 Vercel 的 Domains 中进行配置即可。

修改函数区域

在 Vercel 部署的 Next.js、Nuxt 等全栈项目中,后端接口能力都是由 Vercel 的云函数(Vercel Functions)提供的,因此 Vercel Functions 的访问速度会直接影响用户体验。

image-20250525185600969

在 Vercel 的 Function Region 页面中,修改云函数的部署区域即可。

如果是面向国内用户,则建议部署在距离更近的香港地区。

面向哪个国家和地区的用户就把云函数部署在哪个国家和地区

修改部署区域之后记得重新部署

部署总结

虽然通过 Vercel 部署项目确实挺简单的,不过因为一些客观原因,想要访问 Vercel 却并不容易,这也是 AI 无法解决的问题。

可以说,在一个项目的完整流程中,只有从开发完毕到成功部署,才算真正完成了项目开发。

为什么只说是项目开发呢?因为一个真正的软件项目,只有真的投入使用后,才是一个切实可用的真实项目。

任何未经用户实际检验的项目,都只是开发者的练手项目而已。

如果算上这一步,可见,AI 大模型无法解决的问题会越来越多,这也就是为什么我说“有了 AI 大模型,也不等于人人都能开发自己的软件”,对软件工程还是要有一定的敬畏之心,对项目运营更要有敬畏之心。

以上就是本人对这次 AI 开发开源项目的一次简单的开发心得、技术选型和部署指南分享,如有错漏,欢迎指正。

最新 GitHub 加星仓库

  • CaoMeiYouRen starred cmd-generator - 2025-05-24 01:44:44
    该内容描述了一个通过点击按钮生成 CMD 命令的项目。主要编程语言为 TypeScript,项目在 GitHub 上获得了 27 个星标。
  • CaoMeiYouRen starred FFmpegFreeUI - 2025-05-24 01:44:11
    3FUI 是一款基于 ffmpeg 的 Windows 平台专业交互外壳,主要用于视频转码。该软件的开发动机源于对现有转码工具的不满,开发者希望通过自己的努力提供更好的解决方案。3FUI 使用 Visual Basic .NET 作为主要编程语言,并在 GitHub 上获得了 615 个星标。

其他博客或周刊推荐

阮一峰的网络日志

阿猫的博客

潮流周刊

二丫讲梵的学习周刊

总结

本周的更新和动态如上所示。感谢您的阅读!
您可以通过以下方式订阅草梅周报的更新:

往期回顾

本文作者:草梅友仁
本文地址: https://blog.cmyr.ltd/archives/2025-21-caomei-weekly-afdian-linker-tech-selection-deployment-guide.html
版权声明:本文采用 CC BY-NC-SA 4.0 协议 进行分发,转载请注明出处!

❌