ENGINEERING NOTES · 工程笔记

消费者和商户工作台同包:小程序分包的取舍

一、背景:一个 AppID 里住着两类人

我们的多租户小程序 SaaS,每个商户一个独立品牌、独立 AppID。上一篇讲 ext_json 动态路由让 N 个商户共用一套代码,这篇往里看一层:一个小程序里住着两类用户。

消费者扫码进店、下单支付、领券核销,流量占绝对大头,内部口径九成七以上;商户侧是三个角色——老板看数据改价格,店长管订单管店员,核销员在柜台后扫券码。人不多,页面却重:报表、图表、扫码组件个个吃体积。

最早工作台页面全放主包。去年 12 月一个周四晚上,给工作台加经营日报,图表组件一进来,主包从 1.3M 涨到 1.9M;扫码核销 UI 再塞,开发工具直接报红:主包超 2M,禁止上传。同一晚,合作商户的老板在微信上问:"顾客说打开有点慢,你们是不是偷偷塞东西了?"低端机实测冷启动 3.9 秒——消费者每打开一次,都在替用不到的报表付时间。

拆两个小程序看着最干净,我们否了它。业务约束:模板托管翻倍,每商户两次授权、两份 ext_json、双线提审;订单核销要在同一体系对账,跨 AppID 的 openid 对不上。更关键是心智:老板也是消费者,上线前自己会先下一单;店长核销员本是店里的人,下了班也会买。让同一个人装两个小程序,解释成本比开发成本还高。

于是走另一条路:同一个小程序,分包。一个 AppID、一套模板、一次授权;扫码进店的顾客落在主包,柜台后的店员再走一步进分包。

二、切法:按角色切,不按功能切

定原则是同事一句话拍的板:"页面跟人走,不跟功能走。"按功能切——订单一个分包、商品一个分包——两头都要碰订单,页面归谁?路径全交叉。按角色切就干净:页面是谁的高频路径,就放进谁的包。

主包放公共件、登录与"我的",加消费者高频页:首页、服务详情、下单确认、券包;启动只下主包,消费者的流量不花在工作台上。工作台分包放重货:仪表盘、订单管理、扫码核销、店员与价格管理。

分包多出的代价是进入时一次下载,用预下载抹平:app.json 配 preloadRule,登录后确认是商户侧角色,就在"我的"页预拉工作台分包;wifi 全量预拉,蜂窝网络不拉,不费老板的流量。

三、收敛:三角色的路由守卫

权限收敛三档:老板全权限,店长少改价格一项,核销员只有扫码核销和看当日订单。落到实现是双保险。

前端引导:工作台每个页面的 onLoad 过一道守卫——没角色的送去登录,角色不够的送去引导页,告诉他找谁能开权限。守卫的价值是体验,误入者第一时间得到指引。

服务端兜底:前端校验只是导航。角色声明是登录时服务端签进会话的,工作台每个接口再验一遍——改价格必须是老板,核销必须是三角色之一,验不过一律 403。代码包可解包、请求可伪造,边界永远在服务端(1241 个测试方法里,越权是重点)。

四、体积与启动的账

主包瘦身是一张清单:

  • 图标:本地 PNG 清出主包,统一 iconfont,运营图走 CDN,不留一张超过 10K 的图;
  • 组件:工作台专用的(图表、扫码 UI、表格)下沉分包,共用的(按钮、弹层)留主包;方向单向——分包能引主包,主包引不了分包;
  • 工具函数:报表导出、日期序列化这类重工具挪进分包,主包只留请求封装、埋点、鉴权;
  • 启动逻辑:app.js 只做会话初始化,其余按需加载。

瘦下来的账,启动时长是定性收益:主包从 1.9M 回到 1.3M 出头,低端机冷启动从"先愣一下再出首页"变成"直接出首页";工作台分包 0.7M,预下载后点进去基本无感。九成七的流量,从此不用为 3% 的人买单。

五、脱敏配置示例与守卫伪代码

app.json(占位,非真实):

{
  "pages": ["pages/index/index", "pages/goods/detail", "pages/mine/mine"],
  "subpackages": [
    {
      "root": "packages/workbench",
      "name": "workbench",
      "pages": ["dashboard/index", "orders/index", "verify/scan"]
    }
  ],
  "preloadRule": {
    "pages/mine/mine": { "network": "wifi", "packages": ["workbench"] }
  }
}

工作台守卫(JavaScript,伪代码):

const ROLE = { customer: 0, verifier: 1, manager: 2, boss: 3 };
function guard(minRole) {
  const s = getApp().globalData.session;
  if (!s || !s.roles) {          // 未登录,先送去登录
    wx.reLaunch({ url: '/pages/mine/mine?from=workbench' });
    return false;
  }
  if (s.roles.level < minRole) { // 角色不够,去引导页
    wx.redirectTo({ url: '/packages/workbench/pages/deny/deny' });
    return false;
  }
  return true; // 通过不等于放行,接口侧再验
}
// 页面 onLoad 首行:if (!guard(ROLE.manager)) return;

六、踩坑清单

前两个坑最贵。

坑 1:跨分包跳转的路径。 主包跳工作台,navigateTo 写了相对路径,工具正常,真机直接"页面不存在"——分包页面必须以分包 root 为前缀拼绝对路径。修法:跨分包一律绝对路径,常用路径收进常量文件,code review 就能拦住。

坑 2:分包内的静态资源。 切图随手丢进 packages/workbench/images,首页复用一张,本地正常,真机不显示——分包目录里的资源打进该分包,只有本分包能用,主包引用不到。修法:共享图进主包或 CDN;CI 加条检查,主包代码指向分包目录的引用直接红灯。

其余两个一行带过:

#现象与修法
3tabBar 页放进分包tabBar 页必须在主包;工作台做不成底部 tab,改为主包 tab + 分包二级导航
4preloadRule 不生效network 只认 all/wifi;触发点为进入所配置页面,登录不在这页就永不预下载

七、三句话总结

  1. 一个 AppID 装两类用户,分包按角色切、不按功能切:主包只背消费者高频页,工作台重货下沉,预下载抹平等待;
  2. 三角色权限双保险:前端守卫管引导,服务端校验管边界,缺前者体验差,缺后者不安全;
  3. 跨分包绝对路径、静态资源归属、tabBar 必须在主包,提前写进规范,比出事后排查便宜一个量级。

运营主体:北京位元跃迁科技有限公司。本文同步发布于本号技术专栏,可搬运至 CSDN/掘金。

本文为位元跃迁原创内容,仅代表编辑观点,不构成经营或投资建议;文中涉及的品牌与案例仅作公开信息分析示例。

LET'S TALK

把方法用进你的生意

如果你正在为门店做数字化规划,欢迎和我们聊聊。位元跃迁是微信支付合作伙伴、微信开放平台第三方平台,提供小程序定制、开发咨询与企业数字化服务。

18601279913

业务咨询 · 项目合作 · 代理商合作

了解位元跃迁的服务 →
位元跃迁业务联系微信二维码
微信咨询