I am lazy loading in my SSR (next.js) site a component that uses babylonjs (and react-babylonjs).
To lazy load I tried both next.js dynamic component
The component gets lazy loaded as soon as you scroll into that part of the page, leveraging Lazy load from: react-lazyload - npm
Reason:
I want to avoid loading beforehand the whole babylonjs library and the 3d model files (to leverage good pagespeed within the SEO world).
Problems:
When I scroll, so lazy loadding triggers, the whole babylonjs’s library (serveral megabytes…) gets imported, tree shaking gets completely ignored and the page stutters as is a gigantic payload.
When the model (a single model made of 4 meshes) is being downloaded (I used react-babylonjs but also I did it imperatively with ImportMeshAsync) the thread seems to be blocked and the page is unresponsive.
What I tried:
I tried to use both and babylonjs’ native ImportMeshAsync to no use, the page blocks and is interactive just when the model is loaded
I tried to rather than importing the destructured methods from @babylonjs/core importing them cherrypicking like: @babylonjs/core/Math/math but still the whole lib gets imported….
What I want to achieve:
Page not being blocked so model to REALLY load async
Lazy loading the tree shaked chunks of babylonjs not the whole lib….
To your first point - if the model is large, there will be some synchronous computation involved (reading the vertex data). Afterwards it should continue async-loading. So the page might be blocked for a few moments, especially if the model is very complex. You can try separating the model to a few smaller ones, but I don’t know what and how you are loading it.
To your second point - To achieve tree shaking you will need to load all from the respective directory and load all side-effect files needed. It is documented here - https://doc.babylonjs.com/divingDeeper/developWithBjs/treeShaking
I don’t know how react-babylonjs loads the framework. This is a question from @brianzinn , but I assume it is built with tree shaking in mind. Avoid loading anything from the package root, load only from the right path.
hi, if you are using react-babylonjs and trying to achieve a high level of tree-shaking then you will be disappointed. all of the types from that library are excluded from that bundle, but the code is generated for each supported class for diffing. that will be fixed in v4 either with dynamic registration via side-effects or having no generated code and losing lots of functionality. There are open issues on the repo and the implementation details are still up in the air. The underlying issue is no way to inspect the scene graph from JSX to tree shake (the renderer uses host elements - not Components).
This next.js dynamic component works, here is an example (click Start Now it will load Babylon, but does not block UI).
The trick to prevent blocking UI when scrolling, is to use a Next.js Preload component, put it somewhere visible on the page before the component requiring babylon, at least a pagefold, so it will preload all resources before users even scroll near the actual component, like this:
/**
* Preload Script for given Route without rendering (only works in Next.js production)
* @param {String} to - pathname of the route to preload scripts for
* @param {Object} [props] - other next Link options
*/
export function Preload ({to, ...props}) {
// Next Link expects a native element with ref, and it has to render as HTML element to trigger preload
return <NextLink href={to} {...props}><i className="hidden-preloader"/></NextLink>
}
You need to make sure you always import directly for all classes, if just one import comes from @babylonj/core the entire lib may get imported. Example:
/* Maths */
export { Color3, Color4, } from '@babylonjs/core/Maths/math.color'
export { Plane, } from '@babylonjs/core/Maths/math.plane'
export { Path3D, } from '@babylonjs/core/Maths/math.path'
Put bundle analyzer in your next.js build to verify, like so:
Like mentioned above, react-babylonjs is no good for tree shaking, I know this from exp. I wrote all wrapper react Components manually for Babylon stuff.
Splitting the codegen until multiple files won’t help with tree-shaking afaik. The issue is those references are all needed because the way the renderer is implemented it needs to be able to handle all of the supported API without knowing what host elements will be in the tree graph. i am considering completely dynamic and losing support for custom handlers, but that is with a redo on diffing and object construction.
I recommend the dynamic import as well - there are a few threads here on that.
Hi guys, I am working together with OT on this project.
Preloading or loading beforehand is not an option as we want to have a good pagespeed insights score and it will be considered “unused javascript”.
I will try to refactor imperactively so that I avoid loading the whole lib and see what happens as as far as I understood is react-babylonjs because of its nature bundling the whole lib (becaus of codegen).
It’s not bundling the whole lib. It’s still tree shaking. I have added some imports for side effects to make it easier to use, but those will be removed in v4 s as well. You can run a bundle analyzer in next. It’s actually not a large bundle compared to the size of many assets. HTH.