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

Fixed component rerendering if there's only one renderer (framework components) #12131

Open
wants to merge 12 commits into
base: next
Choose a base branch
from

Conversation

elite174
Copy link

@elite174 elite174 commented Oct 6, 2024

Changes

In this PR multiple server rerendering of the solid component is skipped if there's only one renderer in the project (solid-js).

I used only part of the solution for this issue.

If there're multiple rerenders, it should be processed in another way I suppose, but this little change can help if there's only one solid-js renderer.

Testing

Test was also added.

Docs

No need to update docs

Copy link

changeset-bot bot commented Oct 6, 2024

⚠️ No Changeset found

Latest commit: 1cf5bab

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions github-actions bot added the pkg: astro Related to the core `astro` package (scope) label Oct 6, 2024
@elite174 elite174 force-pushed the fix-multiple-component-rerenders branch from 993f55b to d9fba90 Compare October 6, 2024 06:39
@elite174 elite174 changed the title Fix component rerenders if there's only one renderer Fix component rerendering if there's only one renderer Oct 6, 2024
@elite174 elite174 changed the title Fix component rerendering if there's only one renderer Fix component rerendering if there's only one renderer (solid-js) Oct 6, 2024
Comment on lines 131 to 135
// If there's only one renderer in the project (solid-js)
// we can skip the `check` calls and use that renderer (to not render solid component twice)
if (renderers.length === 1 && renderers[0].name === '@astrojs/solid') {
renderer = renderers[0];
} else {
Copy link
Author

Choose a reason for hiding this comment

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

this is the only change

@elite174 elite174 changed the title Fix component rerendering if there's only one renderer (solid-js) Fixed component rerendering if there's only one renderer (solid-js) Oct 6, 2024
Copy link
Contributor

@matthewp matthewp left a comment

Choose a reason for hiding this comment

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

oops, accidentally approved.

break;
// If there's only one renderer in the project (solid-js)
// we can skip the `check` calls and use that renderer (to not render solid component twice)
if (renderers.length === 1 && renderers[0].name === '@astrojs/solid') {
Copy link
Contributor

@matthewp matthewp Oct 7, 2024

Choose a reason for hiding this comment

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

Why only Solid.js?

Copy link
Author

@elite174 elite174 Oct 7, 2024

Choose a reason for hiding this comment

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

because for some reason the tests fail for other frameworks. Moreover for solid it's critical to be rendered once, because solid doesn't have this "rerender" paradigm as react, preact or others.

More common solution could require much more efforts, so it should be carefully implemented. This is really easy fix which can help many people (because solid-start it's not that production-ready yet, so many people use astro+solid to get SSR), so we can do improvements step by step.

Copy link
Author

Choose a reason for hiding this comment

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

I tried to apply the solution suggested here, but looks like it doesn't work anymore for all the frameworks.

Copy link
Contributor

Choose a reason for hiding this comment

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

What tests fail? It's likely something we can fix. I don't think we should special-case one particular renderer in this case. There's nothing about this suggestion that shouldn't work everywhere.

If you could post the errors that occur when this is enabled for all renderers that would be helpful.

Copy link
Author

Choose a reason for hiding this comment

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

I would appreciate if you help to understand why the tests are failing.

Copy link
Author

Choose a reason for hiding this comment

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

Just pushed a commit

Copy link
Contributor

Choose a reason for hiding this comment

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

thanks, will take a look.

Copy link
Author

Choose a reason for hiding this comment

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

maybe here we need to check not renderers but validRenderers? I see that there can be a renderer with astro:jsx name, maybe this is the point...

Copy link
Contributor

Choose a reason for hiding this comment

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

No, the problem is that some renderers (Preact in particular), expect both check and renderToStaticMarkup to be called because they store state in check. We can probably make it a breaking change in 5.0 that check is not guaranteed to always be called.

Easy fix though, pushed a change.

Copy link
Contributor

Choose a reason for hiding this comment

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

Well there must be another issue too, will look into that.

@@ -132,6 +132,9 @@ async function renderFrameworkComponent(
// we can skip the `check` calls and use that renderer
if (renderers.length === 1) {
renderer = renderers[0];

// Still call `check` because some renderers store state during the check phase that they expect when `renderToStaticMarkup` is called.
await renderer.ssr.check.call({ result }, Component, props, children)
Copy link
Author

@elite174 elite174 Oct 10, 2024

Choose a reason for hiding this comment

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

If you do this you render solid-js component twice (but that was the case we want to fix), so... you can just remove this if statement

Copy link
Author

@elite174 elite174 Oct 10, 2024

Choose a reason for hiding this comment

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

I guess, it's possible to extend renderer interface with boolean flag shouldRun in order to explicitly say that this renderer should be called because it has some state which depends on the initial call?

You discovered that:

some renderers (Preact in particular), expect both check and renderToStaticMarkup to be called because they store state in check

Looks like it's not really obvious from the renderer interface, so that's why I suggest to extend it.

Copy link
Author

Choose a reason for hiding this comment

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

Hmm, it's a bit strange that function check (which should be pure) has some store in it

Copy link
Contributor

Choose a reason for hiding this comment

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

If you want to resubmit against next we could make this a breaking change that check is not guaranteed to run. In that case it would be on the renderer to not rely on it running. We'd also need to update Preact to account for that, I could do that part.

Copy link
Author

Choose a reason for hiding this comment

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

What do you mean by "resubmit" against next? next is a function which is called inside check?

Copy link
Contributor

Choose a reason for hiding this comment

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

@elite174 sorry for not explaining. We can't change the expectation that both check and renderToStaticMarkup both get called in 4.x. We already know it breaks out built-in renderers. That means it might also break external renderers.

We can make that a breaking change in 5.0 though, which is currently in beta. We are using the next branch for 5.0. If this PR was for 5.0 we could make this a breaking change, update the Preact renderer, document the change, etc.

Copy link
Author

Choose a reason for hiding this comment

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

Oh, yes, that would be awesome.

Copy link
Author

@elite174 elite174 Oct 11, 2024

Choose a reason for hiding this comment

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

Just rebased the PR
And removed check call if there's only one renderer.

@elite174 elite174 changed the base branch from main to next October 11, 2024 02:47
@elite174 elite174 changed the title Fixed component rerendering if there's only one renderer (solid-js) Fixed component rerendering if there's only one renderer (framework components) Oct 14, 2024
@elite174
Copy link
Author

Any news about this one? Will it be added to 5.0?

@elite174
Copy link
Author

@matthewp

@bluwy
Copy link
Member

bluwy commented Nov 4, 2024

The tests aren't fixed yet. From what I understand above, Matthew will look into it, but might be a bit tight to take a look.

Personally I don't know if this is the right fix. Once you add another renderer, like MDX or Svelte, you'd get the double rendering behaviour again. It's patching things and makes the DX unpredictable.

It's also risky that if you used a component but forgot to add the integration or renderer, you'd get a cryptic error about rendering issues, rather than "couldn't find matching renderer for this component" type of errors. (I guess the test fails could be related to this)

@elite174
Copy link
Author

elite174 commented Nov 5, 2024

It doesn't fix the situation with multiple renderers, however this easy fix helps if there's only one. Looks like to fix this problem it should be done more work, so I suggest doing it at least step by step.

@bluwy
Copy link
Member

bluwy commented Nov 5, 2024

I don't think it helps if there's no plan for the next steps, it'll only add upon the technical debt that we have to maintain. This easy fix is also going to impact DX as I mentioned above and isn't as harmless as it seems.

@elite174
Copy link
Author

elite174 commented Nov 5, 2024

Yeah, but... there's already a tech debt. And this debt is a bug. It should be fixed anyways.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg: astro Related to the core `astro` package (scope)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants