[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"site":3,"post-yao-bu-yao-wei-xi-lie-dan-du":59,"related-yao-bu-yao-wei-xi-lie-dan-du":82},{"name":4,"url":5,"description":6,"bio":7,"avatar":8,"skills":9,"tools":16,"social":34,"hero":47,"heatmap":52,"icp":55,"police":56,"policeIcon":57,"shortName":58},"时过境迁技术笔记","https:\u002F\u002Fhsgjq.top","一个记录前端与 Node 实践的个人博客，内容围绕 Vue、Nuxt、NestJS 与工程化展开，附源码级的原理笔记。","一名热爱技术的全栈开发者，专注 TypeScript 与 Web 工程化，习惯把踩过的坑和思考记录在这里。","\u002Fuploads\u002Fc485c101-179e-48db-96d1-238693784c38.jpg",[10,11,12,13,14,15],"TypeScript","Vue 3","Nuxt","NestJS","Node.js","工程化",[17,23,28],{"items":18,"title":22},[19,20,21],"Cursor","Git","Chrome DevTools","开发工具",{"items":24,"title":27},[25,26],"Vite","npm","构建工具",{"items":29,"title":33},[30,31,32],"Docker","CI\u002FCD(GitHub Actions)","Vercel","部署运维",[35,39,43],{"href":36,"icon":37,"label":38},"https:\u002F\u002Fgithub.com\u002Fhsgjq","github","GitHub",{"href":40,"icon":41,"label":42},"2971861643@qq.com","mail","邮箱",{"href":44,"icon":45,"label":46},"\u002Frss.xml","rss","RSS",{"lines":48,"subtitle":51},[49,50],"人生若只如初见，","何事秋风悲画扇。","《木兰花·拟古决绝词柬友》",{"enabled":53,"platform":37,"username":54},true,"hsgjq","桂ICP备2024046985号","桂公网安备45011002000103号","\u002Fuploads\u002F72c67ef3-bc86-4b64-b0df-0aba71065050.png","时过境迁",{"slug":60,"title":61,"excerpt":62,"date":63,"updatedAt":64,"tags":65,"content":67,"series":68,"seriesIndex":69,"seriesNav":70,"prev":76,"next":79},"yao-bu-yao-wei-xi-lie-dan-du","要不要为系列单独建一张表","一个字段能解决的事不要建表，除非要排序、要页面、要统计。我把三个判断条件列出来，最后选了建表。","2026-03-28","2026-10-15",[66],"MySQL","需求是\"文章可以属于一个系列，系列页列出它下面的文章\"。第一反应是加个字段：\n\n```prisma\nmodel Article {\n  series String?\n}\n```\n\n一个字符串，最省事。我用了两个月，然后遇到三件事，才决定建表。\n\n一，系列名会打错。\"TypeScript 补课\"和\"TypeScript补 课\"是两个系列，列表里出现重复项，合并要写脚本。\n二，系列页要展示描述、排序、封面。这些没地方放。字段加到文章上会变成\"每篇文章重复存一遍系列描述\"，改一次要更新所有行。\n三，要统计每个系列多少篇。字符串分组能算，但一旦系列本身有属性（比如是否显示），字符串就不够了。\n\n判断标准我总结成一句：这个值除了\"标识归属\"之外，还有没有自己的属性和生命周期。有，就是实体，建表；没有，就是字段。\n\n```prisma\nmodel Series {\n  id       Int       @id @default(autoincrement())\n  slug     String    @unique\n  title    String\n  order    Int       @default(0)\n  articles Article[]\n}\n```\n\n一篇文章一个系列，所以外键放在 Article 上（一对多）。要是将来一篇文章能进多个系列，那才需要中间表。我没提前建中间表——按现在的样子，改的时候多一次迁移，比现在多维护一张空表便宜。\n\n删系列时文章怎么办，是我建表之后才想到的问题。onDelete 我选了 SetNull，文章不跟着消失，只是不再属于任何系列。这个决定应该在建表前问清楚，我补了一次迁移。","MySQL 与 Prisma",8,[71,72],{"slug":60,"title":61,"seriesIndex":69},{"slug":73,"title":74,"seriesIndex":75},"tou-xiang-cong-base64-gai-cheng-wen-jian","头像从 base64 改成文件存储",9,{"slug":77,"title":78},"sou-suo-mian-ban-ctrl-k-he-shu","搜索面板：Ctrl+K 和输入框防抖",{"slug":80,"title":81},"biao-ge-cha-cao-li-de-row-shi","表格插槽里的 row 是宽类型：TS7053",[83,88,98,104,109],{"slug":73,"title":74,"excerpt":84,"date":85,"tags":86},"base64 塞进数据库之后每次查询都拖一大坨。改成存路径、文件进卷，还要处理历史数据怎么迁移。","2026-05-19",[66,87],"Node",{"slug":89,"title":90,"excerpt":91,"date":92,"tags":93},"gang-deng-lu-jiu-guo-qi-yi-ci","一个 401，查出四个前端机制：缓存回放、隐藏页的 rAF、百分比圆角、缓动过冲","响应头里的 token 被 304 原样回放，把刚签发的新 token 顶掉，表现成刚登录就过期。顺带记三个前端细节：隐藏标签页里 rAF 不执行、扁盒子的 50% 圆角是胶囊、缓动曲线的过冲只有 0.0008。","2026-10-13",[94,95,96,97],"CSS","JavaScript","Vue","浏览器",{"slug":99,"title":100,"excerpt":101,"date":102,"tags":103},"dian-xiang-mu-ye-mian-jiu-si-yi","点「项目」页面就死：一次客户端无限重定向","为了保留旧地址大小写加的一条跳转规则，被注册成了客户端路由；路由匹配不区分大小写，于是它自己跳自己。","2026-10-02",[12,97],{"slug":105,"title":106,"excerpt":107,"date":102,"tags":108},"cong-da-bao-shang-chuan-dao-push-ji","从打包上传到 push 即上线：把 CD 接通","私有仓库的镜像包默认也是私有的，健康检查的探测地址在宿主机有 nginx 时会打错地方。两处都是配好之后才验出来的。",[30,15],{"slug":110,"title":111,"excerpt":112,"date":113,"tags":114},"shang-xian-na-tian-yu-ming-zheng-shu","上线那天：域名、证书，和一条我打错的 IP","把 69 打成 96，于是照着\"安全组没放行\"这条错线索查了一整晚。分层排查的前提是先确认敲的是哪扇门。","2026-10-01",[115],"随笔"]