V7.19 vite build output changes

Hi! I’m using vite to build my distribution files. Between v7.18 and v7.19, I’m seeing a huge change in the output for babylonjs files only. I’m using @babylonjs/core and @babylonjs/materials.

v7.18 - sample output (redacted blah and file sizes)
folder/thinInstanceMesh-blahblah.js XX.XX kB │ gzip: Y.YY kB

v7.19 - sample output

folder/mainUVVaryingDeclaration-blahblah.js      XX.XX kB │ gzip:   Y.YY kB
folder/defaultUboDeclaration-blahblah.js         XX.XX kB │ gzip:   Y.YY kB
folder/defaultUboDeclaration-blahblah.js         XX.XX kB │ gzip:   Y.YY kB
folder/harmonicsFunctions-blahblah.js            XX.XX kB │ gzip:   Y.YY kB
folder/harmonicsFunctions-blahblah.js            XX.XX kB │ gzip:   Y.YY kB
folder/logDepthDeclaration-blahblah.js           XX.XX kB │ gzip:   Y.YY kB
folder/shadowsVertex-blahblah.js                 XX.XX kB │ gzip:   Y.YY kB
folder/default.vertex-blahblah.js                XX.XX kB │ gzip:   Y.YY kB
folder/default.vertex-blahblah.js                XX.XX kB │ gzip:   Y.YY kB
folder/pbr.vertex-blahblah.js                   XX.XX kB │ gzip:   Y.YY kB
folder/pbr.vertex-blahblah.js                   XX.XX kB │ gzip:   Y.YY kB
folder/default.fragment-blahblah.js             XX.XX kB │ gzip:   Y.YY kB
folder/default.fragment-blahblah.js             XX.XX kB │ gzip:   Y.YY kB
folder/thinInstanceMesh-blahblah.js             XX.XX kB │ gzip:   Y.YY kB
folder/logDepthVertex-blahblah.js               XX.XX kB │ gzip:   Y.YY kB
folder/oitFragment-blahblah.js                  XX.XX kB │ gzip:   Y.YY kB
folder/oitFragment-blahblah.js                 XX.XX kB │ gzip:   Y.YY kB
folder/pbr.fragment-blahblah.js                XX.XX kB │ gzip:   Y.YY kB
folder/pbr.fragment-blahblah.js                XX.XX kB │ gzip:   Y.YY kB

I am getting a huge bunch of double files built and confusing output, do I have to update my build configurations or is there something off in src?

1 Like

Checking that. might also be related to a different topic about vite and the materials.

Sorry, this is related to code splitting we have introduced in 7.19 to support webgpu and webgl shaders. It’s the expected behavior - shaders are now async-loaded when they are needed

Check out the Magic Comments section

webpack seems to be able to combine chunks into one for statements with the same name if you specify webpackChunkName in the import statement.

It’s nice to be able to selectively load wgsl and gsl code, but if all shader files are split into separate files, it can be slow to load with multiple network requests.

This could be improved by combining files that are likely to be requested together into a single chunk.
(For example, the chance of default.vertex and default.fragment being requested at the same time is almost 100%)

webpackChunkName works for webpack. wonderful, but what about any other bundlers? We won’t introduce any bundler-specific code to babylon.

We gave it thought before doing that, of course. The few extra network requests (and a smaller bundle size) are not going to influence performance, and shaders are the only modules that will be “bundled” this way. In your project configuration you can decide to cancel chunks to this specific request (or altogether), or you can simply import them yourself and have them in the main bundle instead of async-load them. the freedom stays with the developer.

1 Like

Webpack seems to unconditionally split chunk when you do an async import. Is there a way to build the js files as one in webpack like bundler?

webpackChunkName is just one way of configuring your imports. You can also configure them using the split chunks plugin - webpack

1 Like

Thank you. It doesn’t seem simple from a user perspective, maybe it would be nice to have documentation on it

No need to apologize, I was just genuinely caught by surprise. You guys are doing a swell job.

I think this is an issue, I’m unsure where the responsibility lies. The file names are identical for wgsl and gsl, alto vite builds the chunk with hash, the likelihood of filename collision is NOT 0 and cannot be guaranteed to be zero. But bjs is differentiating via folder naming only. hmm…

My hacky solution is to customize the location of my built files, this resolves filename collision.

rollupOptions:{
	output:{
		chunkFileNames:(c)=>{
			if (c.moduleIds[0].includes("@babylonjs/core/ShadersWGSL/")){
				return "wgsl/[name]-[hash].js";
			}
			if (c.moduleIds[0].includes("@babylonjs/core/Shaders/")){
				return "glsl/[name]-[hash].js";
			}
			return "[name]-[hash].js";
		}
	}
}

