react-router HMR Issues when lazy-load
Is HMR working correctly for everyone? I noticed that it's no longer working for me and I have to manually refresh the page each time. The only major change I did was switch to the new React Router 6.4 system: https://reactrouter.com/en/main so it might be that
78 Replies
@nahtnam has reached level 10. GG!
I have seen someone reporting issue about this before as well re: latest react-router
Does this happen only when you change a sub-page, or even when you change the root entry file, HMR won't hit at all?
@nahtnam I assume this is happening in a newtab page right?
Correct on the newtab
let me check if updating the root file HMRs
HMR works if I edit the root file (outside of the react router provider)
that's tricky...
I wonder if this is because of provider and caching :-?..
like if they put the Element inside a memo and cache it
https://github.com/remix-run/react-router/issues/9493
Not a very helpful response
maybe HMR couldn't propagate due to their new provider cached the view, and HMR is blocked from applying view change due to memo cache (?))
I'd investigate this: https://reactrouter.com/en/main/route/should-revalidate
Oh you know what, one other thing
I lazy load every route
if vite's having the same issue, then anyone using the standard react-dev-runtime would have the same issue I recon
hmmm
try disabling lazyload for dev bundle
using
process.env.NODE_ENV
When using lazyload and create prod bundle, does it spit out multiple file or still a huge newtab.js bundle?Let me try that, it returns a bunch of files, one for each page
If it spits out a huge newtab bundle (which I kinda expect it to atm - we don't explicitly split bundle yet due to extension import protocol still need to be investigated), I don't think lazy load would help much. But if it does spit out one for each page (surprise, it just work??), then I'd keep lazy for prod but remove it for dev and see if HMR work
Yep, youre right
That was the issue, changing it to not lazy load the solution
However I'm not entirely sure how to only lazy load in prod, let me look into it
I wonder if I import but don't use
<Component
if it will be tree shaken out in productionyes it will, there's a technique for this as well
I think the treeshaker will actually prune ternary as well
so like:
๐ฅ
Let me give that a shot, ill get back to you in an hour
Now I'm not sure if you can set that process.env into a variable tho.. since the static evaluator might not dig deeper into the runtime stack
so you might need to be verbose with this one, OR have a giant if statement at the top
Alright so this works:
in development but in production it fails. I also tried variations of the code above. I think the issue seems to be that you can't
import('./page')
actually have the import of page
in the same file
yep I think it would cause some type of circular injection
does the HMR work in dev mode with that?
Yes it does
So just need it to build
@nahtnam just released 0.71.1, try it with hoist and for your remote import, use the suggestion in the other thread
Alright so it builds without hoist, so thats good news
Sorry wrong thread
Okay so the 0.71.0 issue is resolved, hoist doesnt work. With the solution you mentioned in the other thread (adding
_
) it throws an error:
Yeah so rn this is focusing on that remote code import right
I'm seeing a similar issue as well, trying to see if I can bundle it somehow :d....
Gotcha, not that big of a deal to not use hoist, some extra code gets bundled
Im more annoyed by the lazy import thing ๐
trying to play around with it, for sure id like to use lazy because the excess code being loaded slows the newtab down and im trying to keep it as light as possible
@nahtnam try out 0.71.2
for this, can the if statement be moved one level up? :-?
Hmmm
๐ด ERROR | EACCES: permission denied, open '/Users/nahtnam/Desktop/code.nosync/ludicrous/caddie-dash/.plasmo/cache/remote-code/240c7a708a5899b1.js'with and without hoist Tried the solution you posted as well
process.env.NODE_ENV === "development" ? exportPage(..) : exportPage(...)
, I think the issue is just having both imports in the same fileoh wat
Fails in CI with the same error too
do you have the import in multiple file?
Nope, I have two imports though
hmmm...
BTW
I got a solution for your original problem
(prod vs dev router)
potential solution xd
So the idea is that you would have a
popup.tsx
and a popup.production.tsx
And in the popup.production, you would specify lazy loading etc...
@nahtnam ^ do you think that direction might solve the problem?I dont think that would work with the way that i've laid out the code ๐ฆ Each of the
route.tsx
export a route, so I think id have to duplicate all of thoseDoes HMR work if you do lazy but with constant invalidation lol
Like this:
Nope, I put a console.log in there too and its not firing so I assume
shouldRevalidate
isnt run even with theres an HMR updatehmm
if that's the case
@nahtnam here's my solution: https://github.com/PlasmoHQ/examples/blob/main/with-react-router/routes/index.tsx
GitHub
examples/index.tsx at main ยท PlasmoHQ/examples
๐ฐ Example projects that demonstrate how to use the Plasmo Framework and integrate with popular tools - examples/index.tsx at main ยท PlasmoHQ/examples
also just published a fix for this in 0.71.3!
basically, the lazy-router is a thin wrapper around the demoview (that's going to be lazy loaded), then if I want to render directly for HMR, the dev version consume the view directly
hmm...
just inspected the bundle... the lazy view is still bundled in the top bundle xd.....
๐
Also build without hoist works in 0.71.3 but with hoist it's still broken
nvm I actually dont think its the
import http
stuff, its broken even if I comment those out
So weird: https://gist.github.com/nahtnam/67798f330ae629b62220e51701f0fd09
I was speculating that maybe if with --hoist
it's more aggressive, maybe the lazy import thing would workdang it
@louis has reached level 46. GG!
I couldn't figre out a good way to ensure both lazy loading and also HMR in dev on the same file lol
unless we provide a custom lazy importer similar to nextjs's dynamic thingy
that's basically what they did
also iirc, nextjs dynamic trigger a reload instead of HMR lol xD....
Hmm no worries, I might just undo the
lazys
in that caseIs there any place that a
const
is being reassigned in your code somehow :d....
weird that it's... bundled ok in dev tho lol
but that error is likely when it try to optimize the code :-?..One last question, I dont fully understand how
import
works but do you know if its possible to have top level dynamic imports?
One potential direction could be:
I don't think so, ts would've complained if i reassigned a const
import()
returns a promise that eventually resolve to the module being imported at runtimeYeah thats what the types represent too, i'm just curious if we could somehow support top level awaits or something and have them resolve in
development
this sucks bc without hoist, you ended up bundling that devtool xD
I tried this and the problem is that when doing import(route.location).Component <- this breaks HMR still lol
๐
yeah so the only option that'd allow HMR in dev and lazy load in prod is
to use dedicated prod vs dev bundle file, that'd basically keep the bundler from looking at both dynamic and static import
Hmm, let me see if there is a way I can organize my code to do that
Quick question, if you add
import * as Sentry from '@sentry/react';
to your newtab.ts, does building with hoist work?
That line is one example of it breaking for meif you remove it, it works?
I commented out all other code in my newtab file
Yes
Well i have other stuff too
hmmm... I'm not sure what's inside the sentry package that'd break the hoisting lol
Its not just sentry, I see several references in my error messages to supabase too
@nahtnam has reached level 11. GG!
But basically if i empty my newtab file to just some plain html + import sentry it breaks
that should be hopefully reproducible
barrel import might affect deduplication/tree-shaking but shouldn't affect the overall build
if you do just
import Sentry from '@sentry/react';
does it work?
Or maybe try to import just what you need from it like init and ErrorBoundary :-?....node\_modules/@sentry/react/esm/index.js does not export 'default'
changing to import { withProfiler } from '@sentry/react';
also doesnt work
Same error messageare you using the latest version?
Yep
they have an ESM bundle :-?
Specifically you need to import * as and then also have
export default Sentry.withProfiler(IndexNewTab, { name: 'NewTab' });
BTW is there any prereq to get the lazy of ReactRouter working? ;d
I couldn't get it to render lol
Getting this:
Related to sentry: https://github.com/parcel-bundler/parcel/issues/8792
Hmmm
This is my export page function:
And of course, the
lazy
route basically needs to export a function called Component
Hmm do you think this would help? https://www.npmjs.com/package/@rollup/plugin-dynamic-import-vars
Oh nvm Plasmo uses parcelyeah xddd
I just added the feature to do
newtab.production.tsx
It actually would solve all of your problems
i.e, not bundling devtool, have sentry unhoisted, and lazyload
But yeah would need a slight refactor for the router ;dI don't mind the refactor, I'm just worried that I'd have to define each route twice
because of not being able to import via a dynamic path
BTW does that work with
newtab/index.production.tsx
? ๐
yeah it does hahah
How would the production file solve the sentry problem? I also want it included in the production bundle
here's an example: https://github.com/PlasmoHQ/examples/blob/main/with-react-router/routes/index.production.tsx
oh sentry can only be bundled without hoist
to clarify - previously we needed hoist to remove the devtools, but now we can remove the devtools without hoist, which also enable bundling sentry xD
Gotcha, so here is my game plan:
index.tsx and index.production.tsx contain the same layout, index.tsx just has the extra devtools
the router.tsx has all of the routes defined BUT does not have the component definition
the two .router.tsx files imports
router.tsx
and attaches an import statement (either lazy or not depending on which file) and I'll rely on typescript to make sure I dont miss a routethat works, you can likely infer type and import it in the other router
I wonder if there's a way to do shape infer like that for route :-?.
BTW @nahtnam
Uh oh
Im half way through the refactor ๐
I suspect it's possible that we will eventually have a downstream fix to the react-router and livereload
xD
oh lol
Gotcha, I've made it in a way that it should be super easy to swap back
Tho in the future if it all works
yeea
I just delete the
index.production.tsx
and copy over the lazy router
If you ever want me to test it, I can ๐yeet
parcel will have a minor upgrade soon next month
we will get their newer js transformer, and I suspect should fix this issue
Alright here is what I ended up with
Thanks for being awesome as always
noice