@vuetter/vite-plugin-vue-svg
Version:
Vite plugin to use svg files as Vue components.
65 lines (62 loc) • 2.27 kB
JavaScript
import { basename } from 'path';
import { readFileSync } from 'fs';
import { compileTemplate } from '@vue/compiler-sfc';
import { optimize } from 'svgo';
const fileRegex = /\.(svg\?inline)$/;
function index (options = {}) {
var _a;
let viteConfig;
const createWrapper = (tagName) => {
var _a, _b;
const attrs = (_b = (_a = options === null || options === void 0 ? void 0 : options.htmlWrapper) === null || _a === void 0 ? void 0 : _a.attrs) !== null && _b !== void 0 ? _b : {};
let stringifiedAttrs = '';
for (const key in attrs) {
stringifiedAttrs += ` ${key}=${attrs[key]}`;
}
return (code) => `<${tagName} ${stringifiedAttrs}>${code}</${tagName}>`;
};
const wrapper = ((_a = options === null || options === void 0 ? void 0 : options.htmlWrapper) === null || _a === void 0 ? void 0 : _a.tagName)
? createWrapper(options.htmlWrapper.tagName)
: (code) => code;
async function compileSvg(source, path) {
let { code } = compileTemplate({
id: path,
filename: basename(path),
transformAssetUrls: false,
source: wrapper(source),
});
code = code.replace('export function render', 'function render');
code += '\nconst VueComponent = { render };';
code += `
VueComponent.name = "icon-${basename(path.replace('.svg', ''))}";
export default VueComponent;
`;
if (!viteConfig.isProduction) {
code += `
VueComponent.data = () => ({
path: "${path}",
});
`;
}
return code;
}
async function compileFileToJS(src) {
let contents = readFileSync(src).toString();
if (options.svgo !== false) {
contents = optimize(contents).data;
}
return await compileSvg(contents, src);
}
return {
name: 'svg-transform',
async configResolved(config) {
viteConfig = config;
},
async transform(src, id) {
if (fileRegex.test(id)) {
return await compileFileToJS(id.replace('?inline', ''));
}
},
};
}
export { index as default };