Vue.js 生态实战:从后端联调到区块链数据展示的踩坑记

代码里的小宇宙
2025-12-26 02:11
阅读 209

上周五晚上十点半,我正窝在回龙观出租屋的沙发上,MacBook Pro 的风扇呼呼作响——不是因为跑 Flutter 项目,而是临时被拉去救火一个 Vue.js 前端项目。是的,你没看错,一个曾经写 Android、现在主攻 Flutter 跨平台开发的“前原生选手”,居然在深夜对着 vue-cliaxios 疯狂 debug。这事说来话长。

事情起源于公司新启动的一个“代码人生”系列内部工具项目。产品经理拍脑袋说要搞个可视化平台,把我们团队用 K8s 部署的微服务链路、CI/CD 流水线状态,甚至某个实验性区块链节点的数据都统一展示出来。后端同事甩过来一堆 RESTful API 和 WebSocket 接口文档,然后轻飘飘一句:“前端你们自己搞定吧,反正 Vue 简单。”

简单?我差点把咖啡喷到 MacBook 键盘上。虽然日常用 Flutter 写跨端 UI 已经如鱼得水,但 Vue 这玩意儿……上次碰还是三年前帮朋友改个后台管理系统。不过架不住 deadline 是下周一上线演示,只能硬着头皮上。

为什么是 Vue?别问,问就是历史包袱

我们技术栈其实挺杂:移动端是 Flutter(感谢我力推),后端是 Go + Node.js 混搭,K8s 上跑着十几个微服务。但 Web 端……由于早期几个外包项目用了 Vue 2,后续维护成本太高,干脆就延续下来了。这次新项目虽然想上 React 或 Svelte,但领导一句话:“能跑就行,别折腾。” 得,Vue 3 + Vite 安排。

说实话,作为习惯了 Flutter 的声明式 UI 和热重载体验的人,刚切回 Vue 时有点“水土不服”。但不得不说,Vue 3 的 Composition API + <script setup> 真香!逻辑复用比 Options API 清晰太多,尤其配合 TypeScript,类型安全做得相当到位。

联调后端:那些年踩过的 CORS 坑

第一个拦路虎不是代码,是跨域

后端服务部署在公司内网 K8s 集群,通过 Ingress 暴露 HTTPS 接口。本地开发用 vite dev 起的是 http://localhost:5173,直接调接口?浏览器直接给你红屏:

Access to fetch at 'https://api.ourcompany.com/chain/status' from origin 'http://localhost:5173' has been blocked by CORS policy...

运维小哥一脸无辜:“我们生产环境没问题啊,你本地配个代理不就完了?” 好吧,Vite 的代理配置其实很简洁,在 vite.config.ts 里加几行:

export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'https://api.ourcompany.com',
        changeOrigin: true,
        secure: false, // 忽略 HTTPS 证书校验(内网自签名)
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
})

但问题来了:WebSocket 怎么代理?Vite 默认不支持 WS 代理!翻了半小时文档,发现要用 @vitejs/plugin-legacy?不对,那是兼容旧浏览器的。最后灵机一动——直接在后端 Nginx 层加了个 /ws 路由转发,前端连接 wss://localhost:5173/ws/chain-data,Nginx 再转给真实 WS 服务。土办法,但有效。

吐槽时间:为什么每次联调都要和 CORS 斗智斗勇?就不能默认允许 localhost 吗?(狗头保命)

区块链数据展示:性能优化实战

项目核心功能之一是实时展示某条私有区块链的交易流水。后端每秒推送约 50 条交易记录,前端用 v-for 直接渲染?页面直接卡成 PPT!

Chrome DevTools 的 Performance 面板一看,每帧渲染耗时超过 100ms,FPS 掉到 10 以下。问题出在哪?

  1. 列表无限增长:没做虚拟滚动,DOM 节点越来越多
  2. 响应式数据冗余:每条交易包含大量字段,但 UI 只用 5 个
  3. 频繁触发 reactivity:WebSocket 回调里直接 push 到响应式数组

解决方案三板斧:

1. 虚拟滚动上阵

放弃 v-for,改用 vue-virtual-scroller。安装后只需包一层组件:

<template>
  <RecycleScroller
    class="scroller"
    :items="visibleTransactions"
    :item-size="60"
    key-field="txId"
  >
    <template #default="{ item }">
      <TransactionItem :tx="item" />
    </template>
  </RecycleScroller>
