欢迎光临
我们一直在努力

AI实战之小程序08-真机适配性能收口后,我这样把Uniapp小程序真正带到可发布状态

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 时,脚本会:

  • 从 .env.local 读取本地 AppID
  • 临时写入 src/manifest.json
  • 构建完成后自动恢复占位源码
  • 这类处理的价值很直接:既保证了真实预览链路,又把公开分支和本地配置边界分开了。

    下面是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 里。

    我为什么现在把这个阶段改成已完成

    之前它一直没勾,核心原因有两个:

  • 构建级证据有了,但发布边界和环境边界还没彻底收干净
  • H5、主题、AppID 注入、性能约束这些点还没统一沉成文档和共享实现
  • 这次复核后,几个关键阻断点已经被消掉了:

    • 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
    赞(0)
    未经允许不得转载:171主机测评 » AI实战之小程序08-真机适配性能收口后,我这样把Uniapp小程序真正带到可发布状态
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址