Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

codemod(svgs): Convert imported SVGs to react components #8564

Merged
merged 26 commits into from
Jun 26, 2023

Conversation

dac09
Copy link
Collaborator

@dac09 dac09 commented Jun 8, 2023

This codemod will find all the cases where SVGs are imported as used as components, and then:

  1. Generates a react component with SVGR (see fixtures for example)
  2. Replaces the import to the svg file with an import to the new React component

e.g.

- import Bazinga from '../bazinga.svg'
+ import Bazinga from '../BazingaSVG.jsx'

const myComponent = () => {
  // ...
  <Bazinga/>

Don't forget that this is needed no matter if you use vite or webpack

Also:
- fixes codemod template
- updates testUtils to output more verbosely
This got pulled out into a separate PR

Todo:

  • test on a real project
  • check output with Webpack
  • check output with Vite
  • deal with SVGs as renderProp
  • deal with unused SVG imports
  • add svgr as dependency, instead of using npx because tests timeout
  • deal with src imports
  • component names should be sanitized

@dac09 dac09 added the release:chore This PR is a chore (means nothing for users) label Jun 8, 2023
@dac09 dac09 requested a review from jtoar June 8, 2023 11:38
@KrisCoulson
Copy link
Contributor

Just to let you know that I am pretty sure this change breaks styling.

if you have an svg like this

<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
	<g>
		<path fill="none" d="M0 0h24v24H0z"></path>
		<path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-			4v2h2V7h-2z"></path>
	</g>
</svg>

When you add a style like color: red the svg is red.

but if you put it in an img tag I don't think it respects the color anymore.

also see
WICG/proposals#50

@jtoar jtoar mentioned this pull request Jun 10, 2023
1 task
@dac09
Copy link
Collaborator Author

dac09 commented Jun 12, 2023

Just to let you know that I am pretty sure this change breaks styling.

if you have an svg like this

<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
	<g>
		<path fill="none" d="M0 0h24v24H0z"></path>
		<path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-			4v2h2V7h-2z"></path>
	</g>
</svg>

When you add a style like color: red the svg is red.

but if you put it in an img tag I don't think it respects the color anymore.

also see WICG/proposals#50

True, and thanks for pointing this out. I knew there were cases where its different, I just couldn't remember what!

It depends on what people use for styling SVGs ofcourse, but if they used styled components or tailwind (or just classnames) it should carry over.

We can merge this in when we decide how to proceed.

@dac09 dac09 added this to the v6.0.0 milestone Jun 14, 2023
@dac09
Copy link
Collaborator Author

dac09 commented Jun 16, 2023

@jtoar do you want to give this a once over? We're good to merge.

@jtoar
Copy link
Contributor

jtoar commented Jun 16, 2023

Sorry @dac09 I don't have the bandwidth right now, deferring to you and @KrisCoulson

@dac09 dac09 enabled auto-merge (squash) June 19, 2023 06:01
@dac09
Copy link
Collaborator Author

dac09 commented Jun 19, 2023

Merging this in, will test with Kris tomorrow - maybe when we write the SVG usage guide.

@Tobbe Tobbe disabled auto-merge June 19, 2023 07:16
@Tobbe
Copy link
Member

Tobbe commented Jun 19, 2023

image

This sounds good, but I don't see these changes in the code. Did you decide not to do those changes after all?

@Tobbe
Copy link
Member

Tobbe commented Jun 19, 2023

I think we should leave SVGs alone that pass non-img props to the generated svgr component. Makes no sense to me to codemod into something we know is broken. Like <MyIcon strokeWidth={2} /> -> <img ... strokeWidht={2} />. We know the generated img wont work, so I think it's better to leave the original code.

@Tobbe
Copy link
Member

Tobbe commented Jun 19, 2023

Also, did we consider using https://github.com/pd4d10/vite-plugin-svgr instead of introducing this breaking change?

Copy link
Collaborator Author

dac09 commented Jun 19, 2023

Also, did we consider using https://github.com/pd4d10/vite-plugin-svgr instead of introducing this breaking change?

We’d need to use a babel plugin so that prerender still works. It’s a conscious decision not to, as discussed before, we want to be closer to Vite’s defaults. There’s a lot of nuance to this - and can create edge cases where rendering breaks (e.g. when using svg component in .js files - why I do not know). Ofcourse users are free to configure their project however they wish. I think https://github.com/JonasKruckenberg/imagetools/blob/main/docs/guide/getting-started.md is what we should be aiming for in the future, using directives feels a lot better UX and avoids the pitfalls of SVGR.

The plan is to remove support, but provide a guide for how to set up SVG components in their project. This means the edgecases aren’t a redwood problem, but a project specific problem (which is a much better problem to have)

This sounds good, but I don’t see these changes in the code. Did you decide not to do those changes after all?

Pulled those changes into a different PR that got merged.

I think we should leave SVGs alone that pass non-img props to the generated svgr component. Makes no sense to me to codemod into something we know is broken. Like <MyIcon strokeWidth={2} /> -> <img ... strokeWidht={2} />. We know the generated img wont work, so I think it’s better to leave the original code.

There’s 1000s of permutations of how attributes are used, and the safest option is to keep all the existing attributes - _with _the caveat that styling may change. SVGR can process SVGs a little differently - and can be brittle. See #8291. Adding strokeWidth etc. is harmless, even if not ideal.

@Tobbe
Copy link
Member

Tobbe commented Jun 19, 2023

It’s a conscious decision not to, as discussed before, we want to be closer to Vite’s defaults. There’s a lot of nuance to this

When we talked about this at the core team meeting I didn't have the full picture

  1. I didn't think about the "pass svg-specific props" use-case. This is a unique feature of SVGs that RW users used to have access to, but won't any more.
  2. I didn't know how easy it'd be to maintain the same suport with Vite (just add a plugin)
  3. I didn't know that this wasn't default for webpack either but rather something someone at some point thought was a valuable addition to RW

Removing a feature means more time is spent in the team talking about it, and more time is needed for users updating their projects, and more friction is introduced in the upgrade process meaning users are less likely to upgrade. I think it needs to be more clear that over time the initial cost will be worth it. Both for us and for our users.

But I also know that sometimes I'm overly accommodating to our users need, and willing to go too far to make it easy for people at the cost of code complexity etc.

Pulled those changes into a different PR that got merged

Awesome! I like it when PRs are smaller and more focused 🙂 I made a note of it in this PR's description

There’s 1000s of permutations of how attributes are used, and the safest option is to keep all the existing attributes - _with _the caveat that styling may change. SVGR can process SVGs a little differently - and can be brittle. See #8291. Adding strokeWidth etc. is harmless, even if not ideal.

I'm just worried that someone runs the codemod and then a while later realizes that half of their svgs have the wrong size or color. And they won't know which ones until they see them in their app. It's easier to find ones that weren't codemodded because they'll have a project that won't build until they fix them all.

@dac09 dac09 removed the request for review from jtoar June 21, 2023 08:04
@dac09
Copy link
Collaborator Author

dac09 commented Jun 21, 2023

@Tobbe want to review again please?

Worth trying out, because it does a lot of funky things. Looks like tests are timing out because of the use of npx.

The alternative is to add svgr as a dependency to the codemod package - will do that in a bit.

…redwood into codemod/replace-svg-as-components

* 'codemod/replace-svg-as-components' of github.com:dac09/redwood:
  chore(deps): update react monorepo (redwoodjs#8677)
  chore(deps): update dependency postcss to v8.4.24 (redwoodjs#8675)
  chore(deps): update dependency esbuild to v0.18.6 (redwoodjs#8670)
  chore(deps): update dependency dependency-cruiser to v13.0.4 (redwoodjs#8674)
  chore(deps): update dependency autoprefixer to v10.4.14 (redwoodjs#8668)
  chore(deps): update dependency @clerk/clerk-react to v4.20.5 (redwoodjs#8672)
  Fix typos in documentation (redwoodjs#8659)
  fix(docs): Fix & make verifyOwnership consistent (redwoodjs#8596)
  chore(deps): update dependency vite to v4.1.5 [security] (redwoodjs#8671)
  fix(deps): update dependency react-hook-form to v7.45.0 (redwoodjs#8664)
  chore(studio): update tremor to v3 (redwoodjs#8645)
  fix(deps): update dependency webpack to v5.87.0 (redwoodjs#8549)
  fix(deps): update dependency dotenv to v16.3.1 (redwoodjs#8663)
  chore(deps): update dependency @clerk/clerk-react to v4.20.4 (redwoodjs#8662)
  fix(vite): Change config for mantine and chakra to use export default (redwoodjs#8639)
  fix(deps): update storybook monorepo to v7.0.22 (redwoodjs#8652)
  Fix failing v5 codemod for DevFatalErrorPage (redwoodjs#8661)
@dac09 dac09 changed the title codemod(svgs): Convert SVGs from components to img tags codemod(svgs): Convert imported SVGs to react components Jun 21, 2023
…ace-svg-as-components

* 'main' of github.com:redwoodjs/redwood: (25 commits)
  fix(deps): update dependency @whatwg-node/fetch to v0.9.7 (redwoodjs#8702)
  fix(deps): update dependency @heroicons/react to v2.0.18 (redwoodjs#8701)
  fix(deps): update dependency @headlessui/react to v1.7.15 (redwoodjs#8700)
  fix(deps): update dependency webpack to v5.88.0 (redwoodjs#8697)
  fix(deps): update dependency @graphiql/toolkit to v0.8.4 (redwoodjs#8698)
  fix(deps): update dependency react-error-boundary to v4.0.10 (redwoodjs#8693)
  Rename cache file (redwoodjs#8699)
  fix(clerk): add alternative decoder (redwoodjs#8642)
  fix(deps): update dependency @vitejs/plugin-react to v4.0.1 (redwoodjs#8692)
  chore(deps): update dependency @simplewebauthn/server to v7.3.1 (redwoodjs#8690)
  chore(rwfw): Add force optimise to vite.config when running project:sync (redwoodjs#8688)
  fix(deps): update storybook monorepo to v7.0.23 (redwoodjs#8696)
  fix(deps): update dependency react-toastify to v9.1.3 (redwoodjs#8694)
  fix(deps): update prisma monorepo to v4.16.1 (redwoodjs#8695)
  Mark broken gql prerender test as slow (redwoodjs#8687)
  fix(deps): update dependency @graphiql/plugin-explorer to v0.1.20 (redwoodjs#8691)
  fix(deps): update typescript-eslint monorepo to v5.60.0 (redwoodjs#8660)
  fix(deps): update dependency @fastify/http-proxy to v9.2.1 (redwoodjs#8680)
  chore(deps): update dependency vite to v4.3.9 (redwoodjs#8682)
  fix(deps): update prisma monorepo to v4.16.0 (redwoodjs#8684)
  ...
@Tobbe
Copy link
Member

Tobbe commented Jun 24, 2023

I tried this on an example project I set up now, and this is the output I got
image

What does "7 unmodified" mean?

Using RW src/-style imports doesn't seem to work
image

@Tobbe
Copy link
Member

Tobbe commented Jun 25, 2023

Just realized it's also having problems with filenames with dashes in them. The generated component name isn't valid.

image

@dac09
Copy link
Collaborator Author

dac09 commented Jun 26, 2023

What does "7 unmodified" mean?

It means JSCodeshift did not modify them.

Thanks, adding Todos:

  • deal with src imports
  • component names should be sanitized

task('Replace Component Svgs', async ({ setOutput }: TaskInnerAPI) => {
await runTransform({
transformPath: path.join(__dirname, 'replaceComponentSvgs.js'),
// Here we know exactly which file we need to transform, but often times you won't.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Here we know exactly which file we need to transform, but often times you won't.

We use globbing because we don't know exactly what files we need to transform, right? So the comment is wrong.

@Tobbe
Copy link
Member

Tobbe commented Jun 26, 2023

It means JSCodeshift did not modify them.

"7 source files matched targetPaths but were not modified". Something like that would make it more clear I think 🙂 Not something we can/should fix. Just jscodeshift that could work on their output messages. Because first I was like "7 unmodified? I don't even have 7 SVGs in total!" 🙂

dac09 and others added 5 commits June 26, 2023 15:46
@dac09 dac09 enabled auto-merge (squash) June 26, 2023 09:16
@dac09 dac09 merged commit c4ecba8 into redwoodjs:main Jun 26, 2023
@redwoodjs-bot redwoodjs-bot bot modified the milestones: v6.0.0, next-release Jun 26, 2023
@dac09 dac09 deleted the codemod/replace-svg-as-components branch June 26, 2023 10:46
@dac09 dac09 modified the milestones: next-release, v6.0.0 Jun 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release:chore This PR is a chore (means nothing for users)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants