Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2022-07-18]: Taro微信小程序分包小记 #21

Open
Lemonreds opened this issue Jul 18, 2022 · 0 comments
Open

[2022-07-18]: Taro微信小程序分包小记 #21

Lemonreds opened this issue Jul 18, 2022 · 0 comments

Comments

@Lemonreds
Copy link
Owner

前言

项目使用Taro框架搭建,兼容H5钉钉端以及微信小程序端。代码随着迭代开发,小程序的代码体积逐渐变大,微信为了用户体验方面考虑,对代码包的体积有一定要求,如果过大则不允许上架。微信推荐的是使用分包方案来处理代码包过大的情况,即代码按照页面区分,分为主包和一个或者多个分包,其中总体积不超过20MB,主包的体积不超过2MB,就允许发布。此文记录了分包主要优化的方面以及遇到的问题。

分包配置

首先,需要改动路由配置,项目原有的路由配置文件如下:

  pages: [
    'pages/home/index', // 首页
    'pages/login/index', // 登录页面 用于token过期,重新登录
    'pages/consult/index', // 资讯
    'pages/consult_detail/index', // 资讯详情
    'pages/my-questionnaire/index', // 我的问卷
     // ....其他页面
  ],

我们将Tab下的四个页面放进主包,其他的页面放入分包(也可以使用多个分包,这里只分了一个包),分包后的路由配置:

 pages: [
    'pages/login/index', // 登录页面 用于token过期,重新登录
    'pages/home/index', // 首页
    'pages/my-library/index', // 学习中心
    'pages/study-calendar/index', // 学习日历
    'pages/person/index' // 我的
  ],
  subpackages: [
    {
      root: 'pages/module-common/',
      pages: [
        'consult/index', // 资讯
        'consult_detail/index', // 资讯详情
        'my-questionnaire/index', // 我的问卷
        'my-qa/index', // 我的提问
        // .... 其他页面
      ]
    }
  ],

可以看到,增加了subpackages配置,除了Tab的页面,全部放进来。同时,代码的文件目录也要做出改动
image.png
其中,module-common是我们自己定的分包命名,命名什么都是可以的。文件结构不允许全部放在pages下面,必须按照包名来分,否则微信会报错。

体积压缩

分包配置完成,但是我们还需要对代码体积进行分析,减少打包体积,目标是主包2MB以下。可以通过微信开发者工具,查看代码依赖分析,来看具体占体积较大的模块(注:应使用npm run build:weapp,生产会进行压缩)
image.png
上图是已经优化过后的代码包大小,可以看到,主包是1.87MB,分包是1.30MB,能达到微信的发布要求。接下来介绍下主要的优化工作,我们研究发现,代码包体积大的原因主要有以下几个方面:

静态资源

一般在assets目录下存放前端静态资源,以图片为主,图片是占据代码包大小的最大元凶,一张图片可能有700KB左右,所以我们首先的优化对象就是处理图片,推荐以下处理方法:

  1. 将体积稍大的图片上传到OSS,改成HTTP URL 引用资源,避免打包进来。
  2. 如果没有OSS,可以将图片进行压缩,前提是图片不要失真过度。
第三方库

我们还发现,某个业务页面的体积居然有500KB。要说明的是,我们的业务代码占总体代码是很少一部分的,代码体积的大头还是第三方库的使用。于是,当我们发现这个500KB的页面时,首先想到了这个页面是否引用了某个超大的第三方库,并将这个库的代码全部打进来了。

"crypto-js": "3.1.9-1",

答案是cryto-js这个库,用于加密。当使用最新版本时,会将其他无用的代码也打进来,压缩后的体积有400KB左右(例如,nodejs版的代码也打进来了),解决方案是回退到3.1.9-1的版本,重新打包后,页面从500KB变成50KB,可以接受。
另外,代码中如果使用了moment,建议使用dayjs来替换,dayjs的体积较小,api一致。如果一个项目既用moment,又用dayjs,在我看来是不可接受的。
微信的代码依赖分析图,可能并不是很明确,例如vendor.js文件,无法展示它具体包含了哪些第三库,这个时候可以考虑使用webpack-bundle-analyzer来分析是哪些库占用了较大的体积,这个插件要在配置文件的webpackchain加上。

打包了H5的代码

我们使用的是Taro来实现h5和小程序的多端统一。当然,有些功能是没可能做到一份代码,到处运行的。无法兼容多端的功能,我们会单独开发,h5一套代码,微信小程序一套代码。
例如,我们在h5中,有个pdf文件预览的功能,基于pdf.js。但是,pdf.js在微信小程序的环境是跑不了的,所以我们微信小程序的文件预览的功能是Webview内嵌h5页面。
分析打包时,发现微信小程序居然把pdf.js也打了进来,pdf.js本身就是一个很大的库,打包进无用的代码,是必须要进行优化的。

import { lazy, Suspense } from 'react';

let FileViewer;

