AI实战之小程序08-真机适配性能收口后,我这样把Uniapp小程序真正带到可发布状态
很多小程序项目做到第 6 个阶段时,看起来已经“挺完整”了:首页、详情、互动、个人中心、社区页都能点,甚至连树洞、举报、消息中心都有了。问题是,真正挡住发布的,往往不是功能数量,而是最后这层兼容与性能收口。
Sourcelin 这轮把 兼容与性能 单独拿出来补一篇,不是为了重复讲页面,而是为了把那些最容易被忽略、但最容易在真机和发布前翻车的点,真正落成可复用的工程做法。
本次阶段推文基于产品文档、仓库现状和本地可提取开发记录生成,未完整依赖远端会话历史。
为什么这个阶段不能只看“能不能跑”
产品文档 5.1 第 7 周对这一阶段的定义很明确:
- 微信小程序真机适配
- H5 适配
- 图片优化
- 缓存和错误态补齐
这说明 兼容与性能 不是“顺手优化一下”,而是发布前的硬门槛。因为你前面 6 个阶段做得再全,只要这里处理得粗,小程序一上真机就可能出现:
- 暗色模式和系统主题不同步
- H5 页面标题、描述、分享信息缺失
- manifest.json 里把真实 AppID 直接暴露进仓库
- 构建能过,但真机登录预览链路不可复用
这次真正落到仓库里的收口点
- 微信 AppID 本地注入脚本:sourcelin-ui/sourcelin-ui-uniapp/build-tools/with-local-wechat-appid.mjs
- 小程序构建脚本:sourcelin-ui/sourcelin-ui-uniapp/package.json
- H5 SEO 工具:sourcelin-ui/sourcelin-ui-uniapp/src/shared/utils/seo.ts
- 体验设置页:sourcelin-ui/sourcelin-ui-uniapp/src/pages-user/settings/settings.vue
- 主题配置:sourcelin-ui/sourcelin-ui-uniapp/src/theme.json
- 全局样式 token:sourcelin-ui/sourcelin-ui-uniapp/src/styles/variables.scss
- 发布口径来源:docs/product/UNIAPP_MINI_PROGRAM_PRODUCT_DESIGN.md、docs/product/UNIAPP_MINI_PROGRAM_DEV_BREAKDOWN.md
换句话说,这一阶段不只是“再调一点样式”,而是把构建、主题、SEO、配置边界和发布说明一起收口。
下面是Uniapp小程序发布前兼容与性能收口的关键流程总览:
#mermaid-svg-ypt51mGdvXMx8T8T{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ypt51mGdvXMx8T8T .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ypt51mGdvXMx8T8T .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ypt51mGdvXMx8T8T .error-icon{fill:#552222;}#mermaid-svg-ypt51mGdvXMx8T8T .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ypt51mGdvXMx8T8T .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ypt51mGdvXMx8T8T .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ypt51mGdvXMx8T8T .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ypt51mGdvXMx8T8T .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ypt51mGdvXMx8T8T .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ypt51mGdvXMx8T8T .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ypt51mGdvXMx8T8T .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ypt51mGdvXMx8T8T .marker.cross{stroke:#333333;}#mermaid-svg-ypt51mGdvXMx8T8T svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ypt51mGdvXMx8T8T p{margin:0;}#mermaid-svg-ypt51mGdvXMx8T8T .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ypt51mGdvXMx8T8T .cluster-label text{fill:#333;}#mermaid-svg-ypt51mGdvXMx8T8T .cluster-label span{color:#333;}#mermaid-svg-ypt51mGdvXMx8T8T .cluster-label span p{background-color:transparent;}#mermaid-svg-ypt51mGdvXMx8T8T .label text,#mermaid-svg-ypt51mGdvXMx8T8T span{fill:#333;color:#333;}#mermaid-svg-ypt51mGdvXMx8T8T .node rect,#mermaid-svg-ypt51mGdvXMx8T8T .node circle,#mermaid-svg-ypt51mGdvXMx8T8T .node ellipse,#mermaid-svg-ypt51mGdvXMx8T8T .node polygon,#mermaid-svg-ypt51mGdvXMx8T8T .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ypt51mGdvXMx8T8T .rough-node .label text,#mermaid-svg-ypt51mGdvXMx8T8T .node .label text,#mermaid-svg-ypt51mGdvXMx8T8T .image-shape .label,#mermaid-svg-ypt51mGdvXMx8T8T .icon-shape .label{text-anchor:middle;}#mermaid-svg-ypt51mGdvXMx8T8T .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ypt51mGdvXMx8T8T .rough-node .label,#mermaid-svg-ypt51mGdvXMx8T8T .node .label,#mermaid-svg-ypt51mGdvXMx8T8T .image-shape .label,#mermaid-svg-ypt51mGdvXMx8T8T .icon-shape .label{text-align:center;}#mermaid-svg-ypt51mGdvXMx8T8T .node.clickable{cursor:pointer;}#mermaid-svg-ypt51mGdvXMx8T8T .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ypt51mGdvXMx8T8T .arrowheadPath{fill:#333333;}#mermaid-svg-ypt51mGdvXMx8T8T .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ypt51mGdvXMx8T8T .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ypt51mGdvXMx8T8T .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ypt51mGdvXMx8T8T .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ypt51mGdvXMx8T8T .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ypt51mGdvXMx8T8T .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ypt51mGdvXMx8T8T .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ypt51mGdvXMx8T8T .cluster text{fill:#333;}#mermaid-svg-ypt51mGdvXMx8T8T .cluster span{color:#333;}#mermaid-svg-ypt51mGdvXMx8T8T div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ypt51mGdvXMx8T8T .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ypt51mGdvXMx8T8T rect.text{fill:none;stroke-width:0;}#mermaid-svg-ypt51mGdvXMx8T8T .icon-shape,#mermaid-svg-ypt51mGdvXMx8T8T .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ypt51mGdvXMx8T8T .icon-shape p,#mermaid-svg-ypt51mGdvXMx8T8T .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ypt51mGdvXMx8T8T .icon-shape .label rect,#mermaid-svg-ypt51mGdvXMx8T8T .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ypt51mGdvXMx8T8T .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ypt51mGdvXMx8T8T .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ypt51mGdvXMx8T8T :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
发布前兼容与性能收口
构建配置收口
主题与体验收口
H5适配收口
文档与发布口径收口
AppID注入脚本with-local-wechat-appid.mjs
小程序构建脚本package.json
体验设置页面settings.vue
主题配置theme.json
全局样式tokenvariables.scss
H5 SEO工具seo.ts
产品设计文档UNIAPP_MINI_PROGRAM_PRODUCT_DESIGN.md
开发拆解文档UNIAPP_MINI_PROGRAM_DEV_BREAKDOWN.md
构建时临时注入AppID
用户可感知的跨端一致性
H5页面SEO与分享信息
发布口径对齐
可发布状态
AppID 不再直接写死到源码里
这是这轮最值得单独拎出来说的一点。
以前很多小程序项目会把真实 appid 直接写进 manifest.json,本地跑起来当然方便,但公开仓库和多人协作都很别扭。Sourcelin 这次改成了“源码只保留占位,构建时临时注入”的方式:
"mp-weixin" : {
"appid" : "__WECHAT_MINI_APP_ID__"
}
配套脚本放在:
const PLACEHOLDER_APP_ID = '__WECHAT_MINI_APP_ID__';
const ENV_KEY = 'VITE_WECHAT_MINI_APP_ID';
执行 dev:mp-weixin 或 build:mp-weixin 时,脚本会:
这类处理的价值很直接:既保证了真实预览链路,又把公开分支和本地配置边界分开了。
下面是AppID注入构建的详细流程图:
#mermaid-svg-TklOAwnGWWI8WYa8{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TklOAwnGWWI8WYa8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TklOAwnGWWI8WYa8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TklOAwnGWWI8WYa8 .error-icon{fill:#552222;}#mermaid-svg-TklOAwnGWWI8WYa8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TklOAwnGWWI8WYa8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TklOAwnGWWI8WYa8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TklOAwnGWWI8WYa8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TklOAwnGWWI8WYa8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TklOAwnGWWI8WYa8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TklOAwnGWWI8WYa8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TklOAwnGWWI8WYa8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TklOAwnGWWI8WYa8 .marker.cross{stroke:#333333;}#mermaid-svg-TklOAwnGWWI8WYa8 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TklOAwnGWWI8WYa8 p{margin:0;}#mermaid-svg-TklOAwnGWWI8WYa8 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-TklOAwnGWWI8WYa8 .cluster-label text{fill:#333;}#mermaid-svg-TklOAwnGWWI8WYa8 .cluster-label span{color:#333;}#mermaid-svg-TklOAwnGWWI8WYa8 .cluster-label span p{background-color:transparent;}#mermaid-svg-TklOAwnGWWI8WYa8 .label text,#mermaid-svg-TklOAwnGWWI8WYa8 span{fill:#333;color:#333;}#mermaid-svg-TklOAwnGWWI8WYa8 .node rect,#mermaid-svg-TklOAwnGWWI8WYa8 .node circle,#mermaid-svg-TklOAwnGWWI8WYa8 .node ellipse,#mermaid-svg-TklOAwnGWWI8WYa8 .node polygon,#mermaid-svg-TklOAwnGWWI8WYa8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TklOAwnGWWI8WYa8 .rough-node .label text,#mermaid-svg-TklOAwnGWWI8WYa8 .node .label text,#mermaid-svg-TklOAwnGWWI8WYa8 .image-shape .label,#mermaid-svg-TklOAwnGWWI8WYa8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-TklOAwnGWWI8WYa8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TklOAwnGWWI8WYa8 .rough-node .label,#mermaid-svg-TklOAwnGWWI8WYa8 .node .label,#mermaid-svg-TklOAwnGWWI8WYa8 .image-shape .label,#mermaid-svg-TklOAwnGWWI8WYa8 .icon-shape .label{text-align:center;}#mermaid-svg-TklOAwnGWWI8WYa8 .node.clickable{cursor:pointer;}#mermaid-svg-TklOAwnGWWI8WYa8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TklOAwnGWWI8WYa8 .arrowheadPath{fill:#333333;}#mermaid-svg-TklOAwnGWWI8WYa8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TklOAwnGWWI8WYa8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TklOAwnGWWI8WYa8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TklOAwnGWWI8WYa8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TklOAwnGWWI8WYa8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TklOAwnGWWI8WYa8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TklOAwnGWWI8WYa8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TklOAwnGWWI8WYa8 .cluster text{fill:#333;}#mermaid-svg-TklOAwnGWWI8WYa8 .cluster span{color:#333;}#mermaid-svg-TklOAwnGWWI8WYa8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TklOAwnGWWI8WYa8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TklOAwnGWWI8WYa8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-TklOAwnGWWI8WYa8 .icon-shape,#mermaid-svg-TklOAwnGWWI8WYa8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TklOAwnGWWI8WYa8 .icon-shape p,#mermaid-svg-TklOAwnGWWI8WYa8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TklOAwnGWWI8WYa8 .icon-shape .label rect,#mermaid-svg-TklOAwnGWWI8WYa8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TklOAwnGWWI8WYa8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TklOAwnGWWI8WYa8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TklOAwnGWWI8WYa8 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
源码状态管理
dev:mp-weixin
build:mp-weixin
开始构建
构建命令类型
开发构建
生产构建
读取.env.local文件
获取VITE_WECHAT_MINI_APP_ID
替换manifest.json中的占位符
源码仓库__WECHAT_MINI_APP_ID__
本地环境真实AppID
临时manifest.json包含真实AppID
执行构建过程
构建完成
恢复占位符__WECHAT_MINI_APP_ID__
构建产物包含真实AppID
公开分支安全无敏感信息泄露
本地预览链路真实可用
可发布的小程序包
协作与版本控制安全
开发者体验良好
H5 适配不是“能打开网页”,而是把页面信息也补齐
如果只说 H5 可访问,其实很空。真正有用的是:H5 页面至少要有正确的标题、描述和关键词,不然搜索、分享和回访体验都很弱。
Sourcelin 这轮把这件事沉成了共享工具:
export function applyH5Seo(payload: H5SeoPayload): void {
// #ifdef H5
document.title = title;
upsertMeta('description', description);
if (keywords) {
upsertMeta('keywords', keywords);
}
// #endif
}
这意味着后面无论是首页、文章详情、搜索页,还是用户主页,都不是各自手写一遍 meta,而是走同一套能力。对发布质量来说,这比“页面能渲染”更重要。
主题模式和体验设置这次也从视觉项变成了发布项
很多团队会把主题模式当成“有空再做”的体验增强,但小程序端一旦已经有 Liquid Glass Mobile 设计语言,这件事就不只是换颜色了,它直接影响:
- 安全区和原生区域是否协调
- 深浅模式下的文本可读性
- 主要触控卡片的层级是否稳定
这轮设置页已经把主题切换、个性化推荐、行为统计和订阅消息授权都放进了真实页面:
function setMode(mode: ThemeMode): void {
themeStore.setMode(mode);
showSuccessToast('外观模式更新成功');
}
这说明 兼容与性能 阶段不再只是“看起来差不多”,而是把用户能感知到的跨端一致性沉到了可维护的页面和 store 里。
我为什么现在把这个阶段改成已完成
之前它一直没勾,核心原因有两个:
这次复核后,几个关键阻断点已经被消掉了:
- manifest.json 已恢复为占位 AppID
- build-tools/with-local-wechat-appid.mjs 已形成稳定注入链路
- package.json 已把小程序构建统一走注入脚本
- H5 SEO 已沉成共享工具
- 体验设置与主题模式已进入真实页面
- 产品文档、开发拆解和发布口径已能对齐到同一结论
所以这次我会把 兼容与性能 从待确认转成已完成,并补上这篇统一长文。
效果图

