◆

Vite 中 Vant2 组件库按需加载自定义 Resolver 实现

2025-03-06 13:120

前言

  • 项目构建工具升级成了 vite,但是出于兼容性要求,使用的 vant 组件库仍旧为 2.x 版本。

  • 基于 vite 构建工具,对 vant 进行按需加载,现在使用最多的就是 unplugin-vue-components 插件, 配置也比较简单,如下

import { VantResolver } from 'unplugin-vue-components/resolvers';
import Components from 'unplugin-vue-components/vite';

Components({
  dts: resolve(root, './types/components.d.ts'),
  resolvers: [VantResolver()],
});

如果没有对打包的文件进行分析,自然就认为 vant 已经按需加载了,事实上,此插件仅对 vant3, vant4 生效, 如果你当前项目使用的是 vant2,打包时仍旧是全量加载。

问题原因

我们看下插件提供的 VantResolver() 源码

import type { ComponentResolver, SideEffectsInfo } from '../../types';
import { isSSR, kebabCase } from '../utils';

const moduleType = isSSR ? 'lib' : 'es';

export interface VantResolverOptions {
  /**
   * import style css or less along with components
   *
   * @default true
   */
  importStyle?: boolean | 'css' | 'less';
}

function getSideEffects(
  dirName: string,
  options: VantResolverOptions,
): SideEffectsInfo | undefined {
  const { importStyle = true } = options;

  if (!importStyle || isSSR) return;

  if (importStyle === 'less') return `vant/${moduleType}/${dirName}/style/less`;

  if (importStyle === 'css') return `vant/${moduleType}/${dirName}/style/index`;

  return `vant/${moduleType}/${dirName}/style/index`;
}

/**
 * Resolver for Vant
 *
 * @link https://github.com/youzan/vant
 */
export function VantResolver(
  options: VantResolverOptions = {},
): ComponentResolver {
  return {
    type: 'component',
    resolve: (name: string) => {
      if (name.startsWith('Van')) {
        const partialName = name.slice(3);
        return {
          name: partialName,
          from: `vant/${moduleType}`,
          sideEffects: getSideEffects(kebabCase(partialName), options),
        };
      }
    },
  };
}

通过上述代码可以发现,如果你使用了一个 vant 组件如 Button, 那么插件会帮你生成如下代码

import { Button } from 'vant/es';
import 'vant/es/button/style/index';

此配置对于 vant3/4 进行按需加载是生效的,但是对于 vant2 不生效,我们看下 vant2 推荐的按需加载方式

  1. 使用 babel-plugin-import 插件,这是基于 webpack 开发的,vite 要使用这个插件需要大量的其他插件支持
  2. 手动按需引入组件
import Button from 'vant/lib/button';
import 'vant/lib/button/style';

我们只要通过 unplugin-vue-components 实现上述解析器即可,代码如下

function kebabCase(str) {
  if (!str) return '';
  str = str.replace(/([A-Z])/g, ' $1').toLowerCase();
  str = str.replace(/[\s_]+/g, '-');
  str = str.replace(/^-+|-+$/g, '');
  str = str.replace(/-+/g, '-');
  return str;
}

Components({
  resolvers: [
    [
      (name: string) => {
        if (name.startsWith('Van')) {
          const partialName = kebabCase(name.slice(3));
          return {
            from: `vant/lib/${partialName}`,
            sideEffects: `vant/lib/${partialName}/style`,
          };
        }
      },
    ],
  ],
  dts: resolve(root, './types/components.d.ts'),
});

可以看出来我们去掉的 name 参数,因为 vant2 实现按需加载的组件不是解构导出。

对于 vant 暴露的方法

上述对组件实现了按需加载,但是当我们使用其中的方法时,如 Toast 组件, 我们同样去使用 antfu 开发的 unplugin-auto-import,实现一个默认导出的 Toast 方法即可

import AutoImport from 'unplugin-auto-import/vite';

AutoImport({
  imports: [
    {
      'vant/lib/toast': [
        ['default', 'Toast'], // 将默认导出重命名为 Toast
      ],
    },
  ],
});

只要使用了插件形式的按需加载,就不要在代码中自己再去引入!否则仍旧会导致全量打包

💬留言板0

还没有留言,来发表第一条吧~

PAGE LOAD / LIVEVite 中 Vant2 组件库按需加载自定义 Resolver 实现加载中