7小时13分钟,使用 AI 将 Laravel 博客重构为 Go

一个运行了 6 年的 Laravel 博客,在 AI Coding 时代完成了一次完整迁移。

项目地址:https://github.com/HubQin/qinblog-go

在线地址:https://blog.ishare.cool/(现在跑的已经是 Go 版了)


背景

这个博客是 2020 年用 Laravel 6 搭的,功能还算完整:文章、分类标签、嵌套评论、用户认证、GitHub 登录、站内通知、全文搜索、后台管理。

当年和现在的技术栈对比如下:

┌─────────────┬───────────────────┬───────────────────────────┐
│   组件      │   Laravel 版       │     Go 重构版              │
├─────────────┼───────────────────┼───────────────────────────┤
│   语言      │   PHP 7.3         │   Go 1.25                  │
│   框架      │   Laravel 6       │   Gin                      │
│   ORM       │   Eloquent        │   GORM                     │
│   模板      │   Blade           │   html/template            │
│   前端      │   Vue 2 + Mix     │   Vue 3 + Vite             │
│   搜索      │   TNTSearch+jieba │   bleve CJK Analyzer       │
│   后台      │   laravel-admin   │   自建 (is_admin)           │
│   队列      │   Redis Queue     │   goroutine (内嵌)          │
│   调度      │   Supervisor      │   robfig/cron (内嵌)        │
│   部署      │   PHP-FPM 容器    │   单二进制 + Docker         │
│   配置      │   config/site.php │   settings 数据库表         │
└─────────────┴───────────────────┴───────────────────────────┘

为什么选择重构

其实博客一直运行得很好,Laravel 6 稳定跑了 6 年,文章、评论、后台都没出过问题,功能也够用。

但用久了,心里越来越有个感觉:

对于一个个人博客来说,Laravel 还是太重了。

Laravel 是个很优秀的框架,ORM、Service Container、Middleware、Event、Queue、生态那是真的丰富,大项目里这些东西非常值钱。

可博客本身其实就这么几样:展示文章、管理内容、提供搜索、少量后台功能。一个简单的网站,却跑在一整套完整框架上面。

结果就是:启动慢一点,链路长一点;改个代码还得惦记着 PHP 环境、Composer 依赖、Laravel 版本;部署也绕不开 PHP-FPM、Nginx 这些东西。倒也不是 Laravel 有什么问题,只是它解决的问题规模,已经远远超过了博客本身的需求。

为什么选择 Go

原因很直接:轻、快、简单。

Laravel:                      Go:
───────                        ────
Nginx                          Nginx
  ↓                              ↓
PHP-FPM                        Go Binary
  ↓                              ↓
Laravel Framework              Handler
  ↓                              ↓
Container                       ↓
  ↓                            Response
Middleware
  ↓
Controller
  ↓
Response

不需要 PHP-FPM,不需要 Composer,编译成一个二进制就能跑。

AI 降低了重构成本

以前一个 6 年的 Laravel 项目,想迁移到 Go,最麻烦的不是写代码,而是读旧代码、搞懂业务、搬迁功能、验证结果这一整条链路。投入太大了,结论往往就是「不值得折腾」。

这次刚好赶上 Qoder 给了大量免费额度,AI 帮忙分析旧项目、生成迁移代码、补测试、快速迭代。成本一下子降下来了。

所以这次重构,本质上不是因为 Laravel 不能用。而是:当 AI 降低了重构成本,一个更轻、更适合自己的技术方案,值得重新选择。


第一次尝试:一句简单的 Prompt

最开始给 AI 的就一句话:

将这个 Laravel 写的 blog 重构到 Golang,
使用 Gin 框架,golang template 渲染;看前端如何结合 Vue。

这显然不是完整需求——数据库要不要保持?laravel-admin 怎么办?Observer 怎么替代?搜索系统呢?一堆东西没明确。所以没有让 AI 直接动手写。


使用 Spec 模式梳理需求

用的是 Qoder 的 Spec 模式,类似传统需求分析——先让 AI 把 Laravel 源码通读一遍(Model、Controller、Migration、Observer、Blade 模板、Vue 页面),再确认范围。

