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

V3SlotSetters linter/codemod draft #1669

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open

V3SlotSetters linter/codemod draft #1669

wants to merge 11 commits into from

Conversation

Spone
Copy link
Collaborator

@Spone Spone commented Feb 28, 2023

What are you trying to accomplish?

I'd like to provide a linter / codemod to ease the upgrade to ViewComponent v3.0.0, especially the new slot setters syntax which is in my opinion the main hassle when upgrading.

For now, this draft only outputs suggestions of changes. If we're confident enough we don't have false positives, we can change it to actually modify the files (or allow running it as a linter or as a codemod).

What approach did you choose and why?

I first tried to experiment with Ruby AST / Parser-based solutions, but given that we have to access the slot names in ViewComponent classes and parse the content of various templates (erb, slim, haml), it did not appear as a viable solution.

Then, I implemented a two-steps approach:

  1. Load all ViewComponents and read the name of their slots;
  2. Try to find exact matches: scan all components and view files to find renders of the components, called with blocks, and methods matching the name of their slots' setter methods. These suggestions are prefixed with probably in the output ;
  3. In some cases (such as when using helpers to render components instead of render(MyComponent.new)), this was not enough to find all occurrences so I added another "uncertain matches" step: try to match the name of the slots in all files. These suggestions are prefixed with maybe in the output.

I tested this on several projects, here is the output:

Anything you want to highlight for special attention from reviewers?

I packaged this as a class that could be included to the gem.
The exact way people can run this remains to be defined.

We also have to figure a way to test this :)

What's left to do

  • fix render_match
  • autodetect view paths
  • improve uncertain matches by targeting full slot names instead of partial. This should reduce false positive results
  • add a rake task that will run codemod
  • make it accessible in rails console too
  • add a "--fix" mode that modifies the files (similar to standardrb --fix or rubocop -A)
  • tests
  • docs
  • changelog

@camertron
Copy link
Contributor

Very cool, thanks for taking this on! Before I really dive in I have a few questions.

  1. Have you had a look at erb-lint? It can parse ERB and I think uses the Parser gem under the hood. Might be a viable way to parse and manipulate ERB code.
  2. I know we probably want this codemod to work statically, but I'll bet we could identify slot getters/setters really accurately by setting a tracepoint and rendering all the previews + running all the tests. What do you think?

@Spone
Copy link
Collaborator Author

Spone commented Feb 28, 2023

  1. Have you had a look at erb-lint? It can parse ERB and I think uses the Parser gem under the hood. Might be a viable way to parse and manipulate ERB code.

I considered it but I wanted something that would work for any templating language (or at least the most popular ones: ERB, Slim, Haml), since I use Slim in most projects.

  1. I know we probably want this codemod to work statically, but I'll bet we could identify slot getters/setters really accurately by setting a tracepoint and rendering all the previews + running all the tests. What do you think?

That would be an interesting approach, but it would only work on thoroughly previewed / tested components, which is sadly not always the case 🙃
I'd love to see what this would look like though! Maybe we can add this as another scanning step.

@allmarkedup
Copy link
Contributor

@Spone this is fantastic! Really great work mate. I have been putting off the big upgrade job at work but this looks like it'll get me a lot closer. Very exciting, I'm sure that the slot name changes are a blocker for quite a few people so this looks like a great solution, even if it only ended up getting 95% of the way there.

I'm off for a couple of days but will give it a test on our codebase when I'm back. I think I'll probably still try to combine it with some sort of monkey-patched ViewComponent gem to hopefully log anywhere that old-style slot names are still being used after the codemod has run, just to be sure.

@boardfish
Copy link
Collaborator

I'm also planning to test this on our migration to ViewComponent 3 once I get around to it. Thanks for putting it together!

I really like providing codemods as a pattern to help folks along their migration path. We could tuck this inside a generator that helps folks to handle migrations, similar to Rails' own app:update task.

@joelhawksley
Copy link
Member

@Spone I like it! Are you hoping to land this in a Release Candidate ahead of 3.0.0 landing?

@Spone
Copy link
Collaborator Author

Spone commented Mar 8, 2023

@joelhawksley I'd love to, if I get sufficient feedback from people who tried it!

I ran this on more codebases, and noticed a few false-positives that I'd like to fix as well.

Copy link
Member

@joelhawksley joelhawksley left a comment

Choose a reason for hiding this comment

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

I think others will find this tool helpful. Would it be worth writing a simple test for it? We don't need to be too thorough.

lib/view_component/codemods/v3_slot_setters.rb Outdated Show resolved Hide resolved
#
# ViewComponent::Codemods::V3SlotSetters.new.call
#
# If your app uses custom paths for views, you can pass them in:
Copy link
Member

Choose a reason for hiding this comment

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

Could we load these from the rails config instead of requiring them to be passed in?

lib/view_component/codemods/v3_slot_setters.rb Outdated Show resolved Hide resolved
lib/view_component/codemods/v3_slot_setters.rb Outdated Show resolved Hide resolved
@joelhawksley
Copy link
Member

@Spone I'm hoping to wrap up the v3 release cycle in the next week or two, so perhaps you could decide whether to land this in the next week?

@boardfish
Copy link
Collaborator

Ran this against our codebase @fac. I'd already gone through and made all the necessary changes previously on another branch.