</template>

瞬间 DOM 节点从上千降到 20 个左右,内存占用直降 70%。

2. 数据扁平化 + computed 缓存

原始交易数据结构嵌套很深:

{
  "block": { "height": 12345, "timestamp": "2023-10-01T12:00:00Z" },
  "tx": { "id": "abc", "from": "0x...", "to": "0x...", "amount": "100" },
  "metadata": { /* ... */ }
}

但 UI 只需要 height, timestamp, id, from, to, amount。于是在 setup() 里做一层转换:

const visibleTransactions = computed(() => 
  rawTransactions.value.map(tx => ({
    txId: tx.tx.id,
    height: tx.block.height,
    time: new Date(tx.block.timestamp).toLocaleTimeString(),
    from: tx.tx.from,
    to: tx.tx.to,
    amount: parseFloat(tx.tx.amount)
  }))
)

这样响应式系统只追踪这 6 个字段,避免不必要的依赖收集。

3. 批量更新 + requestAnimationFrame

原本 WebSocket 回调是这样的:

socket.onmessage = (event) => {
  const tx = JSON.parse(event.data)
  transactions.value.push(tx) // 每条都触发更新!
}

改成批量处理:

let buffer: Transaction[] = []
let isScheduled = false

socket.onmessage = (event) => {
  buffer.push(JSON.parse(event.data))
  if (!isScheduled) {
    isScheduled = true
    requestAnimationFrame(() => {
      transactions.value.push(...buffer)
      buffer = []
      isScheduled = false
    })
  }
}

利用 requestAnimationFrame 把多次更新合并到下一帧,减少 reactivity 系统的计算压力。

优化前后对比(实测数据):

指标 优化前 优化后
FPS 8-12 55-60
内存占用 420MB 110MB
首屏加载 2.1s 0.8s

“代码人生”项目里的工程化思考

这个项目虽然小,但让我重新审视了前端工程化的价值。作为一个习惯 Flutter 单一入口、强类型约束的开发者,Vue 生态的灵活性既是优势也是陷阱。

比如状态管理:一开始想上 Pinia,但发现业务逻辑其实很简单——就是几个独立的数据流(区块链交易、K8s Pod 状态、CI/CD 日志)。最后直接用 ref + provide/inject 搞定,避免过度设计。

再比如构建部署:我们用 GitHub Actions 自动 build 并推到 OSS,配合 CDN 刷新。但有一次因为 vite.config.tsbase 路径写错,导致所有静态资源 404。线上事故!后来加了 CI 校验脚本:

# .github/workflows/check-build.yml
- name: Verify dist assets
  run: |
    npm run build
    npx http-server dist -p 8080 &
    sleep 2
    curl -f http://localhost:8080 || exit 1

这种“小而美”的验证,比事后救火强一百倍。

从 Android 到 Flutter 再到 Vue:我的跨端感悟

写这篇文章时,地铁刚好到西二旗站。回想五年前还在为 Android Fragment 生命周期掉头发,现在却在 Vue 里玩虚拟滚动——技术人的“代码人生”,大概就是不断跳出舒适区吧。

Flutter 让我爱上了跨平台的一致性体验,但现实是:Web 依然是不可替代的入口。Vue 3 的生态成熟度、开发体验和性能,完全能满足大多数企业级应用需求。尤其是配合 TypeScript 和 Vite,开发效率不输任何现代框架。

至于区块链?别被 hype 误导。我们用的只是普通数据库+共识算法,前端展示层和其他数据源没本质区别。真正难的是后端如何保证数据一致性——这活儿还是留给 Go 语言和 K8s 吧(笑)。

最后一点真心话

如果你和我一样,是个“被迫”接触新框架的开发者,别焦虑。Vue 的学习曲线其实很平缓,官方文档堪称业界标杆。遇到问题先看 Vue Mastery,再不行就翻源码——尤雨溪写的代码,注释比文档还详细。

对了,那个“代码人生”项目最终顺利上线。产品经理很满意,还说下次要做个 Flutter 版本……我默默打开了 VS Code,开始写 pubspec.yaml

(完)

作者注:本文所有代码均在 macOS Sonoma + Node 18 + Vue 3.3 环境下验证。Windows 用户请自行解决路径分隔符问题(手动狗头)。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