小程序分包加载踩坑记那些年我遇到的加载失败问题

程序员培聪 移动 阅读 2,569
赞 3 收藏
二维码
手机扫码查看
反馈

我的写法,亲测靠谱

分包加载这个东西,我在实际项目中用了快两年了,说白了就是小程序的懒加载。最开始我也是一脸懵逼,看到复杂的项目结构就头疼,后来慢慢摸索出了几套比较稳定的套路。

小程序分包加载踩坑记那些年我遇到的加载失败问题

先说配置文件吧,这个是基础:

{
  "pages": [
    "pages/index/index",
    "pages/profile/index"
  ],
  "subpackages": [
    {
      "root": "packageA",
      "name": "shop",
      "pages": [
        "pages/list/index",
        "pages/detail/index"
      ],
      "independent": false
    },
    {
      "root": "packageB", 
      "name": "user",
      "pages": [
        "pages/order/index",
        "pages/address/index"
      ]
    }
  ],
  "preloadRule": {
    "pages/index/index": {
      "network": "all",
      "packages": ["shop"]
    }
  }
}

这里面有几个关键点我必须强调一下。root 就是分包的根目录,name 是给分包起个别名,方便 preloadRule 里引用。我当时就被这个 name 给坑过,起名字太随意导致后期维护困难。

preloadRule 预加载规则也得注意,”network”: “all” 表示不管网络状况都预加载,如果用 “wifi” 就只在 WiFi 下预加载。我一般用 all,因为现在流量也不算太贵。

这种错误写法,别再踩坑了

最常见的错误就是路径搞错。我见过好多新手直接这样写:

// 错误写法
wx.navigateTo({
  url: '/packageA/pages/list/index'
})

这是不对的!分包里的页面路径还是相对当前分包的,应该这么写:

// 正确写法
wx.navigateTo({
  url: '/packageA/pages/list/index'
})

但是这里有个坑,如果你在主包跳转到分包,路径确实要写完整的。但如果你已经在某个分包里面跳转到同级分包,就会出问题。我当时为了这个问题调试了一整个下午。

另一个大坑是资源引用。很多人不知道,分包不能引用别的分包的资源,只能引用主包的。比如:

/* 在 packageA 中引用 packageB 的样式 */
@import "../../packageB/styles/common.wxss"; /* 错误 */

/* 应该把公共样式放在主包 */
@import "../styles/common.wxss"; /* 正确 */

还有就是主包大小限制,不能超过 2MB,否则上传不了。我当时做电商项目,把一些不太常用的组件放到了分包里,结果主包还是超了,最后不得不把一些工具类也拆出去。

按业务模块拆分的策略

我的经验是按照业务模块来划分,而不是按照功能类型。比如电商项目,我会这样拆:

  • 主包:首页、登录、公共组件
  • 商品分包:商品列表、详情页、搜索
  • 用户分包:个人中心、订单、地址管理
  • 购物车分包:购物车、结算流程

为什么不按功能类型拆?因为按业务拆,一个分包内的页面关联度高,加载完一个分包后,用户在这个业务模块内跳转就很快了。按功能拆会导致跨包依赖,反而增加加载次数。

独立分包我也用过,就是设置 “independent”: true,这种分包可以单独加载,不依赖主包。但是有个限制,独立分包不能引用主包的资源,也不能跳转到非主包的其他分包页面。我用在一个纯离线的小工具页面上,效果还不错。

性能优化的一些技巧

preloadRule 预加载用好了能明显提升用户体验。我一般是这样配的:

"preloadRule": {
  "pages/index/index": {
    "network": "all",
    "packages": ["shop"]
  },
  "packageA/pages/list/index": {
    "network": "all", 
    "packages": ["user"]
  }
}

用户进入首页的时候,我就把商品相关的分包提前加载了,这样用户点击商品入口就不会卡顿。但预加载也要适度,加载太多会增加初始加载时间。

分包大小控制也是个技术活。我一般控制在 2MB 以内,超过的话就要考虑进一步拆分。计算分包大小的方法是:

# 在微信开发者工具中查看
控制台 -> Network -> 查看各个分包的下载大小

还有一个实用的技巧是分包共享。有些公共的静态资源(比如图片、字体),我都会放在主包里,避免在多个分包中重复打包,节省空间。

实际项目中的坑

最让我头疼的是分包间的通信问题。小程序没有全局状态管理(原生小程序),跨分包的数据传递就成了问题。我当时用了事件系统,但这玩意儿不好调试。

后来改成了本地存储 + 监听的方式,虽然不够优雅,但胜在稳定:

// 分包A设置数据
wx.setStorageSync('shareData', {
  productId: 123,
  productName: '商品名称'
});

// 分包B获取数据  
const shareData = wx.getStorageSync('shareData');
if (shareData) {
  // 使用数据
  this.setData({
    productInfo: shareData
  });
}

分包更新也是一个麻烦事。小程序有分包预下载机制,但如果用户网络不好或者退出了,下次打开可能还是旧版本。我当时遇到过用户反映某个功能异常,查了半天发现分包没更新成功。后来加了版本检测和强制更新逻辑才解决。

还有个隐蔽的坑是插件引用。如果分包里用了第三方插件,需要在 app.json 中声明。我有一次忘记声明,发布后发现分包打不开,查了好久才发现是插件配置问题。

调试分包的小技巧

开发工具的 network 面板很好用,可以清楚地看到哪些分包被加载了,加载时间多少。我经常用来分析用户的使用路径,看看预加载策略是否合理。

还有一个实用的技巧是在页面 onLoad 的时候打印当前分包信息:

onLoad() {
  console.log('当前页面所属分包:', getCurrentPages()[0].route);
  console.log('分包加载情况:', wx.getStorageInfoSync());
}

这样可以直观地看到分包的加载情况,方便调试。

以上是我踩坑后的总结,希望对你有帮助。分包加载说难不难,但细节很多,需要在实际项目中多实践才能掌握。有更好的方案欢迎评论区交流。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论