一文轻松搞定方法库的Tree shaking

开端

最近一通疯狂的忙碌,终于将多端api封装完成了,马上就可以跟同事们就行吹水了。然而,意外还是发生了,就在我进行最后一轮的测试的时候,忽然发现包的体积好像是有一丢丢大(其实,对于小程序来说是体积是很大了)。

单个分包/主包大小不能超过 2M

相信有的小伙伴肯定经历过解决超包的问题,那真的是酸爽之极。既然超包问题如此难以解决,那么我们对于加入主包的每一KB都需要慎之又慎,更何况增加如此大的体积。

下面我们就先来看一下问题发生的原因吧。

问题分析

幸运的是,我们采用的是Taro框架,打包的底层实现是基于webpack实现的。这里我们先借助于 webpack-bundle-analyzer 来查看一下现在的依赖包的大小。

Taro中使用 webpack-bundle-analyzer 的配置代码如下:

js 复制代码
    webpackChain (chain) {
        if (process.env.NODE_ENV === 'production') {
            chain
                .plugin('analyzer')
                .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, []);
        }
    }

构建完成之后,这个时候我们就看到了当前包的体积情况了。

通过一番查找,我们对现在的包体积情况得出结论是这样的:

包的总体积:286.41K

方法库的体积:28.8K

仔细看了一下方法库的内容,发现是把方法库整个给打包进来了,没有删除我们没有使用到的方法,也就是我们常说的没有实现按需加载。

为什么会这样呢?

反复查询了webpack官方对 Tree shaking 的描述,最终发现了这样一段有玄机的内容:

tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)

新的 webpack 4 正式版本,扩展了这个检测能力,...,可以安全地删除文件中未使用的部分

原来是这样,我们再回过来梳理一下。

在方法库中,我们通过 export default xxx 将方法库导出了,然后在项目中通过 xxx.xxx 对方法进行了使用。而在方法库中,我们又将所有的方法模块挂载到了 xxx 上。在这一通操作之下,我们就是对代码块进行了使用,这样就无法满足Tree shaking的情况了。

现在问题定位到了,没有按需加载。但是,方法库又该如何实现按需加载呢?

解决方案

我的脑海第一时间跳出的就是 loadsh(我曾经是lodash的重度使用者)。lodash可以进行按需加载,作为同样的方法库,我是否可以借鉴lodash的思路来实现呢?

鉴于网上有很多有关lodash的按需加载的深入详细的说明了,我就不再班门弄斧了。

通过对lodash的按需加载方式的深入研究,我发现了其中的一个核心点:使用lodash-es依赖替换了lodash依赖 ,而 babel-plugin-lodashlodash-webpack-plugin 插件更多的是为webpack的Tree shaking服务,将loadsh的引用改造成可shaking的方式。

ok,按照思路,我们先实现第一步,将方法库打包成es模块的方式。

ES模块化编译

我们开干之前,先来看一下lodash-es的模块情况。

是不是很意外?是不是很惊喜?

通过lodash的源代码我们可以看出来,所谓的es模块不是我们所理解的单纯的将代码以 ES Module 的方式导出,而是将每个方法以 ES Module 的方式导出为一个单独的文件模块。

我们的方法库采用的是rollup.js的方式进行打包的,这里我们将之前的构建方式改造一下:

css 复制代码
    export default {  
        input: {  
            index: 'src/main-a.js',  
            canIUse: 'src/api/base/canIUse',
            ...
        },  
        output: {  
            dir: 'lib',
            format: 'es',
            exports: 'named',
            sourcemap: true,
        },
        ...
    };

下面来看一下我们的构建结果,是不是已经跟lodash-es的一样了呢!

实现按需加载

虽然实现了方法库的ES Module,但是还有一个问题困扰着我们。

大家进行方法库的使用的时候,习惯的是使用 import {xxx} from 'api',而不会大量的进行 import { xxx } from 'api/lib/xxx'

这可如何是好呢?

忽然我脑海灵光一现,我想到了antd进行按需加载的时候配置过的 babel-plugin-import。对啊,我只需要借助于 babel-plugin-import 在编译的时候,将api方法映射到对应的lib文件夹下的方法模块就ok了呀。

具体配置如下:

arduino 复制代码
    [
        'import', 
        {
            "libraryName": "xxx",
            "libraryDirectory": "lib",
            "camel2DashComponentName": false,
        },
        'xxx',
    ],

成果

配置完成了,我们来验证一下吧。

通过查看构建结果我们可以发现,成果大大的有:

包的总体积:259.18K

方法库的体积:1.58K

通过比较,我们初步得出结论,体积我们减少了 27.23k ,主包体积减少了 27.22k。对于小程序来说,这个空间是相当可观的。当然,如果我们在主包中使用更多的方法的话,体积会略有增大,但是肯定远远到不了优化之前的体积。

总结

我们来总结一下如何对方法库进行Tree shaking:

  • 将方法库以 ES Module 的模式进行打包输出

  • 配置 babel-plugin-import 将方法的引入路径映射到lib下

相关推荐
Ciito19 分钟前
vue项目使用eslint+prettier管理项目格式化
前端·javascript·vue.js
fighting ~1 小时前
react17安装html-react-parser运行报错记录
javascript·react.js·html
老码沉思录1 小时前
React Native 全栈开发实战班 - 列表与滚动视图
javascript·react native·react.js
abments1 小时前
JavaScript逆向爬虫教程-------基础篇之常用的编码与加密介绍(python和js实现)
javascript·爬虫·python
老码沉思录1 小时前
React Native 全栈开发实战班 - 状态管理入门(Context API)
javascript·react native·react.js
文军的烹饪实验室2 小时前
ValueError: Circular reference detected
开发语言·前端·javascript
Martin -Tang3 小时前
vite和webpack的区别
前端·webpack·node.js·vite
王解4 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
老码沉思录4 小时前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
我不当帕鲁谁当帕鲁4 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis