不要再像我这样使用 React 导入了,试试 Wrapper 模式吧!

开发 前端
在本文中,将向你介绍这个问题,以及如何通过 Wrapper(封装)模式 创建一种更灵活的方式,成功解决这一问题的。

在之前的实际项目中发现了一种 React.js 中非常低效的导入策略。在本文中,将向你介绍这个问题,以及如何通过 Wrapper(封装)模式 创建一种更灵活的方式,成功解决这一问题的。

问题所在

在一个项目中,我发现 lodash 和 Framer Motion 这样的库被以下方式导入:

import _ from 'lodash'; // 导入了整个 lodash(71.78KB)
import { motion } from 'framer-motion'; // 导入了整个 framer-motion(111.19KB)
  • 1.
  • 2.

这种方式的问题显而易见:

  • 你直接导入了整个库,导致包的体积激增。
  • 如果你的项目总体积是 1MB,那么仅这两个库就占了约 18%(~180KB)。

🎯 更好的解决方案:直接导入特定方法

要降低包体积,应该具体导入所需方法:

// before:
import _ from 'lodash'; // 71.78KB

// after:
import debounce from 'lodash/debounce'; // 仅 3.41KB
import merge from 'lodash/merge';       // 仅 16KB
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

但,这样就够了吗?

尽管这种导入方式节省了空间,但在实际开发中可能面临以下问题:

  1. 重构成本:如果 lodash 被十几个文件引用,你就需要修改每个文件中的导入语句,这不仅麻烦而且容易出错。
  2. 容易漏掉修改:容易遗漏某些文件,导致代码不一致或产生难以排查的问题。
  3. 合并冲突麻烦:当多个分支都修改了相同的导入方式,合并时可能出现繁琐的冲突。

更灵活的方式:Wrapper 模式(封装模式)

为了解决这些问题,可以使用一个简单的封装文件(Wrapper):

LodashWrapper.tsx:

import debounce from 'lodash/debounce';

const lodashWrapper = {
  debounce,
};

export default lodashWrapper;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

使用时直接导入封装文件:

import lodashWrapper from './lodashWrapper';

const SearchInput = () => {
  const [query, setQuery] = useState('');

  const handleSearch = useCallback(
    lodashWrapper.debounce((searchTerm) => {
      console.log('Searching for:', searchTerm);
    }, 500),
    []
  );

  return <input onChange={(e) => setQuery(e.target.value)} />;
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

⚠️ 注意:Wrapper 本身并不能减少包的体积(需要具体导入才能减少体积),但能提高代码的维护性和灵活性。

可视化结果(使用 vite-bundle-visualizer 生成)

图片图片

优化后的导入方式:

  • 原本大小:71.78KB
  • 优化后:仅导入 debounce 为 3.41KB(gzip 压缩后只有 1.2KB)

🤔 为什么总是建议使用 Wrapper?

使用 Wrapper 的优点显而易见:

  • 开发者更容易管理导入:所有人使用预定义的优化方式导入库。
  • 避免冗余导入:统一管理导入方式,避免重复导入相同内容。
  • 维护简单:如果某个库的导入方式改变,只需要修改封装文件即可。

但也有一些缺点:

  • 增加了抽象层:可能会略微增加代码复杂性。
  • 增加了文件数量:封装多个库可能导致项目中出现大量额外的封装文件。

如何选择合适的库?

在选择第三方库时,也需要注意它们是否支持单独导入:

  • 比如 Recharts,目前不支持单独导入,会导入整个库。
import { BarChart } from 'recharts'; // 导入整个库
  • 1.
  • 而 Nivo 则支持树摇(tree-shake)导入,可以只导入特定图表组件。
import { ResponsiveBar } from '@nivo/bar'; // 只导入特定组件
  • 1.

这种差别,会极大影响应用的性能表现与最终打包体积。

如何快速查看导入大小?

推荐在 VS Code 中使用 Import Cost 插件,可以直观看到每个导入语句带来的体积增加。

优化后的 vite 配置文件

分享我的 vite.config.ts,内置了压缩、手动分块(manual chunk splitting)、路径别名(alias)等优化方式:

// vite.config.ts 示例
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (id.includes('node_modules')) {
            if (id.includes('lodash')) return 'lodash';
            if (id.includes('framer-motion')) return 'framer-motion';
            return 'vendor';
          }
        },
      },
    },
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      components: path.resolve(__dirname, './src/components'),
    },
  },
});
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

总结(Key Takeaways)

  • 不要直接导入整个库,使用具体方法导入减小体积。
  • 使用 Wrapper 封装库,可以提高代码维护性、降低修改成本。
  • 选择支持具体导入(树摇优化)的库,确保应用性能。
  • 使用 VS Code 插件监控导入体积,及时优化。

责任编辑:武晓燕 来源: 大迁世界
相关推荐

2017-12-18 09:56:38

DIY电脑DIY玩家

2024-01-23 13:20:00

分库分表分布式

2023-08-31 09:10:18

JavaScript调试

2022-03-28 08:21:49

适配器模式项目升级接口

2024-12-30 08:22:35

2020-11-10 07:08:08

API程序外接口

2022-02-28 10:30:03

架构代码Native

2020-04-03 14:25:55

diff Meld工具

2024-06-19 10:01:50

2021-03-12 18:25:09

开发前端React

2023-12-12 07:18:47

Linux系统虚拟化

2024-03-11 08:21:49

2022-06-17 11:10:43

PandasPolarsPython

2021-03-05 22:57:25

递归闭包 Python

2023-04-27 13:25:22

索引合并MySQL

2020-12-02 08:31:47

Elasticsear

2018-10-17 11:20:55

SQL数据库程序员

2014-12-09 09:13:46

BaaS云备份备份即服务

2021-07-28 06:51:08

Nacos代理模式

2022-06-05 21:27:40

Reacteffect
点赞
收藏

51CTO技术栈公众号