When I ran this before I had updated the slot syntax, it came up with a lot of maybe cases. Enough of these were false positives that I can say this was quite noisy for my use case. In particular, it caught a lot of method names that begin with the names of slots that exist on components. For example, it would catch total_somethings where there was a component with a slot named total. It'd be good to rework that side of things and perhaps also make it easier to filter the output.

When I ran this after I had updated the slot syntax, it didn't turn up any cases at all, which I'm hoping suggests that I had found everything that needed to be fixed.

Ideally, I think it would be really good to use erb-lint and rubocop to do this, with a view to making it possible to autocorrect these with confidence. That being said, there are definitely "maybe" cases, especially in cases where folks have components aliased to helpers.

@joelhawksley
Copy link
Member

@Spone are you still interested in landing this PR? I'd be cool either way but I'm trying to get a feel of what we'd like to land with v3 final.

@Spone
Copy link
Collaborator Author

Spone commented Mar 29, 2023

@joelhawksley Sorry I missed your previous comment. I'd like to continue improving this but I cannot commit to a specific time frame. I feel like this can be part of an upcoming v3.x minor version release. What do you think?

@Spone
Copy link
Collaborator Author

Spone commented Apr 26, 2023

I'd be open to pairing with someone to wrap this up!

@Spone Spone added help wanted slots Related to the Slots feature labels Apr 26, 2023
rendered_components = []
content = File.read(file)

if (render_match = content.match(RENDER_REGEX))

Choose a reason for hiding this comment

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

Is this assuming only a single render_match per file?

If I render multiple different components in the same file, would this catch it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

After re-reading the code, I guess you're right. I'm a bit surprised I didn't catch this earlier 😅

This part needs to be reworked.

@kirillplatonov
Copy link

kirillplatonov commented Apr 29, 2023

@Spone what's left here in order to get this ready for merge? Some suggestions I have:

  • Improve uncertain matches by targeting full slot names instead of partial. This should reduce false positive results
  • Add a rake task that will run codemod
  • Make it accessible in rails console too

@Spone
Copy link
Collaborator Author

Spone commented May 4, 2023

@kirillplatonov I added a "What's left to do" section to the PR description, including your suggestions. Would you like to take care of some of these items?

@kirillplatonov
Copy link

@Spone sure! Should I open a PR with my changes to codemods/v3-slots branch?

@Spone
Copy link
Collaborator Author

Spone commented May 8, 2023

Yes please do!

* Add rake task for legacy slots detection

* Add view component previews to codemod view paths

* Autodetect rails view paths

* Improve uncertain matches detection

* Update lib/view_component/codemods/v3_slot_setters.rb

Co-authored-by: Hans Lemuet <Spone@users.noreply.github.com>

* Update usage instruction

* Add rake task to migrate to new slots

* Update changelog

* Standardrb

* Add tests

* Call eager loading via Rails

* Update docs/CHANGELOG.md

Co-authored-by: Hans Lemuet <Spone@users.noreply.github.com>

* Add support for passing view paths via CLI

* Fix helper in rake tasks

* Fix tests

* Add note about codemod to changelog

---------

Co-authored-by: Hans Lemuet <Spone@users.noreply.github.com>
@Spone Spone marked this pull request as ready for review June 29, 2023 20:54
@Spone Spone requested a review from joelhawksley June 29, 2023 20:55
Copy link
Member

@joelhawksley joelhawksley left a comment

Choose a reason for hiding this comment

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

Might we add something to the docs for this?

@Spone
Copy link
Collaborator Author

Spone commented Jul 6, 2023

Might we add something to the docs for this?

Yes, but not sure where. We don't yet have a "Upgrading" page.

Also, we need to fix the changelog, the entry has to be under the main heading.

@joelhawksley
Copy link
Member

Yes, but not sure where. We don't yet have a "Upgrading" page.

How about adding a note to the Slots docs?

@Twistedben
Copy link

Hey guys!

I started working on a similar solution last week and had no idea! At eXp-Realty we use a lot of View Components and have 10+ production apps with them in them. I built a Ruby script to automatically update these slot calls with the with_ change. It's amazing how similar our solutions are though I think yours is better. I just wanted to add to the discussion and my script file if it can help at all. In one of our apps that I used it, it correctly updated over 327 slots.

https://github.com/Twistedben/view_component_3_slot_upgrade

@camertron
Copy link
Contributor

Hey @Spone, how's this PR coming along? Is it ready to merge?

@Spone
Copy link
Collaborator Author

Spone commented Aug 9, 2023

Haven't had time to look at this again before holidays, I'll get back to it when I'm back to work. Thanks everyone for your patience 🙏

@JWShuff
Copy link
Contributor

JWShuff commented Dec 20, 2023

Hey guys!

I started working on a similar solution last week and had no idea! At eXp-Realty we use a lot of View Components and have 10+ production apps with them in them. I built a Ruby script to automatically update these slot calls with the with_ change. It's amazing how similar our solutions are though I think yours is better. I just wanted to add to the discussion and my script file if it can help at all. In one of our apps that I used it, it correctly updated over 327 slots.

https://github.com/Twistedben/view_component_3_slot_upgrade

Just used that script to great effect, TY! Noted a small issue with encoding and have opened a PR against your repo if you'd like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted slots Related to the Slots feature v3
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants