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

feat: dynamic modulepreload #7453

Merged
merged 17 commits into from
Apr 4, 2025
Merged

feat: dynamic modulepreload #7453

merged 17 commits into from
Apr 4, 2025

Conversation

wmertens
Copy link
Member

@wmertens wmertens commented Mar 24, 2025

This moves the service worker logic into the qrl handling, adding modulepreload link tags to request preloading chunks that will probably be needed soon.

This allows the browser to do its thing way better, and reduces complexity. (it would also allow some preloading in dev, but only for the SSR result, not implemented)

You can easily test the impact by going to the docs site and clicking the search button.

Features:

  • automatic no-config preloading based on probabilities, via qrl class
  • some mild preloading in dev
  • path-to-bundle mapping included in bundle graph
  • move all insights related build code into the insights plugin, including amending bundle graph
  • server now has manifest built-in, not necessary to pass it (but you can still amend it)

TODO:

  • test
  • replace qprefetch dispatches with some qwik API call
  • push qwik-city path preloads into bundlegraph
  • deprecate service workers, make them instead uninstall the current SW and use this
  • make this the default, we may not need any strategy any more
  • change jslink strategy to use this
  • fallback to preload when modulepreload not supported (iPhone 2017, iPad 2017, iPod Touch. All other browser support it for 1.5 years now. https://iosref.com/ios, https://caniuse.com/link-rel-modulepreload 93%)
  • implement probability-based loading via bundlegraph
  • use probabilities for ssr link provisioning
  • debug flag in the prefetch config
  • qwik add service-worker now that the starter no longer includes it

@wmertens wmertens added the COMP: performance This issue is related to a performance problem or bug label Mar 24, 2025
@wmertens wmertens self-assigned this Mar 24, 2025
Copy link

changeset-bot bot commented Mar 24, 2025

🦋 Changeset detected

Latest commit: a3fa86b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@builder.io/qwik Minor
@builder.io/qwik-city Minor
eslint-plugin-qwik Minor
create-qwik Minor

Not sure what this means? Click here to learn what changesets are.

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

@wmertens wmertens force-pushed the dynamic-modulepreload branch 2 times, most recently from b4e3856 to 5c623f5 Compare March 25, 2025 08:33
Copy link

pkg-pr-new bot commented Mar 25, 2025

Open in StackBlitz

npm i https://pkg.pr.new/@builder.io/qwik@7453
npm i https://pkg.pr.new/@builder.io/qwik-city@7453
npm i https://pkg.pr.new/eslint-plugin-qwik@7453
npm i https://pkg.pr.new/create-qwik@7453

commit: a3fa86b

Copy link
Contributor

github-actions bot commented Mar 25, 2025

built with Refined Cloudflare Pages Action

⚡ Cloudflare Pages Deployment

Name Status Preview Last Commit
qwik-docs ✅ Ready (View Log) Visit Preview a3fa86b

@Varixo
Copy link
Member

Varixo commented Mar 25, 2025

Is it a good idea to move fetching bundle graph to the head element?
Currently everything is added at the bottom of page, but if we have some promise to await then interactivity will be broken? For qwikloader we have an option to append it at the top, maybe here also should be such as option?

@wmertens
Copy link
Member Author

@Varixo

The bundlegraph is not that important for initial interactivity, it's better that the browser spends resources on showing the page first.
It is marked with normal priority before the modulepreloads, so depending on bandwidth the browser may or may not fetch it.

All the entry points get higher priority, so they will be available when you click.
The bundlegraph is not needed for QRLs to work, and priority goes to executing the app. Once the bundlegraph is loaded, it injects preloads for everything, but app functioning is not impacted.

@wmertens wmertens force-pushed the dynamic-modulepreload branch from bdea31c to 5d5c54a Compare March 25, 2025 16:57
@wmertens wmertens marked this pull request as ready for review March 25, 2025 16:58
@wmertens wmertens requested review from a team as code owners March 25, 2025 16:58
@wmertens wmertens force-pushed the dynamic-modulepreload branch 4 times, most recently from ee1de36 to 23d530b Compare March 26, 2025 00:04
@wmertens wmertens force-pushed the dynamic-modulepreload branch from 8df1c60 to 74b0661 Compare March 26, 2025 15:45
gioboa
gioboa previously approved these changes Mar 26, 2025
Copy link
Member

@gioboa gioboa left a comment

Choose a reason for hiding this comment

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

👏👏👏@wmertens

@wmertens wmertens force-pushed the dynamic-modulepreload branch 5 times, most recently from 05d51f1 to 115cee1 Compare March 27, 2025 13:31
@wmertens wmertens force-pushed the dynamic-modulepreload branch from 9305441 to da5ed64 Compare April 4, 2025 13:39
@wmertens wmertens enabled auto-merge April 4, 2025 13:59
@thejackshelton
Copy link
Member

@wmertens it might. But using link in initial html comes at the price of delaying initial layout as explained here : QwikDev/qwik-evolution#193 (comment)

So it's a trade-off.

  1. If you need a small amount of large files that you are critical at load time (classic CSR for example) it's better to include it in the head because the delay on layout depends on the amount of requests no matter the size.
  2. If you need a large amount of small files that can wait (prefetch everything for offline mode for example) it's better to move it in idle callback.

In the case you describe it's a small amount of small files that are not critical for load time but will be used soon. So not easy to give a definitive answer ah ah. I would say, since priority of qwik is load time I would recommend to wait idle callback.

The best, of course, would be to have some kind of threshold of files over which you wait until idle callback. But it might be a lot of work with unknown results.

Going off of what @GrandSchtroumpf mentioned here. If the modulepreload links are added during the critical rendering path, it is going to shave off some pagespeed points.

What we've done to prevent this in our production apps at work is by adding them at the load event during the browser idle periods

https://github.com/kunai-consulting/qwik-design-system/blob/main/apps/docs/src/docs-widgets/module-preload/module-preload.tsx

@wmertens
Copy link
Member Author

wmertens commented Apr 4, 2025

@thejackshelton looking at performance recordings, the FCP doesn't seem impacted by the modulepreloads even while the preloader is adding linkds, and in any case you can set maxPreloads to 2 or even 0 so that the preloader does the loading.

So I think that's ok?

@GrandSchtroumpf
Copy link
Contributor

@wmertens how is it going to behaves ?
The dev can specify the amount of links to add at SSR time, the framework add them in order of priority, then it adds remaining links on idle callback ?
For example if there are 10 links to add and dev set maxPreload to 3, then 3 links will be in the SSR result and 7 will be appended to the dom on idle callback ?

@wmertens
Copy link
Member Author

wmertens commented Apr 4, 2025

@wmertens how is it going to behaves ? The dev can specify the amount of links to add at SSR time, the framework add them in order of priority, then it adds remaining links on idle callback ? For example if there are 10 links to add and dev set maxPreload to 3, then 3 links will be in the SSR result and 7 will be appended to the dom on idle callback ?

Yes correct, but it adds them as soon as the preloader loads, and we can make it happen at idle time if you see that that works better.

Perhaps I should add query parameters to configure the preload for testing.

In any case I don't think we should wait for the answer to this to merge, we can always refine.

@shairez
Copy link
Contributor

shairez commented Apr 4, 2025

I agree, let's merge it now to start the alpha testing.
@GrandSchtroumpf if you can please run your checks and comparison on the 1.14.0 alpha I'm going to publish in the alpha testers channel, that would be awesome!

Thank you very much! 🙏

@wmertens wmertens merged commit 41cb35e into main Apr 4, 2025
21 checks passed
@wmertens wmertens deleted the dynamic-modulepreload branch April 4, 2025 18:06
@shairez shairez moved this from Backlog to Done in Qwik Development Apr 4, 2025
@github-actions github-actions bot mentioned this pull request Apr 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
COMP: performance This issue is related to a performance problem or bug
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

7 participants