Vue.js 生态系统深度探索与项目实战:从秋招焦虑到区块链项目的落地

梁霞
2025-12-18 05:33
阅读 700

大家好,我是小张,目前是某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 项目

我们的核心需求就三个:

  1. 用户连接 MetaMask 钱包
  2. 读取指定合约的 NFT 列表
  3. 动态渲染藏品图片 + 元数据

第一步:初始化项目

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.vueNftGallery.vueComposition API 真香! 以前在 Vue 2 里用 mixin 写这种逻辑,变量命名冲突到想哭。

第三步:读取 NFT 数据 —— 性能优化是关键

最初的实现很 naive:每次进页面就调用合约方法,结果在 Rinkeby 测试网上加载 10 个 NFT 要 8 秒。用户直接关页面了。

后来做了三件事:

  1. 缓存元数据:把 IPFS 上的 JSON 缓存到 localStorage(带 TTL)
  2. 并发请求:用 Promise.allSettled 并行 fetch 所有 tokenURI
  3. 骨架屏 + 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 的 Bufferprocess,导致 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

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