• 小程序包大小优化(uni-app)


     

    背景

    在开发微信小程序的过程中,随着业务逻辑日渐庞大之后,突显了一些问题。

    首先我们发现在 dev mode 时,本地包大小已经达到了 4m+,这种情况下,已经无法在 dev mode 使用真机调试了。

    其次此时,小程序 build 后也有 1.8M 左右。而且后续还有相当多的业务需求需要开发,包大小肯定会更大。

    这时候就想要优化小程序包大小。下面分享一下我的定位过程和解决思路。尽管我们使用 uni-app 开发,但思路是通用的,希望能给大家一些帮助吧。

    如何减小包大小

    代码分析

    首先分析包大在哪儿了。

    打开本地代码目录查看文件大小。可以发现 common/vendor.js 和 page,components 中 js 占了大部分。

    在 build 编译模式下,代码压缩已经启用了,需要思考别的优化方式。这时候可以使用webpack-bundle-analyzer插件。它可以帮助分析 vendor.js 中都有哪些 js 模块,哪些模块比较大,以便我们进一步优化代码

    通过这个插件,发现了下面两个问题。

    问题一: uni-app 自定义组件模式编译 tree shaking 无效

    如果不是使用 uni-app 开发可以跳过这一段

    通过代码分析发现有些模块应该被 tree shaking 但却被打包进来了。基本确定是 tree shaking 没有生效。

    同样是 webpack4 + babel7。在不使用 uni-app,直接使用 vue-cli create 项目的前提下,tree shaking 是没有问题的。而使用 uni-app 去新建项目,tree shaking 却无效。

    排查 babel 配置时发现是由于 uni-app 在创建项目的时候,设置了 modules: 'commonjs'导致。修改后,demo 的 tree shaking ok。但是回到项目里一编译,又出错了。继续定位发现是 uni-app 自定义组件模式编译问题。目前uni-app已经修复了我提的bug,虽然还未正式发布。

    当然你不使用 uni-app 自定义组件模式编译也可以解决,uni-app 还支持template模板模式,但是会有一些开发差异和性能差距,有兴趣可以看下这篇文章

    问题二:部分库不支持 tree shaking

    有些库(比如 lodash)本身并没有使用 import/export,所以 webpack 并不能对它们 tree shaking。这些库我们可以分情况优化。

    首先可以找下网上是否有库对应的 esm 版本可以替代,如 lodash-es。

    其次可以从代码分析中看出,如果库的每个模块都在不同文件中,入口文件只是一个统一入口,那么我们就可以通过修改写法按需加载,如

    1. import add from "lodash/add";
    2. import Button from 'ant-design-vue/lib/button';
    3. 复制代码

    我们也可以使用babel-plugin-import插件针对那些库统一实现按需加载,它的本质是在编译时统一按配置修改加载路径,不需要自己手动去修改代码。

    最后如果都不行,那要么接受,要么自己重写为社区做贡献~

    规范模块开发

    为了免除无法 tree shaking 的烦恼,我们在开发 npm 模块的时候也需要遵循一定的规范,从而减少模块打包后的大小。

    同时支持 commonjs 和 es module

    我们的模块需要同时支持 commonjs 和 es module。这样才能既满足 commonjs 开发的用户,又支持 tree shaking。

    如何实现呢?如果你的代码是 typescript,以@sentry/browser 为例,可以在编译时编译 cjs 和 esm 两种规范代码,如下

    1. // package.json
    2. "build": "run-s build:dist build:esm build:bundle",
    3. "build:bundle": "rollup --config",
    4. "build:dist": "tsc -p tsconfig.build.json",
    5. "build:esm": "tsc -p tsconfig.esm.json",
    6. 复制代码

    然后在 package.json 中指定两个入口以及无副作用标识

    1. "main": "dist/index.js",
    2. "module": "esm/index.js",
    3. "sideEffects": false,
    4. 复制代码

    这样当 webpack 解析模块(解析规则),就会按需优先解析 esm 目录。并且当识别到无副作用时进行 tree shaking。

    如果你的代码本身就是 es6,你也可以这样

    1. "module": "src/index.js",
    2. 复制代码

    第三方自定义组件

    如果使用了第三方微信自定义组件,由于引用是在 json 文件,所以 webpack 在编译时并不能通过 entry 分析到相关文件,因此不会对其进行编译、压缩等。这时候就需要我们自己处理。而且由于 webpack 不处理,tree shaking 自然也无法支持,因此建议尽量避免这种方式引用组件。

    分包

    小程序分包也是一种常规的优化方案。

    通过分析后,可以将一些较大的页面划分为子包。如果有单页依赖第三方自定义组件,而且第三方组件还挺大,也可以考虑将该页面划分为子包。也因此尽量避免将第三方自定义组件放在 globalStyle,不然没法将它放到子包去。

    大图不要打包

    小程序中的大图,尽量避免打包进来,应该放到 CDN 通过 url 加载。我们的做法是在开发时加载本地图片,在 CI/CD 环节自动化发布图片,并改写地址。

    如何解决真机调试问题

    首先还是查看编译后的文件,发现common/vendor.js巨大,足有 1.5M。其次pagescomponents也有 1.4M,而这其中占了 js 的大小又占了绝大部分。

    为什么 js 文件这么大呢?主要是因为在 dev mode 默认并没有压缩,当然也没有 tree shaking。

    我的选择是修改编译配置,在 dev mode 压缩 js 代码。本地代码减少到了 2M。预览大小则是减少到了 1.4M。参考配置如下:

    1. // vue.config.js
    2. configureWebpack: () => {
    3. if (isDev && isMp) {
    4. return {
    5. optimization: {
    6. minimize: true,
    7. },
    8. }
    9. }
    10. }
    11. 复制代码

    这看上去并不是个好方案,但确实简单有效。也考虑过分包,但分包并不能解决 common/vendor.js 巨大的问题,预览时包还是很大。如果有其它好的办法也欢迎留言~

     

  • 相关阅读:
    【云原生 | 从零开始学Kubernetes】七、资源清单与Namespace
    Android Studio 实现登录注册-源代码 (连接MySql数据库)
    rust语言初识
    数据库查询优化:主从读写分离及常见问题
    小分子PEG CAS:1352814-07-3生物素-PEG6-丙酸叔丁酯
    tiup cluster import
    Quartus 入门
    目标检测算法——YOLOv5/YOLOv7改进之结合CBAM
    计算机网络(一):基础篇
    redis五种数据类型
  • 原文地址:https://blog.csdn.net/std7879/article/details/127823537