vue3-vite-组件动态编译

想做一个vite svg loader插件来着,转了一圈发现已经有现成的了,看了下代码,主要是动态编译组件的技术。

svgicon/index.js

import { compileTemplate } from '@vue/compiler-sfc';
import { readFileSync } from 'fs';
import SVGO from 'svgo';

async function compileSvg(source, id) {
  let { code } = compileTemplate({
    id,
    source,
    transformAssetUrls: false,
  });

  code = code.replace('export function render', 'function render');
  code += `\nexport default { render };`;

  return code;
}

async function optimizeSvg(svgo, content, path) {
  const { data } = await svgo.optimize(content, {
    path,
  });

  return data;
}

export default (options = {}) => {
  const { svgoConfig, defaultExport = 'url' } = options;
  const svgo = new SVGO(svgoConfig);
  const cache = new Map();
  const svgRegex = /\.svg(?:\?(component|url))?$/

  return {
    name: 'vue-svg',
    async transform(source, id, isBuild) {
      const result = id.match(svgRegex);

      if (result) {
        const type = result[1];

        if ((defaultExport === 'url' && typeof type === 'undefined') || type === 'url') {
          return source;
        }

        if ((defaultExport === 'component' && typeof type === 'undefined') || type === 'component') {
          const idWithoutQuery = id.replace('.svg?component', '.svg')
          let result = cache.get(idWithoutQuery);

          if (!result) {
            const code = readFileSync(idWithoutQuery);

            const svg = await optimizeSvg(svgo, code, idWithoutQuery);

            result = await compileSvg(svg, idWithoutQuery);

            if (isBuild) {
              cache.set(idWithoutQuery, result);
            }
          }

          return result;
        }
      }
    }
  }
}

用法:

vite.config.j注册:

const vueSvgPlugin = require('./src/components/SvgIcon/index').default;
plugins: [vue(),
    vueSvgPlugin()]

views使用:

import MyIcon from './assets/icons/svg/user.svg?component';
<MyIcon/>