输出结果如下:

┌──────────────────────────────────────────────────────────────┐
│                    Spec 需求分析输出                            │
├──────────────────────────────────────────────────────────────┤
│  ✅ 保持的功能:文章 CRUD + 多标签 / 多级嵌套评论 + 通知 /       │
│     用户注册登录 + GitHub OAuth / 全文搜索 (中文分词) /          │
│     年月归档 + 分类 + 标签 + 专题 / MySQL 11 张表 零数据迁移 /   │
│     后台管理 (仪表盘 + 9 组 CRUD)                              │
│                                                              │
│  🔄 替换:TNTSearch+jieba → bleve CJK / Redis Queue → goroutine│
│          Supervisor → robfig/cron / config/site.php → settings│
│                                                              │
│  ✂️ 砍掉:laravel-admin RBAC → users.is_admin 单一字段         │
└──────────────────────────────────────────────────────────────┘

至此,核心原则就一条:保持业务一致,不做重新设计——功能一致、表结构不变、行为逐一对等。


Goal 模式开始执行

后端:Gin + GORM    模板:html/template    搜索:bleve
前端:服务端渲染 + Vue3/Vite 组件化          后台:自建替代 laravel-admin

到这里,AI 做的已经不是「帮我写个博客」了,而是「完成一次确定范围的软件迁移」。


迁移过程

整个过程的时间线:

时间线 (7h13min)
═══════════════════════════════════════════════════════════
00:00  骨架搭建    go mod init / 目录 / config / database / models / render
02:00  前台功能    posts / comments / auth / tags / topics / notifications
04:00  后台管理    仪表盘 + 9 组 CRUD + 站点设置
05:30  前端迁移    Blade → Go template / Vue2 → Vue3 / Mix → Vite
06:30  验证        单元测试 + 端到端 (12 张截图)
07:13  完成

以上,主要模块的迁移记录如下。

1. 后端迁移

Laravel 到 Go 的对应关系,基本是一层对一层:

┌───────────────┬──────────────────┬───────────────────────────┐
│    层         │   Laravel        │   Go 重构版                │
├───────────────┼──────────────────┼───────────────────────────┤
│   路由        │   routes/web.php │   internal/router          │
│   控制器      │   Controller     │   internal/handlers/web    │
│   模型        │   Eloquent Model │   internal/models          │
│   数据库      │   Migration      │   GORM AutoMigrate         │
│   业务逻辑    │   Service/Observer│  internal/services         │
│   模板        │   Blade          │   html/template            │
│   中间件      │   Middleware     │   internal/middleware       │
│   验证请求    │   FormRequest    │   handler 内校验            │
│   工具函数    │   helpers.php    │   internal/support          │
└───────────────┴──────────────────┴───────────────────────────┘

数据库结构保持不变,继续用原 MySQL 表——用户、文章、评论全都不用迁移,零数据转换。

2. 前端迁移

Blade                          Go template
══════════════════════════════  ═══════════════════════
@extends('layouts.app')         {{template "layout" .}}
@section('content')             {{block "content" .}}
@include('partials.*')          {{template "partials/*" .}}
@foreach($posts as $p)          {{range .Posts}}

Vue 2: SimpleMDE/multiselect →  Vue 3: EasyMDE/@vueform/multiselect

服务端渲染为主,Vue 组件只做增强。博客这种内容型网站,没必要搞成 SPA。

3. 搜索迁移

原:保存 → PostObserver → TNTSearch(jieba) → MySQL 索引 → 回 DB 查
新:保存 → Service Layer → bleve(CJK) → 索引文件 → 回 DB 查

4. 后台迁移

后台是迁移里工作量最大的一块。原来用的是 laravel-admin,admin_users 表、RBAC、菜单、操作日志一整套,上手确实容易,但个人博客真不需要这些。最后简化为一个 users.is_admin 字段加中间件拦截,9 组 CRUD 手写:文章、评论(批量审核)、分类、标签、专题、栏目、友链、用户、站点设置。


遇到的几个坑

1. bcrypt 密码兼容

报错:所有老用户都登不进去。