Not very robust, use at your own discretion or as a base for your own customization. Leaving it here for other vite users. Marking as solved, cheers!

2 Likes

I was about to reply the same!

here is how it looks now:

Btw the index.js has grown from 4Mb to 4.6Mb switching from 6.x to 7.x too

Can I assume this is unminified 600KB?

Also wondering how your configuration for the chunks look like. Could it be that you include both webgpu and webgl shaders in the index file?

Hello @RaananW to be honest I didn’t made any change yet, I’ve just updated Babylon and packed it again, is there any guide about how to proceed?

Here is the full import list:

import { ActionManager } from “@babylonjs/core/Actions/actionManager”;

import { ExecuteCodeAction } from “@babylonjs/core/Actions/directActions”;

import { FreeCamera } from “@babylonjs/core/Cameras/freeCamera”;

import { Ray } from “@babylonjs/core/Culling/ray”;

import { Engine } from “@babylonjs/core/Engines/engine”;

import { KeyboardEventTypes } from “@babylonjs/core/Events/keyboardEvents”;

import { PointerEventTypes } from “@babylonjs/core/Events/pointerEvents”;

import { HighlightLayer } from “@babylonjs/core/Layers/highlightLayer”;

import { HemisphericLight } from “@babylonjs/core/Lights/hemisphericLight”;

import { SceneLoader } from “@babylonjs/core/Loading/sceneLoader”;

import { Effect } from “@babylonjs/core/Materials/effect”;

import { ShaderMaterial } from “@babylonjs/core/Materials/shaderMaterial”;

import { StandardMaterial } from “@babylonjs/core/Materials/standardMaterial”;

import { CubeTexture } from “@babylonjs/core/Materials/Textures/cubeTexture”;

import { Texture } from “@babylonjs/core/Materials/Textures/texture”;

import { TextureSampler } from “@babylonjs/core/Materials/Textures/textureSampler”;

import { Matrix } from “@babylonjs/core/Maths”;

import { Axis } from “@babylonjs/core/Maths/math.axis”;

import { Color3 } from “@babylonjs/core/Maths/math.color”;

import { Vector2 } from “@babylonjs/core/Maths/math.vector”;

import { Quaternion } from “@babylonjs/core/Maths/math.vector”;

import { Vector3 } from “@babylonjs/core/Maths/math.vector”;

import { Mesh } from “@babylonjs/core/Meshes/mesh”;

import { MeshBuilder } from “@babylonjs/core/Meshes/meshBuilder”;

import { TransformNode } from “@babylonjs/core/Meshes/transformNode”;

import { AssetsManager } from “@babylonjs/core/Misc/assetsManager”;

import { SmartArray } from “@babylonjs/core/Misc/smartArray”;

import { Tools } from “@babylonjs/core/Misc/tools”;

import { BlurPostProcess } from “@babylonjs/core/PostProcesses/blurPostProcess”;

import { Scene } from “@babylonjs/core/scene”;

import { WebXRState } from “@babylonjs/core/XR”;

import { WebXRExperienceHelper } from “@babylonjs/core/XR/webXRExperienceHelper”;

import { WebXRSessionManager } from “@babylonjs/core/XR/webXRSessionManager”;

import “@babylonjs/core/Helpers/sceneHelpers”;

import “@babylonjs/core/Materials/Node/Blocks”; //polyfill requirement for XR

import “@babylonjs/loaders/glTF/”;

import { ActionManager } from “@babylonjs/core”;

wasn’t asking about the imports, but looking at your list, it seems like you are loading the actionmanager from @babylonjs/code , which will load the entire framework. So you get everything, which makes sense - the framework itself is larger (use-case dependent, of course)

The more interesting thing would be to see your bundler configuration (just like in the message before), to see how you define the chunks.

it seems like you are loading the actionmanager from @babylonjs/code

Yes, my bad! it should be

import { ActionManager } from “@babylonjs/core/Actions/actionManager”;

Do you mean vite config?

import viteCompression from ‘vite-plugin-compression2’

export default {
base: ‘./’,
build: {
//assetsInlineLimit: 2048, // bytes limit
rollupOptions: {
output: {
assetFileNames: [name][extname],
chunkFileNames: [name].js,
entryFileNames: [name].js,
},
},
},
plugins: [
viteCompression({
algorithm: ‘gzip’,
ext: ‘.gz’,
})
],
};

Obviously, I’m open to any improvement!