Inspector v2 not importing properly when using Vite in dev mode

When using Vite as the build and development tool, the inspector seems to have problems loading. I’ve created a repository to demo the issue:

The error occurs at the time of import. In my example, I am simply doing import('@babylonjs/inspector') and it fails at that point. The error also seems to vary depending on whether BabylonJS modules are listed in Vite’s config optimizeDeps.exclude or not. When not excluded, this error appears:

init_thinInstanceMesh is not a function

When excluded, this error appears:

The requested module ‘/node_modules/react/index.js?v=5e6cea53’ does not provide an export named ‘Fragment’

The latter seems to be related to JSX, but even specifying "jsx": "react-jsx" in tsconfig.json doesn’t seem to do anything. Amusingly, it seems to work properly when using build mode, but that’s likely because Vite’s toolchain is different in dev mode vs in build mode.

Has this been encountered by anyone else? Is there something I am missing in my configuration to allow inspector v2 to work in dev mode when using Vite?

(There was a similar issue that was causing build problems related to incorrect import definitions not too long ago, but this was fixed in #18230.)

Since it works in production, the main reason is Vite pre-bundling.

When Vite pre-bundles @babylonjs/inspector during dev mode, two problems occurs in your setup:

init_thinInstanceMesh is not a function - This happens when Babylon.js core modules are pre-bundled. The pre-bundling process can break internal function references that the Inspector relies on.

React Fragment export error - When you exclude Babylon modules from pre-bundling, the Inspector’s React dependencies aren’t properly resolved, causing JSX-related export errors.

These issues don’t appear in production builds because Vite uses Rollup for bundling, which handles dependencies differently than the development server’s esbuild-based pre-bundling.

There are different ways to solve this but their usage may depend on your further setup. You may have a look how it is done in this Babylon-Vite template - GitHub - eldinor/bp900: Babylon.js 9 + Vite 8 Typescript 6 Template with Havok Physics, GLB loading and GUI / React, Vue, Svelte · GitHub

To call Inspector press Shift+Alt+Ctrl+I.

i know you say this does not happen in production but it still feels off to me , im not personally dealing with these problems but Im simply speaking from the perspective of being a developer , that uses vite , and uses all sorts of tools and modules under the sun and so far , never having libraries or modules “not work” because its dev mode and not production.

That is my perspective of what feels off about the “reasons” why. They dont site right , it feels like this is a babylon issue that needs to be addressed? You seem to have good knowledge of what is going wrong, The question is , is this solvable at a framework/engine level? or is it expected that end users have to jump through hoops to make it work in development mode?

The matter is that the resolving of this issue depends on a bundler and its settings.

There may be other issues, for example, if one uses Webpack instead of Vite/Rollup.

That said, there shouldn’t be any issues when setttings are correct.

The repo at GitHub - kv-bh/babylon-inspector-test · GitHub is quite non-usual setup which also has some default port issues. Anyway, here is the corrected vite.config.mjs


import {defineConfig} from 'vite';

import {resolve} from 'node:path';




export default defineConfig(({mode}) => ({

  root: resolve('.'),

  cacheDir: resolve(mode === 'optimized' ? 'temp/optimized' : 'temp/default'),

  base: './',

  server: {

    hmr: false,

    host: '0.0.0.0',

    port: 9000 + (mode === 'optimized' ? 2 : 1),

    strictPort: true,

    open: true,

    fs: {

      strict: true,

    },

  },

  optimizeDeps: {

    force: true,

    include: [

      'react',

      'react-dom',

      'react-dom/client',

      'react-dom/server',

      'react/jsx-runtime',

      'react/jsx-dev-runtime',

      'scheduler',

      'use-sync-external-store/shim',

      'use-sync-external-store/shim/with-selector',

    ],

    exclude: mode === 'optimized' ? [] : [

      '@babylonjs/addons',

      '@babylonjs/core',

      '@babylonjs/gui',

      '@babylonjs/gui-editor',

      '@babylonjs/inspector',

      '@babylonjs/ktx2decoder',

      '@babylonjs/loaders',

      '@babylonjs/materials',

      '@babylonjs/post-processes',

      '@babylonjs/procedural-textures',

      '@babylonjs/serializers',

      'babylonjs-gltf2interface',

    ],

  },

  build: {

    outDir: resolve('temp/build'),

    emptyOutDir: true,

    minify: false,

    modulePreload: false,

    rollupOptions: {

      input: [

        resolve('index.html'),

      ],

      output: {

        entryFileNames: 'js/[name].js',

      },

    },

  },

}));

Currently for some reasons there are 2 Vite instances in dev mode.
With these changes the server at 9001 will work; server at 9002 will give error. It can be cured with proper port assigning.
Still I would recommend less exotic setup, like just npm create vite@latestor the recent npm create babylonjs - Babylon.js docs

cc @ryantrem

The only reason that there are two servers is to demonstrate two different Vite configs - one with optimizations and one without - and how that causes two different errors to appear.

I’ve created a few branches to test some environment variations and my findings are below. Note that for each environment I ran using two test configurations:

  • Test server with port=9001 uses optimizeDeps.exclude=[babylonjs...]
  • Test server with port=9002 uses optimizeDeps.exclude=[] (empty)

Vite 8:

  • port=9001: doesn’t work
  • port=9002: doesn’t work

Vite 8, with includes:

  • port=9001: works
  • port=9002: doesn’t work

Vite 6:

  • port=9001: doesn’t work
  • port=9002: works

Vite 6, with includes:

  • port=9001: works
  • port=9002: works

What I gather from this is that Vite 8 breaks things somehow. Running npm create babylonjs uses vite@^6.0.0, which does work if optimizeDeps.exclude is empty or omitted. However, updating to Vite 8 and trying to load the inspector results in the errors I described in the OP.

The optimizeDeps.include values added in labris’s post do seem to fix the issue when using optimizeDeps.exclude=[babylonjs...] in both version of Vite.


This is maybe a separate issue, but the reason why I had been using optimizeDeps.exclude to exclude BabylonJS was to prevent an issue where I think multiple versions of BJS were being loaded and causing conflicts. This seemed to be due to BabylonJS not pinning/limiting dependency versions, resulting in sub-dependencies installing newer versions than whatever version of @babylonjs/core was installed.

Example: @babylonjs/inspector@9.4.1 depends on @babylonjs/*@^9.0.0, which can pull in a version newer than 9.4.1 if one is available at the time of install.

Investigating more, I suspect the init_thinInstanceMesh issue is due to some side-effect imports not being performed in the inspector code. I’ve created another minimal reproduction starting from npm create babylonjs to reproduce the error and subsequently fix it - here is a link to the repo branch. The initial commit is the result of the npm create command, and each subsequent commit makes a small change until I was able to reproduce the error. I ran using npx vite --force to ensure the cache was cleared every run.

The fix seems to be to import the side effects from these two files:

import "@babylonjs/core/Meshes/thinInstanceMesh";
import "@babylonjs/core/Materials/Textures/baseTexture.polynomial";

I agree that with Vite 8 the whole setup with Inspector is more complicated than with Vite 6.

Probably there is a need to add some recommended examples to the Inspector docs.
cc @ryantrem

Thanks for the very thorough investigation, @kvbh — and for narrowing it down to the missing side-effect imports.

I dug into it more as well and it appears to be a Vite 8 / Rolldown dep-optimizer bug, not a Babylon source issue. I confirmed babylonjs/core@9.4.1 is essentially DAG-clean (only one tiny vestigial side-effect import that I’ll clean up separately, but removing it doesn’t fix the symptom). Inspecting Vite’s prebundle output shows that Rolldown’s chunk splitter is creating a circular chunk dependency: the inspector’s main chunk wraps thinInstanceMesh’s evaluation in an __esmMin(...) lazy init and exports it as init_thinInstanceMesh. A sibling chunk (gaussianSplattingMesh-*.js) imports that init back from the main chunk and calls it at top-level. The two chunks form an ESM cycle, so the sibling chunk evaluates while the main chunk’s var init_thinInstanceMesh = __esmMin(...) isn’t defined yet — hence init_thinInstanceMesh is not a function. Vite 6 used esbuild for the dep optimizer and chunked things differently, which is why Vite 6 worked and Vite 8 doesn’t, exactly matching what you observed.

I filed an upstream Vite issue with the analysis and a pointer to your repro: [Vite 8 / Rolldown] Cross-chunk `init_*` binding undefined when prebundled package contains side-effect prototype-augmenting modules · Issue #22341 · vitejs/vite · GitHub

Until that’s fixed upstream, the cleanest workaround that doesn’t require touching app code is to ask Vite to pre-bundle the affected side-effect modules as their own entries:

 // vite.config.ts
 import { defineConfig } from "vite";
 
 export default defineConfig({
     optimizeDeps: {
         include: [
             "@babylonjs/core/Meshes/thinInstanceMesh",
             "@babylonjs/core/Materials/Textures/baseTexture.polynomial",
         ],
     },
 });

I confirmed this works against Vite 8 + a fresh app + a local build of @babylonjs/inspector@9.4.1. If you also want to keep @babylonjs/* in optimizeDeps.exclude, you’ll additionally need @labris’s React-side optimizeDeps.include list.

Thank you all for looking into this and figuring out where the underlying issue is coming from and for providing some workarounds. I should be able to work with all of the info that has been provided here. I also just want to give a shout out of praise for how helpful and quick the responses are from the contributors here are, it’s a breath of fresh air compared to some other things I’ve worked with.

Thanks!