从零开始构建一个现代化前端项目:一个被裁外包仔的实战复盘
作者:老K,前大厂前端,现深圳南山自由接单人。房租3500,猫粮每月120,靠React和咖啡续命。
开头:凌晨三点的泡面与焦虑
去年十月的一个周五晚上,我坐在南山区白石洲一间不到15平米的出租屋里,面前摆着一碗已经凉透的康师傅红烧牛肉面。窗外是深南大道永不熄灭的霓虹,而我的MacBook屏幕上,是一封HR发来的“优化通知”邮件。
“因组织架构调整……感谢你过去两年的贡献……N+1已打款……”
我盯着那行字看了足足十分钟,脑子里一片空白。那时我才意识到,所谓“大厂光环”,在裁员潮面前,不过是一张薄纸。
更扎心的是,第二天早上老婆(对,我结婚了)醒来第一句问我:“下个月房贷怎么办?”
那一刻,我真的慌了。但慌完之后,只能硬着头皮往下走——于是我注册了几个外包平台,开始接单。第一个客户,是个做区块链钱包的小创业公司,老板姓李,在腾讯大厦楼下约我喝了一杯瑞幸。
他说:“我们要做一个Web3的DApp,前端用React,UI要炫一点,最好下周就能看Demo。”
我差点一口咖啡喷出来——下周? 但想到银行卡余额只剩8000块,我还是点了点头。
于是,这个“从零开始构建一个现代化前端项目”的故事,就这么仓促地开始了。
一、不是所有“从零开始”都叫脚手架
很多人以为“从零开始”就是 npx create-react-app 走起。但现实哪有那么简单?
李老板的需求很模糊:“我们要一个像MetaMask那样的界面,用户能连钱包、查余额、转账,还要能看链上交易记录。”
我问他:“用哪条链?”
他说:“先做以太坊吧,后面可能加Polygon。”
我又问:“要不要支持多链切换?”
他想了想:“当然要啊,不然怎么显得我们专业?”
我内心OS:这哪是做DApp,这是要做Web3版支付宝啊!
但没办法,接了单就得干。我花了整整一个周末,在GitHub上翻了十几个开源钱包项目,最后决定——不直接抄,但借鉴架构。
我最终选择的技术栈如下:
- React 18 + TypeScript(必须的,类型安全能救命)
- Vite(比Webpack快太多,开发体验直接拉满)
- Tailwind CSS(快速出UI,省得写样式到秃头)
- Ethers.js(连接以太坊的标准库)
- Zustand(状态管理,比Redux轻量太多)
- Wagmi(专为Web3设计的React Hooks库,真香)
- ESLint + Prettier + Husky(代码规范不能少,不然review时会被客户骂死)
光是搭环境就折腾了两天。Vite配置别名、Tailwind集成、Wagmi初始化……每一个环节都有坑。比如Wagmi默认用EIP-1193标准,但有些老钱包(比如某些国产钱包)不完全兼容,得手动处理Provider。
这时候我才明白:所谓“现代化前端项目”,不是堆砌最新框架,而是用合适的工具解决实际问题。
二、面试题挑战?不,是生产环境挑战
有趣的是,在开发过程中,我居然遇到了好几个“前端面试题”。
比如,有一次李老板突然问我:“为什么用户连上钱包后,页面刷新就断开了?”
我心想:这不就是经典的“状态持久化”问题吗? 面试官最爱问:“如何在页面刷新后保持登录状态?”
但在Web3场景下,问题更复杂——你不能简单存个token,因为钱包连接依赖于window.ethereum这个注入对象,而它只在钱包扩展存在时才有效。
我的解决方案是:
- 用Zustand存储用户地址和链ID
- 页面加载时,检查是否已有地址
- 如果有,尝试重新激活Wagmi的Connector
- 如果失败(比如用户卸载了钱包),则清空状态
代码大概长这样:
// stores/walletStore.ts
import { create } from 'zustadt';
import { getAccount, switchChain, disconnect } from '@wagmi/core';
export const useWalletStore = create((set) => ({
address: null,
chainId: null,
connect: async () => {
const account = await getAccount();
set({ address: account.address, chainId: account.chainId });
},
reconnect: async () => {
try {
const account = await getAccount();
if (account.address) {
set({ address: account.address, chainId: account.chainId });
}
} catch (e) {
// 钱包未安装或未授权
set({ address: null, chainId: null });
}
}
}));
然后在App.tsx里:
useEffect(() => {
const storedAddress = localStorage.getItem('walletAddress');
if (storedAddress) {
useWalletStore.getState().reconnect();
}
}, []);
你看,面试题从来不是为了刁难你,而是真实世界的问题简化版。只是现实中,你还要处理MetaMask、Coinbase Wallet、Trust Wallet等各种兼容性问题。
有一次测试时,我发现Trust Wallet在移动端Safari里根本打不开dapp——后来才知道它不支持window.ethereum,得用WalletConnect。于是又加了一套连接逻辑。
那一刻我真想对着屏幕喊一句:“求求你们统一标准吧!”
三、区块链不是噱头,是新的交互范式
很多人觉得“区块链+前端”就是贴个标签,但真正做起来才发现,整个交互逻辑都变了。
传统Web应用,数据在服务器;而DApp的数据在链上,前端只是“读取器+触发器”。这意味着:
- 所有操作都是异步且不可逆的(交易一旦发送,无法撤回)
- 用户需要支付Gas费(所以你得实时显示预估费用)
- 网络可能拥堵(交易可能卡几小时)
- 链上数据查询慢(得用The Graph或Alchemy加速)
我在做“交易历史”功能时,最初直接调ethers.js的provider.getHistory(),结果发现一次请求要5秒+。用户肯定骂娘。
后来改用Alchemy的API,配合React Query做缓存,体验才好起来。
更头疼的是错误处理。比如用户余额不足,或者Gas设置太低,ethers.js会抛出各种cryptic error message(比如“insufficient funds for gas * price + value”)。普通用户根本看不懂。
于是我写了一个错误映射表:
const ERROR_MESSAGES = {
'insufficient funds': '余额不足,请检查ETH余额',
'nonce too low': '交易已被替换,请刷新页面',
'gas price too low': 'Gas费用过低,建议提高'
};
前端不再是“展示层”,而是用户与去中心化世界的翻译官。这让我重新思考前端的价值——我们不只是切图仔,更是用户体验的守门人。
四、外包的真相:没有需求文档,只有微信语音
说实话,做外包最痛苦的不是技术,是沟通。
李老板从来不写PRD,所有需求都在微信里说。有一次半夜11点,他发来一段60秒语音:“老K啊,我觉得转账页面那个按钮颜色不够‘科技感’,能不能改成那种蓝紫色渐变?就像币安那样。”
我默默打开Figma,把#3B82F6改成#8B5CF6,心里默念:“我是艺术家,我是用户体验设计师,我不是调色盘……”
还有一次,他说:“能不能加个功能,让用户一键把NFT挂到OpenSea上?”
我:“……OpenSea不开放挂单API。”
他:“那别的平台呢?”
我:“都不开放。”
他:“那你想想办法嘛。”
外包的潜规则:客户永远觉得“技术能搞定一切”,而你得在“做不到”和“收更多钱”之间找平衡。
最后我折中做了个“导出元数据”功能,用户可以把NFT信息下载下来,手动上传。收了他额外3k,勉强回血。
五、转机:从接单到建立自己的产品思维
做到第三周,项目基本成型。李老板很满意,还介绍了一个做DeFi的朋友给我。更重要的是,我自己开始有了想法。
我发现市面上很多Web3前端都做得特别丑,交互反人类。为什么不做一个“前端模板库”,专门给DApp开发者用?
于是我在业余时间,把项目里的通用组件抽离出来:钱包连接按钮、链切换器、交易状态提示、Gas费用估算器……打包成一个npm包,叫web3-ui-kit。
没想到发到GitHub后,居然有人star,还有人提issue。虽然现在只有200+ stars,但至少证明——我不是在重复造轮子,而是在解决真实痛点。
这也让我意识到:外包不是终点,而是跳板。通过接不同项目,我能快速积累垂直领域经验(比如Web3),再把这些经验产品化,形成自己的护城河。
六、写给同样在挣扎的你
如果你也在经历裁员、焦虑、接单维生,我想说几句掏心窝的话:
- 别怕从小项目开始。我第一个外包单才8k,但换来的是Web3实战经验。
- 技术是手段,不是目的。客户不在乎你用React还是Vue,只在乎功能能不能跑。
- 把每次“救火”变成知识沉淀。遇到问题就记下来,写成博客或组件库,长期看是资产。
- 保持输出。哪怕只是朋友圈发一句“今天搞定了Wagmi多链切换”,也是个人品牌的积累。
我现在月收入不稳定,有时2w,有时1w5,但至少不用看老板脸色。上周刚带老婆去吃了顿海底捞——她说:“比你以前加班吃泡面强多了。”
结尾:前端不死,只是进化
从大厂格子间到白石洲出租屋,从CRUD工程师到Web3全栈外包仔,这一路跌跌撞撞,但也看清了很多事。
React会过时吗?可能会。区块链是泡沫吗?也许。但只要用户还需要界面,前端就有存在的价值。
区别在于,以前我们对接产品经理,现在我们对接智能合约;以前我们优化首屏加载,现在我们优化交易确认速度。
技术在变,但解决问题的心没变。
所以,别被“现代化”吓住。所谓现代化项目,不过是用今天的工具,解决今天的问题。
而你我,都在路上。
后记:这篇文章写完那天,我又接到一个新单子——用React做NFT铸造平台,预算3w。我回了个“OK”,然后关掉电脑,牵着狗下楼散步。深圳的晚风有点热,但心里踏实。

评论 0