iconify.ts 1.85 KB
import { existsSync, readFileSync } from 'fs';
import { Plugin } from 'vite';
import { IconifyJSON } from '@iconify/iconify';

const Plugin_Name = '@iconify-icon-offline-import';

const baseMsg = (msg: string) => `[${Plugin_Name}] ${msg}`;

export default function IconifyPlugin(): Plugin {
  const virtualModuleId = 'virtual:@iconify/json';

  const cache: Record<string, IconifyJSON> = {};

  return {
    name: 'iconify-json-tree-sharking',
    resolveId(id) {
      if (id.includes(virtualModuleId)) {
        return '\0' + id;
      }
    },
    async load(id) {
      if (id.includes(virtualModuleId)) {
        const iconPaths = id.split(virtualModuleId);
        const iconPath = iconPaths[iconPaths.length - 1];

        if (!iconPath) return 'export default {}';

        const [collectName, iconName] = iconPath.split('/').filter(Boolean);

        const collectPath = require.resolve(`@iconify/json/json/${collectName}.json`);

        if (!existsSync(collectPath)) {
          const msg = baseMsg(`Can't found virtual:@iconify/json/${collectName}/${iconName}.`);
          throw new Error(msg);
        }

        let collect: IconifyJSON;
        if (cache[collectName]) {
          collect = cache[collectName];
        } else {
          const res = readFileSync(collectPath, {
            encoding: 'utf-8',
          });
          collect = JSON.parse(res);
          cache[collectName] = collect;
        }

        if (Object.hasOwn(collect.icons, iconName)) {
          return `export default ${JSON.stringify(
            Object.assign(collect.icons[iconName], {
              width: collect.width,
              height: collect.height,
            }),
            null,
            2
          )}`;
        } else {
          const msg = baseMsg(`Can't found ${iconName} from ${collectName} collect.`);
          throw new Error(msg);
        }
      }
    },
  };
}