evenchange4 / svgr.macro

Run svgr at build-time with babel-plugin-macros.
MIT License
43 stars 4 forks source link

Feature: options with callback #27

Closed lifeiscontent closed 4 years ago

lifeiscontent commented 6 years ago

@evenchange4 hey, thanks for this awesome macro.

I was wondering if we could have a feature so that you can pass the options as props.

so we could do something like this:

import toReactComponent from "svgr.macro";

const icons = toReactComponent("./icons/*.svg", ({ fileName }) => {
  const path = require('path');
  return {
    icon: true,
    replaceAttrValues: ["#000000=currentColor"],
    svgo: NODE_ENV === "production",
    componentName: path.basename(fileName, '.svg')
  };
});

basically, I'd like to create a mapping of icons based off their actual fileNames.

evenchange4 commented 6 years ago

Thanks for the feedback. :) In my opinion, it is not necessary to customize componentName yourself. Svgr already use filename as componentName by default.

Here is a demo:

$ svgr src/__tests__/fixtures/material/autorenew.svg
import React from "react";

const Autorenew = props => (
  <svg height={24} viewBox="0 0 24 24" width={24} {...props}>
    <path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8A5.87 5.87 0 0 1 6 12c0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z" />
    <path d="M0 0h24v24H0z" fill="none" />
  </svg>
);

export default Autorenew;
lifeiscontent commented 6 years ago

@evenchange4 yeah, let me talk about a few problems in my head with current implementation.

  1. if someone updates the template, this macro will break.
  2. in every project I've ever worked in, all components usually map to the filename. Given this expectation, I think a reasonable default would to have the key be the actual file path, and that way you can map it to whatever you want from a component which consumes the source.

Example

// Icon/icons.js
const icons = {
  './icons/a-to-z.svg': props => { ... }
}

export default icons;
// Icon/index.js
import icons from './icons';
const Icon = ({name, ...props}) => React.createElement(icons[icons.find(path => path.match(name))], props)

export default Icon;
// Usage

<Icon name="a-to-z" fill="blue" />

With this, the name can be flexible, because you have the full path at your disposal.

evenchange4 commented 6 years ago
  1. if someone updates the template, this macro will break.

Yes, there is a known Babel cache problem for using macro as loader.

lifeiscontent commented 6 years ago

@evenchange4 I know about the Babel cache problem. That's not what I'm talking about, in SVGR, you can set a custom template for how the SVG is transformed. If someone sets that option in the macro, the macro will break, for example if the function is changed from an arrow function to a function declaration.

lifeiscontent commented 6 years ago

can you also respond to the other issue I brought up?

evenchange4 commented 6 years ago

You are right. Custom template will break the AST path of component name.

lifeiscontent commented 6 years ago

@evenchange4 would you consider updating the macro so that it returns a list of file names as keys instead of the name of the function? This makes more sense to me, as it works similar to the import-all macro from kentcdodds.