if (process.env.TARO_ENV === 'h5') {
  FileViewer = lazy(() => import('./components/FileViewerH5'));
} else {
  FileViewer = lazy(() => import('./components/FileViewerTaro'));
}

const FilePreview = () => {
  return (
    <Suspense fallback={<span />}>
      <FileViewer />
    </Suspense>
  );
};

export default FilePreview;

解决上述问题的方法就是使用代码分割,这里使用的是react的Suspens、lazy以及异步import的方案,识别到伊布import后,webpack会自动帮我们按需加载,就不会将h5的代码打进来了。
还有一个例子是,我们的项目有视频播放的功能,在h5上使用的是video.js,在微信小程序上使用的是video标签,这部分也需要代码分割,按需引入,避免在微信上打包进了video.js。

import { forwardRef, lazy, Suspense } from 'react';

let Video;

if (process.env.TARO_ENV === 'h5') {
  Video = lazy(() => import('./VideoH5'));
} else {
  Video = lazy(() => import('./VideoTaro'));
}

function VideoWrapper(props) {
  return (
    <Suspense fallback={<span />}>
      <Video {...props} />
    </Suspense>
  );
}

export default forwardRef(VideoWrapper);

路由问题

我们进行分包的时候,业务代码基本写完了,页面的路由也都定好了。但是进行分包后,微信小程序和h5的路由都会发生变化,原有路由根本不能使用,例如:

 Taro.navigateTo({ url: `/pages/my-qa/index` });

分包后的路由:

Taro.navigateTo({ url: `/pages/module-common/my-qa/index` });

会发现,分包内的页面,要在路由上加载前缀,这个改动无疑是巨大的。我们不可能把代码里面的每一个url都手动去加上前缀,部分路由url,在后端也有存储,还要去改后端数据库里的url。考虑再三后,我们希望把改动降到最小,不改动原有的 navigateTo中的url,h5的路由保持不变,能接受改动微信小程序的路由。

h5的路由不变

image.pngh5路由保持不变使用的是 config.js中h5的router属性,来配置router的别名。即真实的路由是/pages/module-common/consult/index,但是/pages/consult/index相当于一个别名,也能找到页面。

单独处理小程序的路由

小程序没有像h5,可以配置“别名”,来映射路由。所以,我们期望的效果是在调用 Taro.navigateTo({ url: /pages/my-qa/index }); 时,能自动加上分包前缀,跳转到真正的页面。
Taro.navigateTo({ url: /pages/module-common/my-qa/index });
实现以上效果的做法是,在Taro的实例上定义一个navigateToPage方法,核心就是使用Object.defineProperties方法,所有的navigateTo都替换成navigateToPage方法,navigateToPage方法为跳转的url新增分包的前缀。
实现如下:

import Taro from '@tarojs/taro';

// 主包内的路由
const mainPkgRoutes = [
  'pages/home/index', // 首页
  'pages/login/index', // 登录页面 用于token过期,重新登录
  'pages/my-library/index', // 学习中心
  'pages/study-calendar/index', // 学习日历
  'pages/person/index' // 我的
];

// 分包的路由加上前缀
const beforeRoute = options => {
  if (process.env.TARO_ENV === 'weapp') {
    const { url } = options;
    const isMainPkgRoute = mainPkgRoutes.find(route => url.includes(route));
    if (isMainPkgRoute) {
      return options;
    }
    return {
      ...options,
      url: url.replace('/pages', '/pages/module-common')
    };
  }

  return options;
};


/**
 * @function 自定义navigaTo等路由跳转方法(用于处理微信分包)
 */
const initCustomTaro = () => {
  Object.defineProperties(Taro, {
    navigateToPage: {
      configurable: true,
      enumerable: true,
      get() {
        return options => Taro.navigateTo(beforeRoute(options));
      }
    },
    redirectToPage: {
      configurable: true,
      enumerable: true,
      get() {
        return options => Taro.redirectTo(beforeRoute(options));
      }
    },
    reLaunchPage: {
      configurable: true,
      enumerable: true,
      get() {
        return options => Taro.reLaunch(beforeRoute(options));
      }
    }
  });
};

export default initCustomTaro;

最后,在全局app.ts执行initCustomTaro进行初始化即可。再全局替换navigateTo为navigateToPage即可,就能自动带上分包前缀,避免改错改漏的情况发生。当然,如果在项目开始前,就定好分包策略,路由便不需要进行如此困难的改动了。

总结

本文记录了Taro框架下微信小程序进行分包的一些经验,包括如何进行页面拆分和配置、如何进行体积压缩、以及遇到的路由问题。

体积压缩:

  1. 处理图片,上传到OSS或者进行压缩。
  2. 使用第三方库时,要考虑其体积。如果仅仅是使用部分功能,可以按需加载,或者考虑用其他库来替代。
  3. 避免微信端打入了h5的代码。

路由问题:

  1. 建议在开发前,就定好微信的分包。
  2. 可以在Taro的实例上重新定义个路由跳转方法,用来增加分包前缀。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant