按需引入,你真的会用吗?

765 阅读3分钟

序言

Hello,大家好,我是kamesan。

说到减少打包体积,最常听到的说法就是按需引入,也就是下面这种写法

// 以element-plus为例
import { ElButton } from 'element-plus'

通过按需引入,我们可以只打包ElButton相关的js文件,可以极大程度的减少打包文件的体积。

打包分析工具

在这里给大家介绍一个分析打包文件的工具rollup-plugin-visualizer,通过配置该工具可以在根目录生成一个stats.html文件,打开后就能看到项目打包后各个依赖的使用情况,我在这里给出一个最简的配置。

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { visualizer } from 'rollup-plugin-visualizer';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    visualizer({
      gzipSize: true,
    }),
  ],
})

全量引入和按需引入

回归正题,我们看一下全量引入element-plus和按需引入ElButton在打包后差距会有多大。

全量引入 image.png 按需引入

image.png 从直观的视觉对比中,全量引用与按需引入的差异一目了然,这种差异不仅体现在模块覆盖的范围上,更显著地反映在文件体积的占用上。具体而言,全量引用的文件大小膨胀至1.45MB,而按需引入的文件仅占用16.95KB。

按需引入的隐式隐患

这里就引申出了一个问题,只要使用import { xxx } from 'xxx'的写法就一定是按需引入吗?我们来看一个例子。

import { isArray } from 'lodash';
console.log(isArray(['1']))

我们跑一遍build看一下打包的情况

image.png 可以看出整个lodash都被打包进去了,那为什么使用了按需引入的写法却没有达到按需引入的效果呢?我们可以通过查看node_moduleslodash的文件得到答案

image.png

image.png lodash库在使用CommonJS模块系统时,并非通过单独导入和导出isArray方法来构建。相反,它导出的是一个完整的lodash对象。

与之相反的是element-plus,使用了非常规范的importexport,所以我们才可以通过使用按需引入的方式只打包我们所需的部分。

image.png

如何真正的按需引入

以lodash为例,如果想要真正做到按需引入的效果,可以通过下面几种方式实现

1. 只import自己需要的方法

import isArray from 'lodash/isArray';
console.log(isArray(['1']))

打包效果

image.png

2. 使用对应的插件

这边网上的资料比较常见的都是webpack的插件,vite相关的应该也有但是比较少,不太推荐

3.使用依赖的es版本

以lodash为例,官方提供了lodash-es,可以方便的让我们使用按需引入

import { isArray } from 'lodash-es'
console.log(isArray(['1']))

打包效果

image.png

总结

不要觉得使用了ES标准的导入语法就能实现按需引入的效果,通过打包分析才能看出效果,多看官方的文档说明,一般里面都会有提及如何按需引入。

Extra quiz

不知道大家有没有用过highlight.js,大家可以模拟自己使用到这个的场景并进行优化,欢迎在评论区进行分享。