原因:Laravel 的 bcrypt 哈希用了 $2y$ 前缀,Go 的 x/crypto/bcrypt 只认 $2a$,就差一个字符。

解决:校验前把 $2y$ 替换为 $2a$ 即可。这个问题不读旧代码根本不会想到,很有意思。

2. Laravel Observer 隐藏逻辑

Laravel 保存一篇文章会悄悄触发一堆东西:

Laravel 隐式 (框架自动触发)            Go 显式 (Service 手动调用)
══════════════════════════════════════ ═══════════════════════════
保存文章 → PostObserver::saved()        保存 → services.Post.Save()
  ├─ tags.post_count += 1                 ├─ db.Save(&post)
  ├─ 更新全文索引                          ├─ UpdateTagCount()
  └─ 清理侧边栏缓存                        ├─ Search.IndexPost()
                                          └─ Sidebar.ClearCache()
删除评论 → CommentObserver::deleted()   删除 → services.Comment.Delete()
  ├─ posts.comment_count -= 1             ├─ db.Delete(&comment)
  └─ 清理通知计数                           └─ UpdateCommentCount()

副作用全藏在框架机制里                   所有副作用显式写在 Service 里

迁移到 Go 后改成 Service 层显式调用,代码多了几行,但逻辑一眼就能看清,以后排查不用再猜了。

AI Coding 中最重要的一点

AI 不是替代开发,分工很明确:人负责定义目标、设计约束、判断取舍、验证结果;AI 负责读旧代码、生成迁移代码、辅助测试。

完整流程:需求定义 → Spec 梳理(AI 读 + 人确认)→ Goal 执行(AI 逐模块生成,循环修正)→ 验证收尾(单测 + 截图 + DEVELOPMENT.md)

全程无人值守:AI 自己跑了一整夜

Spec 定好、Goal 启动之后,我基本上没再管过:

传统重构:  人 ████████████████████████████████ 100%
本次:      人 ███░░░░░░░░░░░░░░░░░░░░░░░░░███ 15%
           AI ████████████████████████████ 85%

中间那些坑——bcrypt 兼容、Observer 隐藏逻辑、路由冲突、模板差异、搜索索引重建——AI 全自己处理了。我做的事情真的只有三件:凌晨 00:06 启动 Goal,中间放心睡了几个小时,早上起来一看:跑起来了。

当然,有个前提:这个博客的业务逻辑比较直接,边界很清晰,1:1 复刻让迁移范围完全确定。如果是多租户、复杂审批流那种系统,人的参与度肯定会高很多,验收也没那么容易。但对这类小项目,人确实可以「放手」。

这大概就是「AI 改变软件工程」最直接的体现:不是省了多少时间,而是人可以完全脱离执行层了。


最终结果

7 小时 13 分钟,一个人 + AI,完成了一次完整迁移。

交付如下:Go 博客完整运行(Gin + GORM / Vue3 + Vite / html/template)、自建后台 9 组 CRUD、bleve CJK 全文搜索、Docker 三阶段部署、单元测试、12 张端到端验证截图、DEVELOPMENT.md 交接文档、bcrypt $2y$ 兼容、内嵌 cron。

成本对比          手工            AI 辅助
═══════════════════════════════════════════
时间              2-4 周          7h13min
理解旧代码        几天             AI 读
写代码            1-2 周           对话式生成
调试              1 周             即时修复
AI 成本           $0              $27.26 (实付 $0)

最后,贴一下本次折腾的成果:https://blog.ishare.cool/,现在跑的已经是 Go 版了。


总结

这次最大的收获不是「AI 帮我写了多少代码」,而是发现:以前很多项目不是做不了,只是不值得投入。

以前: 想重构 → 评估 2-4 周 + 风险 → 不值得,继续跑吧
现在: 想重构 → 评估 7 小时 + $0  → 今晚就干

AI 降的是工程的启动成本。一个拖了 6 年的重构,一个晚上就搞完了。

未来的开发也许不是写更多代码,而是 让更多以前不敢开始的工程重新变得可行。

评论 (1)
Qin
Qin 13小时前

强大

登录 后发表评论