开发过程提示词(优化版)
请先读取 AGENTS.md、rules/frontend-uniapp.md、rules/testing-and-validation.md,
以及 docs/product/UNIAPP_MINI_PROGRAM_PRODUCT_DESIGN.md 第 5.1 节“兼容与性能”阶段要求。
本次只处理兼容与性能收口,不扩展到新的业务页面开发。
请重点检查并收口:
1. 小程序 AppID 是否仍直接写进源码
2. 微信小程序与 H5 构建脚本是否已经形成统一入口
3. 主题模式、原生区域同步和体验设置是否进入真实页面
4. H5 页面 title/description/keywords 是否沉成共享能力
5. 文档里的发布口径是否与代码现状一致
输出时必须说明:
1. 涉及的配置文件、共享工具和页面
2. 哪些点属于发布边界,不能只靠手工记忆
3. 已执行的验证命令
4. 还剩哪些发布前补录材料
这类任务里 AI 最容易跑偏的点
- 看到功能页很多,就误以为兼容与性能已经自动完成。
- 只讲主题色和样式,不检查 manifest.json、构建脚本和环境注入边界。
- 把 H5 适配理解成“页面能打开”,却不补 SEO 和分享信息。
- 明明只是发布前说明没对齐,却不去修 README 和构建说明,最后文档继续误导人。
项目入口
- 在线演示:https://sourcelin.cn
- Gitee:https://gitee.com/my_lyq/sourcelin-cloud-blog
- GitHub:https://github.com/SourceLin/sourcelin-cloud-blog






