最近,我终于把网站升级了。
按理说,这应该是一件很开心的事。新的页面、新的功能、新的技术,之前想改却一直没有动手的地方,这一次也重新整理了一遍。
可真正到了新旧版本切换的那一刻,心里还是有点舍不得。
这一版旧站,陪我走过了五年多。
五年多的时间,说长不长,说短也不短。它见过我兴致勃勃地熬夜更新,也见过我因为工作和生活忙碌,很久没有打开后台。状态好的时候,我会写文章、改页面、折腾一个新功能;没什么可写的时候,就随手记下一件刚刚发生的小事。
现在回头去翻,那些内容并不都完整,也谈不上多么有价值。有些只是几句话,有些是当时踩过的一个小坑,还有些甚至已经记不清前因后果。
但也正是这些零零碎碎的记录,让我重新看见了过去的自己。
原来那时候会因为网站多了一个功能开心很久;原来曾经为了一张配图、一处样式反复修改;原来工作、旅行、读书、健身,还有一些没来得及说清楚的心情,都悄悄留在了这里。
它表面上是一个网站,实际上更像一本断断续续写了很多年的日记。
欢迎来访 航栈 | 让创造持续发生
旧版



十年,也藏在这个网站里
如果把时间再往前拨一点,这个网站记录的其实也是我近十年的职业成长。
18 岁时,我还在安陆的汽修厂里当学徒,一个月只有 300 元。每天换皮带、提机油、换轮胎,晚上带着满身机油味回到床上,累得很快就能睡着。后来我去了武汉,端过盘子,也进过光电厂。工作不算轻松,未来也看不清楚,但心里一直知道,这不是我想要的生活。
21 岁开淘宝店时,我第一次认真意识到设计的重要性。那时背着家里拿出的户口本,咬牙借了 3 万元去学习 UI 设计。对当时的我来说,这不是一个轻松的决定,却也成了进入互联网行业的敲门砖。
成为 UI 设计师以后,我在做店铺装修时第一次真正接触到代码。敲几行字符,就能让设计稿变成可以点击、可以交互的网页,那种感觉让我非常着迷。于是我开始利用下班时间看教程,从 HTML、CSS、JavaScript 一点点学起,慢慢走进 Web 前端。
自学转行并不顺利。没有科班背景,能力也不足,失业和贷款的压力一度让我喘不过气。但我没有放弃,后来加入一家创业公司,从一开始每天被总监盯着改代码,到最后能够独立负责项目,才算真正完成了从设计师到开发者的转变。
接下来的这些年,我从切页面、写交互,走到 Vue、工程化和前端架构;从只关心浏览器里的页面,走到 PHP、Node.js、接口、MySQL、Redis、Docker 和 Nginx;也从一名前端开发,成长为前端主管、项目负责人,再到今天能够站在全栈工程师的视角,独立完成一个完整项目。
2017 年开始做个人网站时,我其实还在一边工作、一边学习 PHP 和 MySQL。很多刚学会的东西,都会立刻拿到网站上试一遍。网站能登录了、能评论了、能发布文章了、能做网址导航了,我就记下一条升级日志。现在回头看,那些日志不只是产品版本,也是我学习和成长的刻度。
所以这一次网站升级,对我来说也像是一次十年小结。从汽修学徒到自学 Web,再从前端走向全栈,在到如今的AI时代,这条路并不标准,也走过不少弯路。但正因为一步一步都是自己摸索出来的,今天再打开这些旧代码,才会格外舍不得。
那套陪我走过五年多的技术
2019 年重写旧站时,我选择了当时比较熟悉的一套方案:前端使用 Vue 2 和 Webpack 4,后端使用 ThinkPHP 5、PHP 与 MySQL,后台管理则使用 Layui。服务器从 Apache 换成了 Nginx,也开始尝试 Docker。
旧前端并不是现在常见的单页应用,而是一套多页面应用。项目通过 pages.js 为首页、文章列表、文章详情、网址导航、社区、个人中心、升级日志等页面分别配置入口,再由 Vue CLI 和 Webpack 打包成 index.html、index_thread.html、index_archives.html 等多个 HTML 文件。
当时还做了公共代码拆分,把第三方依赖和通用代码抽成 chunk-vendors、chunk-common,对 JavaScript 和 CSS 生成 Gzip 压缩文件,并关闭生产环境 Source Map。页面里面使用了 Vue Router、Vuex、Axios、iView、ECharts、mavon-editor、tui-editor 等很多库。现在再去看依赖列表,会觉得有些庞大,但那些功能确实是一点点加进去的:文章编辑、代码高亮、图表、轮播、图片裁剪、评论、收藏、网址导航......每一个都留下过折腾的痕迹。
旧后端项目是典型的 ThinkPHP 5 MVC 结构。MySQL 负责保存文章、用户、网址导航、社区和升级日志等数据,ThinkPHP 同时承担 API、后台管理和一部分页面模板渲染。Nginx 负责域名与 HTTPS 跳转、静态资源缓存以及 API 反向代理。那时很多东西都需要自己拼起来,但也正是这套架构,让我真正经历了一遍从前端页面、接口、数据库到服务器部署的完整过程。
为了 SEO 做过的一次折中
旧站最特别的一部分,是当时为了解决 SEO 问题做的架构调整。
前后端分离以后,Vue 页面主要依赖浏览器加载 JavaScript,再通过接口获取内容。用户访问没有问题,但搜索引擎抓到的初始 HTML 信息很少,文章标题和描述也不能根据内容及时变化。对于一个依赖文章和网址收录的网站来说,这个问题不能一直放着不管。
当时没有直接换成完整的服务端渲染方案,而是保留 Vue 2 的开发方式,把前端改造成 Webpack 多页面打包。打包后的各个 HTML 文件再放进 ThinkPHP 的视图层,通过 MVC 控制器来渲染。
访问首页、文章详情、导航详情或社区内容时,ThinkPHP 控制器会先根据 URL 参数查询 MySQL,得到当前内容的标题、关键词和摘要,再把 title、keywords、description 注入页面模板;浏览器拿到页面以后,Vue 再启动,其他内容继续通过 API 加载。
简单来说,就是把 SEO 需要的部分留在服务端渲染,把交互和主要业务数据交给前端。它不是最标准的前后端分离,也算不上真正的 Vue SSR,却是当时在现有技术和维护成本之间找到的一个办法。旧站后来能够持续被搜索引擎收录,这套做法也发挥了很大作用。
现在的航栈
这一次升级,不再需要把前端打包文件放进 PHP 的 MVC 控制器里"绕一下"了。
新站前端升级到了 Nuxt 4、Vue 3 和 TypeScript,使用 Vite 完成开发与构建。Nuxt 本身支持服务端渲染,文章、工具、社区等公开页面可以在服务端获取数据并生成 HTML。每个页面的标题、描述、Canonical 地址、Open Graph 信息和 JSON-LD 结构化数据,也可以跟随真实内容一起输出。登录、创作中心和后台等不需要收录的页面,则会明确设置 noindex。
相比以前由 ThinkPHP 控制器手动查询数据、再给模板注入三个 SEO 字段,现在页面内容和 SEO 信息属于同一套渲染流程,结构更清楚,也更容易继续维护。
后端也从 ThinkPHP 5 升级为 NestJS 11 与 Fastify 5,全部使用 TypeScript。数据层仍然是熟悉的 MySQL,但升级到了 MySQL 8,并通过 Prisma 管理数据模型和查询;Redis 继续负责缓存、访问去重等高频数据。接口按照账号、认证、内容、互动、媒体、管理后台等模块重新拆分,并增加了参数校验、Swagger 文档和更完整的权限控制。
整个项目现在使用 pnpm Workspace 和 Turborepo 组织成 Monorepo,前端、后端、数据库模型、共享类型和设计变量都放在同一个工程里。生产环境中,Nginx 仍然守在最前面:/api 请求转发给 NestJS,普通页面转发给 Nuxt SSR 服务,静态资源和上传文件则设置不同的缓存策略。应用可以通过 PM2 或 Docker 运行,MySQL、Redis、Web 和 API 的职责也比以前划分得更清楚。
从 Vue 2、Webpack 4、ThinkPHP 5,到 Nuxt 4、Vue 3、TypeScript、NestJS、Fastify 和 Prisma,这看起来是一长串技术名词。可对我来说,它们不只是版本升级,也记录着这些年我对前端、后端、数据库、工程化和服务器部署理解的变化。
舍不得旧站,并不是因为旧技术有多先进,而是因为它保存了那个阶段认真折腾、不断试错的自己。
那些旧文章、旧照片、升级日志和日常记录,我还是会尽量保留下来。它们也许不会再出现在最显眼的位置,但偶尔翻回去看看,依然会觉得很有意思。
谢谢旧站陪伴我的这五年多,也谢谢每一位曾经读过文章、留下评论,或者只是路过这里的朋友。
网站升级了,我也还在路上。以后会继续写技术,也会继续记录生活,把那些当下看起来普通的瞬间,好好地留在这里。
欢迎来到新的航栈。让创造持续发生,也让每一段值得记住的日子,都有地方停靠。