-
Notifications
You must be signed in to change notification settings - Fork 434
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
Add strict helpers #1987
base: introduce-component-local-config
Are you sure you want to change the base?
Add strict helpers #1987
Conversation
d6fe052
to
3c74fd8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thought on naming.
As a bigger question: what happens if one turns this on for their app and then wants to use a gem that provides ViewComponents that use helpers?
lib/view_component/base.rb
Outdated
@@ -224,7 +232,7 @@ def controller | |||
# @return [ActionView::Base] | |||
def helpers | |||
raise HelpersCalledBeforeRenderError if view_context.nil? | |||
|
|||
raise StrictHelperError if ViewComponent::Base.config.strict_helpers_enabled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this feature might be less confusing if we just had it be config.helpers_enabled
and defaulting it to true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@joelhawksley I think that's a good idea, when I have some time I will apply this feedback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@joelhawksley I have changed the config to this, if you could review it again it would be a massive
@reeganviljoen thoughts on my comment from my review above?
|
@joelhawksley I don't think this will break any existing gems, unless the user enables the config, however if the user does, it might not work unless the gem documents which helpers are used so the user can add them themselves with the use_helpers method I do think this is a positive improvement however, as just adding helpers increases coupling to global state, which I feel is bad and is against the whole point of view_component. If a gem wants to add helpers they should let the user decide what helpers and how much coupling to global state they want |
If a gem providing ViewComponents uses helpers, I'm not sure we should mandate that it's subject to Gems providing components that use helpers would need to be updated to use the new syntax, and waiting on providers to do that doesn't feel like an ideal experience for devs using ViewComponent to me. It's absolutely something gem maintainers should do post-haste, but I think configuration could make the transition period easier for consumers of these gems. I can see us going a few different ways with this:
I'm sure there are options beyond that, but that's what comes to mind right now. Any thoughts? |
@boardfish thanks for sharing your concerns- I generally agree with you. I think we might be better off having this be a macro folks can set on a component, likely on their ApplicationComponent. |
@joelhawksley @boardfish noted, I wills see if I can work on something to macro based system working |
I am on board with this ☝🏻 Could we also allow it to be optionally a deprecation warning instead of an error, that way it won't break things but it will give devs the tool to migrate their existing components. This could be useful for e.g. very large code bases where it is infeasible to migrate all components at once |
Another useful feature might be allowing to pass in a block that gets called every time helpers is referenced, so that devs can hook into their error tracker e.g. Sentry |
@reeganviljoen just checking in- are you planning to complete this work? |
@joelhawksley Absolutely, just been verry busy |
@joelhawksley what do you think about @danini-the-panini comment, I think its a good idea, I could work that into our current instrumentation setup in a seperate PR |
@joelhawksley I think that this api is complete as the main concern was gem compatibility but the recent addition to |
@reeganviljoen thanks for cleaning up this PR. For now, I'm going to mark it as blocked on @boardfish's work here: #1945 (comment) ❤️ |
This might actually be ideal as the first component-local config option due to the small scope of the PR. I'll see if I can grab some time this weekend to figure out if I can use this to make a start. |
Had a very scrappy crack at this in 35017a9 – it looks possible, and we could probably even ship that with a few more tests behind it and some cleanup (still need to document things and get the use of the private variable names vs. public method names straight). Going forward, though, we probably want to make a nice internal DSL that'll support migrating these config options across slowly but surely. |
@boardfish I aprreciate the help, if you want to pair on this issue I be happy to help. |
There's perhaps an even cleaner solution in |
313a922
to
a4a7ed9
Compare
@boardfish I have rebased of of #2124 and made that the base branch for this to make sure there is no weird diff issues |
Awesome ✨ In #2092, the changes to |
161cee3
to
6378768
Compare
On reflection, I'm thinking that the implementation I've got here (to be included in this branch) probably might need to change a touch – that makes all global options available on component-local config, when in reality changing any settings other than the ones related to helpers won't do anything. I expect that might cause some confusion if left in. Perhaps it would be good to have a |
* Fix duplicate template error bug This change fixes the bug reported where a component will report that it has both a template and a `call` method defined despite only having an HTML template. I was able to reproduce this bug by pulling in Avo (like reported in the initial bug report) and running `vegeta` (to trigger parallel requests since I had a hunch this was a race condition): ``` echo "GET http://localhost:3000/avo/resources/cars/1" | vegeta attack -duration=2s ``` This reliably reproduced the error: ``` ActionView::Template::Error (Template file and inline render method found for Avo::CoverPhotoComponent. There can only be a template file or inline render method per component. Template file and inline render method found for variant '' in Avo::CoverPhotoComponent. There can only be a template file or inline render method per variant. Templates: ``` I added _a lot_ of debug logs to understand the race condition that I thought was occurring, and realized that multiple threads are calling `gather_templates` _and_ mutating the `@templates` array at the same.When looking at the old compiler code and realized that this likely isn't new behavior. This led the investigation towards how we collect and surface errors or otherwise might modify templates. It turns out there's a difference in the new and old compiler code after the refactor: ```ruby \# old def template_errors @__vc_template_errors ||= \# new def gather_template_errors(raise_errors) errors = [] ``` _We're not memoizing the errors like we used to_. This is more correct behavior, but explains how a race condition would make this error case much more difficult to occur in older versions of the compiler. This change brings us back to the old behavior by memoizing the errors we collect in `gather_template_errors` but the `@templates` ivar is still being mutated. I don't want to change _too much_ in this PR, but a subsequent change might be wrapping the entire `compile` method in the `redefinition_lock` (and renaming it to `compile_lock`) to avoid similar issues in the future. I did not include a test because it's dfficult to reproduce this race condition reliably in the test environment. I believe this _should_ close out ViewComponent#2114 * Fix tests, raise errors for compiled components with errors * There isn't always a default template when there are errors. * Make standard happy ugh * Remove debug code * Fail compilation when errors present * Revert default template change * Add informative comment * Add changelog --------- Co-authored-by: Joel Hawksley <[email protected]>
70bed0a
to
dbfc516
Compare
Made those changes myself, but there are a few icky commits left in – I figure that if the base PR is merged, those will be easier to clean up. |
@boardfish much thanks will take a look tonight |
e9592cb
to
37e6d0d
Compare
2dcc88d
to
62e0960
Compare
closses #1976
What are you trying to accomplish?
Add a
config.view_component.strict_helpers_enabled
mode to view component which will throw anViewComponent::StrictHelperError
whenhelpers.<some_helper>
is used.This
What approach did you choose and why?
Anything you want to highlight for special attention from reviewers?