svgIconLoader.cjs 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. /**
  2. * Webpack loader for SVG icons in svgs/ directory.
  3. * Transforms SVG files into Iconify-compatible objects: { width, height, body }
  4. * - single-color/: replaces fill/stroke colors with currentColor
  5. * - multi-color/: preserves original colors
  6. */
  7. let iconifyToolsPromise = null;
  8. function getIconifyTools() {
  9. if (!iconifyToolsPromise) {
  10. iconifyToolsPromise = import('@iconify/tools');
  11. }
  12. return iconifyToolsPromise;
  13. }
  14. module.exports = async function svgIconLoader(source) {
  15. const callback = this.async();
  16. const resourcePath = this.resourcePath;
  17. const isSingleColor = resourcePath.includes('single-color');
  18. try {
  19. const { SVG, cleanupSVG, parseColors, isEmptyColor } = await getIconifyTools();
  20. // Multi-color icons containing <image> tag: extract as-is
  21. if (!isSingleColor && source.includes('<image')) {
  22. const viewBox = source.match(/viewBox="([^"]+)"/)?.[1] || '0 0 1 1';
  23. const parts = viewBox.split(' ').map(Number);
  24. const width = parts[2] || 1;
  25. const height = parts[3] || 1;
  26. const innerContent = source.replace(/<svg[^>]*>([\s\S]*)<\/svg>/i, '$1');
  27. callback(null, `export default ${JSON.stringify({ width, height, body: innerContent })}`);
  28. return;
  29. }
  30. const svg = new SVG(source);
  31. await cleanupSVG(svg);
  32. if (isSingleColor) {
  33. parseColors(svg, {
  34. defaultColor: 'currentColor',
  35. callback: (_, colorStr, color) => {
  36. return !color || isEmptyColor(color) ? colorStr : 'currentColor';
  37. },
  38. });
  39. }
  40. const width = svg.viewBox.width;
  41. const height = svg.viewBox.height;
  42. const optimizedSvg = svg.toMinifiedString();
  43. const innerContent = optimizedSvg.replace(/<svg[^>]*>([\s\S]*)<\/svg>/i, '$1');
  44. callback(null, `export default ${JSON.stringify({ width, height, body: innerContent })}`);
  45. } catch (err) {
  46. callback(err);
  47. }
  48. };