Vue.js 生态系统深度探索与项目实战:从秋招焦虑到区块链项目的落地
大家好,我是小张,目前是某985高校计算机专业的大三狗,坐标北京,每天挤1号线通勤一小时去实习。MacBook Pro 是我的主力开发机(Windows 只在测试兼容性时才会打开),最近一边刷 LeetCode 准备秋招,一边在实习公司搞一个基于 Vue 的区块链前端项目——没错,就是那种“产品经理说要上链,但其实只是加了个水印”的伪区块链(笑)。
今天这篇博客,其实是被逼出来的。上周五晚上十一点半,我正准备关机去吃泡面,leader 突然在钉钉群里@我:“下周要给客户 demo,这个 Vue 3 + Vite + Web3.js 的前端得跑起来,UI 再优化下,别让用户觉得我们在炒冷饭。”
我当时内心 OS:这需求三天前才定下来,现在让我一天半搞定? 但嘴上只能回:“好的,我尽快。”
于是,熬了两个通宵,踩了一堆坑,也顺便把 Vue 生态重新捋了一遍。趁着记忆还热乎,写点东西记录一下,也算是给秋招攒点“项目经验”资源吧——毕竟简历上光写“熟悉 Vue”可没人信,得有能讲清楚的技术细节和选型思考。
为什么又回到 Vue?不是都说 React 更香吗?
先说背景。我们团队技术栈偏传统,后端 Java + MySQL,前端之前用的是 Vue 2 + Element UI。今年年初,公司想搞个“创新项目”,领导拍板要做一个轻量级数字藏品展示平台(其实就是 NFT 展示页,但不能叫 NFT,懂的都懂),要求支持钱包连接、链上数据读取、动态渲染藏品卡片。
一开始,我和另一个实习生极力推荐上 React + Next.js,理由很充分:
- 社区 Web3 工具(如 Wagmi、RainbowKit)对 React 支持更好
- SSR 对 SEO 友好(虽然这项目根本不需要 SEO)
- 我们俩 React 更熟
结果被 leader 一句话打回:“团队里没人会 React,你俩走了谁维护?”
行吧,现实就是这么骨感。为了项目可持续性和团队协作成本,最终还是决定用 Vue 3 + Vite + Pinia + Vue Router 4 这套组合拳。顺便把老项目也一起升级了。
📌 求职 tip:秋招面试官特别爱问“你们为什么选 A 而不选 B”。别只会说“因为流行”,要能说出团队规模、维护成本、学习曲线、社区生态这些实际因素。我上次面试字节,就被问到“Vue 和 React 在大型项目中的状态管理差异”,当场感谢这次踩坑经历。
技术选型对比:Vue 2 vs Vue 3 vs Nuxt vs Svelte(是的,我也试过)
为了说服自己“Vue 3 其实也不赖”,我花了一天时间做了个横向对比,主要围绕几个维度:开发体验、性能、Web3 集成难度、构建速度、团队上手成本。
| 技术栈 | 开发体验 | 构建速度 (Vite) | Web3 集成 | 团队学习成本 | 是否适合本项目 |
|---|---|---|---|---|---|
| Vue 2 + Webpack | ⭐⭐ | 慢(冷启动 15s+) | 需手动封装 | 低(现有代码) | ❌(已淘汰) |
| Vue 3 + Vite | ⭐⭐⭐⭐ | 快(<1s HMR) | 中等(需适配) | 中 | ✅ |
| Nuxt 3 | ⭐⭐⭐⭐ | 快 | 好(模块化) | 高 | ⚠️(过度设计) |
| SvelteKit | ⭐⭐⭐⭐⭐ | 极快 | 差(生态弱) | 极高 | ❌ |
结论很清晰:Vue 3 + Vite 是最平衡的选择。既享受了 Composition API 的逻辑复用优势,又能用 Vite 的闪电速度提升开发效率。至于 Web3 集成?大不了自己封装一层 hooks(哦不,是 composables)。
实战:如何优雅地集成 Web3 到 Vue 3 项目
我们的核心需求就三个:
- 用户连接 MetaMask 钱包
- 读取指定合约的 NFT 列表
- 动态渲染藏品图片 + 元数据
第一步:初始化项目
npm create vue@3
# 选择 TypeScript, Pinia, Vue Router, ESLint, Prettier
cd my-blockchain-dapp
npm install ethers viem @wagmi/core # 先试试 viem,后来发现 ethers 更稳
💡 本来想用 wagmi(React 专用),结果发现它对 Vue 支持几乎为零。最后还是回归
ethers.js+ 自己写 composable。
第二步:封装 useWallet Composable
// composables/useWallet.ts
import { ref } from 'vue'
import { ethers } from 'ethers'
const provider = ref<ethers.providers.Web3Provider | null>(null)
const signer = ref<ethers.Signer | null>(null)
const address = ref<string | null>(null)
export function useWallet() {
const connect = async () => {
if (!(window as any).ethereum) {
alert('请安装 MetaMask!')
return
}
try {
// 请求用户授权
await (window as any).ethereum.request({ method: 'eth_requestAccounts' })
provider.value = new ethers.providers.Web3Provider((window as any). ethereum)
signer.value = provider.value.getSigner()
address.value = await signer.value.getAddress()
} catch (error) {
console.error('连接钱包失败:', error)
// 这里曾因为没 catch 导致页面白屏,线上事故+1 😭
}
}
return { provider, signer, address, connect }
}
这个 composable 被我在多个组件中复用,比如 WalletButton.vue 和 NftGallery.vue。Composition API 真香! 以前在 Vue 2 里用 mixin 写这种逻辑,变量命名冲突到想哭。
第三步:读取 NFT 数据 —— 性能优化是关键
最初的实现很 naive:每次进页面就调用合约方法,结果在 Rinkeby 测试网上加载 10 个 NFT 要 8 秒。用户直接关页面了。
后来做了三件事:
- 缓存元数据:把 IPFS 上的 JSON 缓存到 localStorage(带 TTL)
- 并发请求:用
Promise.allSettled并行 fetch 所有 tokenURI - 骨架屏 + loading:提升感知性能
// composables/useNfts.ts
const nfts = ref<NftItem[]>([])
const loading = ref(true)
const fetchNfts = async (contractAddress: string, tokenIds: number[]) => {
loading.value = true
const contract = new ethers.Contract(contractAddress, ABI, provider.value!)
// 并发获取 tokenURI
const uriPromises = tokenIds.map(id => contract.tokenURI(id))
const uris = await Promise.allSettled(uriPromises)
// 获取元数据(带缓存)
const metadataPromises = uris.map((result, i) => {
if (result.status === 'fulfilled') {
return getCachedMetadata(result.value) // 自定义缓存函数
}
return Promise.resolve(null)
})
const metadatas = await Promise.all(metadataPromises)
nfts.value = metadatas.filter(Boolean).map((meta, i) => ({
id: tokenIds[i],
...meta
}))
loading.value = false
}
🚨 血泪教训:千万别在 for 循环里 await!这是实习生第一天写的代码,被我揪出来当反面教材。
踩坑实录:那些让我想砸 MacBook 的瞬间
坑 1:Vite + ethers 的兼容性问题
Vite 默认用 esbuild,而 ethers.js 里用了 Node.js 的 Buffer 和 process,导致 build 失败:
Uncaught ReferenceError: process is not defined
解决方案:在 vite.config.ts 里加 polyfill:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
define: {
'process.env': {}
},
resolve: {
alias: {
// 解决 Buffer 问题
'./runtimeConfig': './runtimeConfig.browser'
}
}
})
或者更彻底地,改用 ethers@6(beta 版,纯 ESM),但当时不敢上生产。
坑 2:MetaMask 注入的 provider 版本混乱
有些用户用旧版 MetaMask,window.ethereum 的 API 不一致。比如 request 方法在某些版本不存在,得降级用 enable()。
最后写了兼容层:
const getEthereum = () => {
const { ethereum } = window as any
if (!ethereum) return null
// 兼容旧版
if (typeof ethereum.enable === 'function') {
return {
request: async (args: any) => ethereum.enable().then(() => ethereum.request(args))
}
}
return ethereum
}
坑 3:Pinia 状态持久化
用户刷新页面后钱包地址丢失,体验极差。于是引入 pinia-plugin-persistedstate:
// stores/wallet.ts
import { defineStore } from 'pinia'
import { useWallet } from '@/composables/useWallet'
export const useWalletStore = defineStore('wallet', () => {
const { address } = useWallet()
return { address }
}, {
persist: true // 自动存 localStorage
})
但要注意:敏感信息别存! 地址可以,私钥绝对不行。
性能与体验:不止是“能跑就行”
作为前端,我坚信:再酷炫的区块链概念,如果页面卡成 PPT,用户也不会买单。
我们做了几项优化:
- 懒加载图片:用
<img loading="lazy">或vue-lazyload - 虚拟滚动:NFT 列表超过 50 项时启用
vue-virtual-scroll-list - 减少重渲染:用
v-memo(Vue 3.2+)缓存列表项 - PWA 支持:让用户能“安装”这个 DApp 到手机桌面
<template>
<div v-for="nft in nfts" :key="nft.id" v-memo="[nft.id]">
<NftCard :nft="nft" />
</div>
</template>
Lighthouse 评分从 45 提升到 82,虽然离完美还有距离,但至少产品经理不再吐槽“怎么比淘宝慢”。
写在最后:关于求职、资源与技术热情
这个项目上线后,虽然只是内部 demo,但成了我秋招简历上的亮点。上周面试美团,面试官看到“Vue 3 + 区块链前端”直接问了半小时细节,从状态管理聊到 Web3 安全实践。
说实话,Vue 生态这几年进步巨大。Vite 让开发飞起,Pinia 比 Vuex 清爽十倍,Vue 3 的类型推导也足够强。虽然 React 社区更活跃,但在国内,尤其是一些传统企业或创业公司,Vue 依然是主流。
如果你也在准备秋招,我的建议是:
- 别只学框架语法,要理解生态工具链(Vite/Webpack、状态管理、测试)
- 项目要有“故事”:为什么选这个技术?解决了什么痛点?数据指标如何?
- 善用开源资源:GitHub、VueUse、Awesome Vue 都是宝藏
最后,分享一句我工位贴的便签:“代码可以重构,deadline 不能”。
共勉。
(泡面凉了,我去加热了,拜拜👋)

评论 0