Is it possible to use Inspector as an external js library in ES6 app?

My app is ES6 tree-shaking app and when I import inspector there it increases my bundle too much. From 5mb to 38mb just because of Inspector. And my build time increases from 1.5sec to 12sec. So I decided to use Inspector as a external library like this:

const script = document.createElement( "script" );
script.src = "https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js";
document.head.appendChild( script );

;( BABYLON as any ).Inspector.Show( scene, {} );
// or:
scene.debugLayer.show( {} );

But it failed:

Uncaught TypeError: Cannot read properties of undefined (reading 'Debug')
    at babylon.inspector.bundle.js:2:772
    at babylon.inspector.bundle.js:2:823

Whatā€™s the Debug it waits for?
Is it possible to use Inspector in this way?

Are you using vite? If so, try the following code:

// vite.config.ts
import { loadEnv, type ConfigEnv, type UserConfigExport } from 'vite'

export default (configEnv: ConfigEnv): UserConfigExport => {
    const viteEnv = loadEnv(configEnv.mode, process.cwd()) as ImportMetaEnv
    const { VITE_PUBLIC_PATH } = viteEnv
    return {
        base: VITE_PUBLIC_PATH,
        build: {
            rollupOptions: {
                output: {
                    "babylonjs-core": ["@babylonjs/core"],
                    "babylonjs-materials": ["@babylonjs/materials"],
                    "babylonjs-loaders": ["@babylonjs/loaders"],
                    "babylonjs-post-processes": ["@babylonjs/post-processes"],
                    "babylonjs-procedural-textures": ["@babylonjs/procedural-textures"],
                    "babylonjs-serializers": ["@babylonjs/serializers"],
                    "babylonjs-gui": ["@babylonjs/gui"],
                    "babylonjs-inspector": ["@babylonjs/inspector"],
                    "babylonjs-havok": ["@babylonjs/havok"]
                }
            }
        },
        optimizeDeps: {
            exclude: ['@babylonjs/havok'],
        }
    }
}
// debug.ts
import "@babylonjs/core/Legacy/legacy"
import "@babylonjs/core/Debug/debugLayer"
import "@babylonjs/inspector"
// main.ts
import("./debug.ts").then(() => {
    scene.debugLayer.show({
        overlay: true,
        showExplorer: true,
        showInspector: true,
        embedMode: false,
        handleResize: true,
        enablePopup: true,
        enableClose: true
    })
}

Edited this on my phone on my way home from work, so please point out any formatting and spelling errors!

3 Likes

Hm, as far as I understand, these debug imports also will be included in a final build? Or not? I donā€™t know how to load DebugLayer externally as I think Inspector doesnā€™t create it by yourself :grinning:

Importing legacy adds +12mb to my webpack bundle.

As @gsw945 mentionned, this is what I use in my projects:

first a debug file: BabylonjsInkSample/src/debug/appDebug.ts at master Ā· sebavan/BabylonjsInkSample Ā· GitHub

and a dynamic import into it (to enable efficient code splitting):

Maybe thereā€™s some problem with my Webpack config but this dynamic import imports all the ā€œdebug.tsā€ imports on bundling stage. So I have included all the imports in my bundle uncluding dynamic imports content.

But I think itā€™s a correct behaviour. If you will not add all the contents of Inspector module in the bundle, then from where you will load it when you will call a dynamic import? :smile:

My idea was to load Inspector after bundling stage to avoid including its contents in a bundle.

this would be important in your tsconfig
image

I have this option exactly like this. Well it looks like I should move my webpack config to split chunks I think :smile: as it bundles all what it can bundle too aggressively :smile:

But anyway, I think it will bundle it but as a separate file. But it will also waste the building time during bundling stage. Maybe it could be possible to turn on some cache to not rebuild Inspector files and others that was not changed.

1 Like

Tried to use your Vite config but Vite gives me a warning about output names:

Unknown output options: babylonjs-core, babylonjs-materials, babylonjs-loaders, babylonjs-post-processes, babylonjs-procedural-textures, babylonjs-serializers, babylonjs-gui, babylonjs-inspector, babylonjs-havok. Allowed options: amd, assetFileNames, banner, chunkFileNames, compact, dir, dynamicImportInCjs, entryFileNames, esModule, experimentalMinChunkSize, exports, extend, externalImportAssertions, externalImportAttributes, externalLiveBindings, file, footer, format, freeze, generatedCode, globals, hashCharacters, hoistTransitiveImports, importAttributesKey, indent, inlineDynamicImports, interop, intro, manualChunks, minifyInternalExports, name, noConflict, outro, paths, plugins, preserveModules, preserveModulesRoot, reexportProtoFromExternal, sanitizeFileName, sourcemap, sourcemapBaseUrl, sourcemapDebugIds, sourcemapExcludeSources, sourcemapFile, sourcemapFileNames, sourcemapIgnoreList, sourcemapPathTransform, strict, systemNullSetters, validate, virtualDirname

Am I missing something?

The main principle is that the build is divided into different chunk files and the inspector dynamically import() only when needed.
Later I will create a git repository with a full example.

1 Like

That would be really helpful.

Demo( GitHub Pages) is Ready: Babylonjs Dynamic Inspector

Please toggle Debug enable to load and view inspector

Source Repo as below:

2 Likes

The repository code is stripped from my private project, refactored to match the completeness of the demo, and all Chinese comments are translated to English using DeepL.

So please take what you need and ignore the code you donā€™t need.

1 Like

Could you please tell me, is it needs to do tsc before vite build? I thought Vite works without tsc but after looking into your repo I see that npm build there looks like this tsc && vite build.

The packages.json was automatically generated when creating the project via pnpm create vite bbl-inspector-demo ---template vanilla-ts, and I didnā€™t make any special modifications, except for adding packages.

Hereā€™s an explanation of why thereā€™s a tsc before vite build: Should Vite do type-checking on builds by defaults? (Why `tsc -b && vite build` instead of just `vite build`) Ā· vitejs/vite Ā· Discussion #18543 Ā· GitHub

My personal understanding is that tsc is there to do typescript compilation checking, to eliminate typescript compilation errors before build.
If you remove tsc, vite build should still work.

tsc, the TypeScript compiler

1 Like

First of all, I thank you for HUGE knowledge for me. Thatā€™s so much new highly useful information. Thanks a lot!

Just tried to install all the packages and call vite build:

[I] bbl-inspector-demo|main āž¤ vite build
vite v6.0.11 building for production...
āœ“ 2085 modules transformed.
dist/index.html                                  1.60 kB
dist/assets/HavokPhysics-CjZXfFYQ.wasm       2,097.08 kB
dist/assets/index-CYAhd4I_.css                   6.33 kB
dist/assets/debug-CP0n70AZ.js                    0.39 kB
dist/assets/screenfull-DmVOzVZz.js               1.85 kB
dist/assets/neodrag-BCRXwOkg.js                  5.53 kB
dist/assets/index-D3EsHLC0.js                    6.00 kB
dist/assets/simple-notify-CxyQiKTK.js           10.03 kB
dist/assets/lil-gui-BjijGF_O.js                 31.13 kB
dist/assets/babylonjs-havok-2rBdoeXY.js         39.71 kB
dist/assets/babylonjs-gui-mZNDGpUK.js          555.40 kB
dist/assets/babylonjs-inspector-DAIQE9yj.js  5,108.19 kB
dist/assets/babylonjs-core-BI4ACCnv.js       5,590.73 kB

(!) Some chunks are larger than 2048 kB after minification. Consider:
- Using dynamic import() to code-split the application
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
āœ“ built in 38.25s

It looks the bundler exports all the babylon-core engine? Or is it not the whole core package? Is it correct behaviour or maybe I do something wrong?

cc @RaananW in case he has an idea ?

I will be very happy to analyze a repro, if possible! Can you share a project reproduction of the issue that I can run locally?

Well, I donā€™t have a repro but it simly calling this code by a click some keyboard key:

const script = document.createElement( "script" );
script.src = "https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js";
document.head.appendChild( script );

setInterval( () => {
  scene.debugLayer.show( {} );
  // or:
  ;( BABYLON as any ).Inspector.Show( scene, {} );
}, 2000 ); // it doesn't matter as appendChild should be synchronized

Both cases lead to:

Uncaught TypeError: Cannot read properties of undefined (reading ā€˜Debugā€™)
at babylon.inspector.bundle.js:2:772
at babylon.inspector.bundle.js:2:823

A project is pure ES6, with ES6-imports. Also I tried to import all the debug package:

import "@babylonjs/core/Debug"

but it leads to the same error.

I just wanted to load Inspector separately (on-demand), without bundling in as it weights too much.

This package of the inspector is meant for the UMD (or CDN-based) Babylon packages distribution. If you want to load it on demand in a project using the es6 packages you will need to do something like this:

         void Promise.all([
             import("@babylonjs/core/Debug/debugLayer"),
             import("@babylonjs/inspector"),
         ]).then((_values) => {
             scene.debugLayer.show({
                 handleResize: true,
                 overlay: true,
                 globalRoot: document.getElementById("#root") || undefined,
             });
         });

Yaeh, sure, but it doesnā€™t help as in this way a bundler (Webpack) will bundle all those imports in the final bundle which is too heavy operation when it comes to Inspector. As it adds about +40mb to a 4mb bundle size in case of Webpack without chunks (single bundle file). Thatā€™s why I tried to load Inspector separately after my build will run.