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

Modules with no react exports are treated as fast-refresh boundaries #9869

Closed
7 tasks done
IanVS opened this issue Aug 26, 2022 · 2 comments · Fixed by #10239
Closed
7 tasks done

Modules with no react exports are treated as fast-refresh boundaries #9869

IanVS opened this issue Aug 26, 2022 · 2 comments · Fixed by #10239

Comments

@IanVS
Copy link
Contributor

IanVS commented Aug 26, 2022

Describe the bug

In Dan's original comment describing fast-refresh (facebook/react#16604), he says only files that only export components should be treated as boundaries. But, it seems that the isRefreshBoundary function in @vitejs/plugin-react is much more lax. It seems to only check that export names are capitalized. But, they don't need to be functions, they can be exported objects. See the reproduction for an example of how this causes problems.

One approach we could take which might be more robust, would be to perform a runtime check using isLikelyComponentType from the react-refresh runtime library. That has more robust checks than I think we can accomplish statically in the AST. https://github.com/PepsRyuu/rollup-plugin-react-refresh/blob/master/index.js is an example of a project that takes roughly this approach.

Reproduction

https://stackblitz.com/edit/vitejs-vite-b4yvhl?file=src/not-react-components.jsx

System Info

N/A

Used Package Manager

npm

Logs

No response

Validations

@IanVS
Copy link
Contributor Author

IanVS commented Sep 12, 2022

I'm willing to attempt a PR to use isLikelyComponentType if it's agreed that's a viable option by the core team.

@IanVS
Copy link
Contributor Author

IanVS commented Sep 25, 2022

I've hit a snag, unfortunately. I was able to add a conditional import.meta.hot.accept() which checks if all the exports are react components, using isLikelyComponentType, and that part worked great. But I found that changes were still not bubbling up to the parent, and tracked down the reason:

if (rawUrl === 'import.meta') {
const prop = source.slice(end, end + 4)
if (prop === '.hot') {
hasHMR = true
if (source.slice(end + 4, end + 11) === '.accept') {
// further analyze accepted modules
if (source.slice(end + 4, end + 18) === '.acceptExports') {
lexAcceptedHmrExports(
source,
source.indexOf('(', end + 18) + 1,
acceptedExports
)
isPartiallySelfAccepting = true
} else if (
lexAcceptedHmrDeps(
source,
source.indexOf('(', end + 11) + 1,
acceptedUrls
)
) {
isSelfAccepting = true

It appears that the import analyzer only looks for the string import.meta.hot.accept() in the source code, and does not consider that it might be conditional. So, even when my if block would prevent the self-accept from happening, vite still does not allow the change to bubble to a parent and be dealt with there.

I tried to calculate a list of "acceptable" exports and use import.meta.hot.acceptExports (which would be really cool to do!), but again hit a problem because it's looking for a static list of export names, not a dynamic variable calculated at runtime.

I'd love to hear any thoughts from @patak-dev or @aleclarson (or anyone else!) about what could potentially be done here.

@github-actions github-actions bot locked and limited conversation to collaborators Oct 20, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant