一个非工程师,三周从零做出微信小程序:跨端架构与合规妥协
10 分钟阅读
投资大师之路最初只是一个 H5 网站——用浏览器打开就能玩。但当我想把它推到"日活更高的入口"时,所有路径都指向了**微信小程序**。中国互联网你可以不用任何 App,但很难不用微信。
但小程序不是"H5 套壳"。这一篇是我作为非工程师,三周内把这个项目从 H5 重写到原生微信小程序的完整记录——包括踩到的合规雷、跨端共享数据的架构、以及个人主体的现实约束。
### Step 0:H5 套壳为什么走不通
最朴素的想法是:在小程序里放一个 `<web-view>` 组件加载 master-ai.cn/gam3,一行代码搞定。
走不通。微信对 `<web-view>` 有三层硬限制:
1. **个人主体小程序禁用 `<web-view>`**——这是硬规则,没有任何绕过空间。
2. 业务域名(webview-domain)需要企业认证 + 行业资质,个人申请不下来。
3. 即使企业主体能用,微信运营规范明确禁止"纯 webview 套壳"——审核员发现整个小程序就是一个 webview 加载外部网页,会直接驳回。
> **微信生态对原生小程序的偏好不是建议,是政策**。Skyline 渲染引擎、订阅消息、自定义分享卡、支付能力——这些只对原生开放。webview 永远是二等公民。
所以唯一的路径是:**用小程序原生技术栈(WXML/WXSS/Page)重写整个前端**。
### Step 1:评估真实工作量
我先逐文件统计了 H5 版本的代码体量:
- `runner-v4.js`:2035 行,69 个函数。覆盖剧本状态机、HUD、对话/选项/头条/信息卡/锦囊/交易确认弹窗、Ken Burns 背景、Mini K 线 + 全屏 K 线、章末复盘、净值曲线、html2canvas 分享图。
- `style-v4.css`:1200 行,电影感视觉风格。
- 60 个章节背景图,14 个人物立绘,60+ JSON 文件。
让 LLM 一次性翻译成 WXML/WXSS/Page 是不现实的——细节差异太多。我必须**逐层重写**,并且**砍掉一部分功能换合规性**。
### Step 2:合规边界(可能比技术更重要)
个人主体小程序选了"工具/查询"类目。审核员看一眼小程序里如果有任何"投资建议"嫌疑,就会拒。我把 H5 版的功能矩阵划成两类:
**砍掉**(v1 不上):
- 模拟交易(买/卖按钮、股数输入、盈亏 HUD)
- K 线图(看起来太像股票软件)
- 自由交易窗口 + 自动播放
- 期货章节("棉花""螺纹钢"——期货关键词敏感)
- 任何"建议买入/卖出"措辞
**保留**:
- 剧情对话、选项、头条卡、信息卡
- "大师当时怎么想"——把原来的"💡 大师锦囊"改名,去掉"建议"语义
- 章末复盘(纯文字,不画净值曲线)
定位从"投资互动游戏"调整成"投资史互动阅读器"。**功能砍掉一半,但过审概率从 30% 拉到 95%**。
### Step 3:跨端数据架构(这一步最关键)
最大的工程问题:**怎么让 H5 版和小程序版共用一份内容?**
如果数据打进小程序包,每次加新章节都要重新提交审核(小程序代码版本审核通常 1-3 天)。这显然不可接受——内容产品的核心是"快速迭代剧本"。
最终落地的架构:
```
master-ai.cn/gam3/ ← 静态托管 (HTTPS + ICP 备案)
├── chapters.json ← 章节列表
├── script-*.json ← 各章节剧本
├── prices-*.json ← 历史价格 (合规版不读)
├── headlines-*.json ← 头条卡
├── advices-*.json ← 大师当时怎么想
├── infoCards-*.json ← 信息卡
└── art/ ← 背景 + 人物插画
```
H5 版直接 fetch,小程序版用 `wx.request` 拉。
小程序端的 `utils/api.js` 实现了一个简单的 cache-first 策略:
```js
function fetchJson(path, onUpdate) {
// 1. 缓存有就立即回调一次(用户立即看到内容)
const cached = readCache(path);
if (cached) onUpdate(cached.data, true);
// 2. 同时后台请求最新版(用户网络好就秒级更新)
wx.request({
url: `${BASE_URL}/${path}`,
success: (res) => {
writeCache(path, res.data);
onUpdate(res.data, false);
}
});
}
```
**红利**:以后我改剧本只需要把 JSON push 到 master-ai.cn——H5 版立即生效,小程序版下次启动自动拉到(用户感知是"无缝更新")。**小程序代码本身不需要重新审核**。
这个架构在我反复阅读微信文档后才确认是合规的——只要 `wx.request` 拉的内容本身合规、域名是 ICP 备案的 HTTPS 域名,就没问题。
### Step 4:状态机改造
H5 版的 `runner-v4.js` 是 DOM 操作风格——直接 `document.getElementById`、`innerHTML`、`addEventListener`。小程序是数据驱动 + `setData`,必须改造。
我把核心 2000 行剧本引擎重写成一个**纯函数式状态机**:
```js
class ChapterRunner {
start() { this._step(); }
advance() { /* 推进对话/卡片 */ }
choose(idx) { /* 选了第 idx 个选项 */ }
_step() {
// 不断 _executeNode 直到遇到 wait(对话/选项/卡片)
// 触发 onStateChange 回调
// Page 收到回调用 setData 渲染
}
}
```
精髓是:**runner 不知道 WXML 长啥样,Page 不知道剧本逻辑长啥样**。两者通过 onStateChange 一个回调通信。这套架构 H5 版照样能用——本质上是个跨端的状态机。
代码体量从原来 2035 行的 `runner-v4.js` 缩到 280 行的小程序版(因为砍掉了 K 线、交易、复盘画图等模块)。
### Step 5:剩下的小坑
- **图片 URL**:小程序的 `<image>` 组件可以直接用 https URL,但要在小程序后台"服务器域名"里加 `master-ai.cn` 进 `request 合法域名` 列表。开发版可以勾"不校验合法域名"先调试。
- **textarea 焦点**:小程序的 textarea 在 iOS 上键盘弹起会顶住整个布局,要用 `fixed` + `adjust-position` 处理。
- **wx.setStorageSync 单 key 1MB 上限**:我在 cache 层做了分桶,每个 JSON 文件单独存一个 key。
### 总成本盘点
- 实际投入:每天 2-3 小时 × 18 天 ≈ 50 小时
- 工具:Claude Code 全程协作,几乎每个文件第一版都是它写的,我做架构决策和合规裁剪
- 砍掉的功能:交易模拟、K 线、复盘画图、分享图——大约 40% 的 H5 版功能
- 没砍掉的红利:跨端数据架构(最重要的工程沉淀)
> 做完后我才理解微信生态"原生优先"政策的深意。如果走 webview 套壳,三个月后我还在原地打转——加一个新功能就要重新备案、重新审核、还要应付各种限流。**而走原生 + 数据云端架构,我每天都能上一篇新章节,平台甚至会因为我"内容更新活跃"给更多曝光**。
最后一个意外发现:把这一整套架构迁移过程当作一个产品案例写出来,本身就是一个挺好的内容产品。所以才有了这一篇文章。
