用户
 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,登录网站

小程序社区 首页 教程 实战教程 查看内容

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

Rolan 2019-11-28 00:24

在开发微信小程序的过程中,随着业务逻辑日渐庞大之后,突显了一些问题。首先我们发现在 dev mode 时,本地包大小已经达到了 4m+,这种情况下,已经无法在 dev mode 使用真机调试了。其次此时,小程序 build 后也有 ...

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

首先我们发现在 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。

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

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

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

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

规范模块开发

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

同时支持 commonjs 和 es module

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

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

// package.json
"build": "run-s build:dist build:esm build:bundle",
"build:bundle": "rollup --config",
"build:dist": "tsc -p tsconfig.build.json",
"build:esm": "tsc -p tsconfig.esm.json",
复制代码

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

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

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

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

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

第三方自定义组件

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

分包

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

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

大图不要打包

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

如何解决真机调试问题

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

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

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

// vue.config.js
    configureWebpack: () => {
        if (isDev && isMp) {
            return {
                optimization: {
                    minimize: true,
                },
            }
        }
    }
复制代码

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

鲜花
鲜花
鸡蛋
鸡蛋
分享至 : QQ空间
收藏
原作者: 张块块 来自: 掘金