Problems loading babylon via es modules

Yes, I assume that my library (I’ll verify that soon :slight_smile:) will work without any trouble in the project that already has BabylonJS bundled.
@RaananW I believe it all comes down to importing modules in the browser

But I don’t know why the BabylonJS doesn’t work and some other libraries do. I am unable to check it by myself as I’m not familiar with BabylonJS source code and, as I said before, it’s not that important to me. It came out from the curiosity :raccoon: and I don’t know if you (Raanan) are interested in enabling this feature for the BabylonJS :slight_smile:

of course we are interested in this, and, as i said, it should work with the core library, if it is hosted correctly (though we always come back to the same point when talking about it :slight_smile: ).
There is also a long-standing task for the esm-friendly package that will be 100% supported in browsers.

1 Like

@RaananW @brianzinn I think I got it working at least for my case.
It works when I use the relative path for babylonjs/core like:

import {
  Color3,
  MeshBuilder,
  Quaternion,
  StandardMaterial,
  Vector3,
} from "../node_modules/@babylonjs/core/index.js";

Which for my demo / development is ok.
But in general it comes down to BabylonJS not working with importmaps as it doesn’t work if I try to load it like this:

<script type="importmap">
      {
        "imports": {
          "@babylonjs/core": "https://unpkg.com/@babylonjs/core@5.28.0/index.js"
        }
      }
    </script>

I’m getting ton of CORS errors in the console

Access to script at 'https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrBlockNormalGeometric.js' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
pbr.fragment.js:42          GET https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrBlockNormalGeometric.js net::ERR_FAILED 502
localhost/:1 Access to script at 'https://unpkg.com/@babylonjs/core@5.28.0/Materials/Node/Blocks/Fragment/TBNBlock.js' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
clearCoatBlock.js:11          GET https://unpkg.com/@babylonjs/core@5.28.0/Materials/Node/Blocks/Fragment/TBNBlock.js net::ERR_FAILED 502
localhost/:1 Access to script at 'https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrDebug.js' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
pbr.fragment.js:59          GET https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrDebug.js net::ERR_FAILED 502
localhost/:1 Access to script at 'https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/sceneVertexDeclaration.js' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
shadowMapVertexDeclaration.js:3          GET https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/sceneVertexDeclaration.js net::ERR_FAILED 502
localhost/:1 Access to script at 'https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrBlockNormalFinal.js' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
pbr.fragment.js:44          GET https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrBlockNormalFinal.js net::ERR_FAILED 502
localhost/:1 Access to script at 'https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrBlockClearcoat.js' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
pbr.fragment.js:38          GET https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrBlockClearcoat.js net::ERR_FAILED 502
localhost/:1 Access to script at 'https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrDirectLightingFalloffFunctions.js' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
pbr.fragment.js:23          GET https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrDirectLightingFalloffFunctions.js net::ERR_FAILED 502
localhost/:1 Access to script at 'https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrBlockSheen.js' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
pbr.fragment.js:37          GET https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrBlockSheen.js net::ERR_FAILED 502
localhost/:1 Access to script at 'https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrBlockReflectance0.js' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
pbr.fragment.js:48          GET https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/pbrBlockReflectance0.js net::ERR_FAILED 502
localhost/:1 Access to script at 'https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/geometryVertexDeclaration.js' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
geometry.vertex.js:8          GET https://unpkg.com/@babylonjs/core@5.28.0/Shaders/ShadersInclude/geometryVertexDeclaration.js net::ERR_FAILED 502
localhost/:1 Access to script at 'https://unpkg.com/@babylonjs/core@5.28.0/Compute/computeShader.js' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
index.js:2          GET https://unpkg.com/@babylonjs/core@5.28.0/Compute/computeShader.js net::ERR_FAILED 520

that’s not a babylon issue, it is an issue with unpkg not supporting cors :slight_smile:

If you import directly from the URL (and not using importmap) it will work as expected

1 Like

There is an ESM button on jsDelivr:

image

But the next example doesn’t work: Plunker - ES-module and Babylon.js

Error: BABYLON.Vector3 is not a constructor

    <!-- Import maps polyfill -->
    <!-- Remove this when import maps will be widely supported -->
    <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

    <script type="importmap">
        {
            "imports": {
                "babylonjs": "https://cdn.jsdelivr.net/npm/babylon@6.18.0/+esm"
            }
        }
    </script>

    <script type="module">
        import * as BABYLON from "babylonjs";

        console.log(new BABYLON.Vector3(1, 2, 3));
    </script>

you will want to use the es6 packages (@babylonjs/core) in order to get that to work.

1 Like

You can see an example here - RaananW/babylonjs-esm-in-browser: A simple example of how to use Babylon.js es6 packages directly in your browser. (github.com)

1 Like

I want to use it on Plunker and PlayCode with importmaps.

this repository shows an example of usage with importmaps, and I still recommend you to use @babylonjs/core and not babylonjs (which is UMD-only package)

1 Like

I tried it: Plunker - ES-module and Babylon.js

    <script type="importmap">
        {
            "imports": {
                "babylonjs": "https://cdn.jsdelivr.net/npm/@babylonjs/core@6.3.1/+esm"
            }
        }
    </script>

I took this link here: @babylonjs/core CDN by jsDelivr - A CDN for npm and GitHub

Sorry! It works! Thank you very much!

1 Like

yep, it does. Another recommendation (as in the repo) is not to load from /core, but from the correct directory in the repo. This will load less files.

1 Like

I don’t understand how to do it. In your example above you imported from /core:

    <script type="importmap">
      {
        "imports": {
          "@babylonjs/core": "./@babylonjs/core",
          "@babylonjs/core/": "./@babylonjs/core/",
          "@babylonjs/loaders": "./@babylonjs/loaders",
          "@babylonjs/loaders/": "./@babylonjs/loaders/"
        }
      }
    </script>

P.S. You should add this line of code:

    <!-- Import maps polyfill -->
    <!-- Remove this when import maps will be widely supported -->
    <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

Because import maps isn’t supported on some browsers: Import maps | Can I use... Support tables for HTML5, CSS3, etc

image

image

i’m not sure how cdndeliver does it, but unpck offers the same directory structure as babylon’s core package. so in your code you can import from @babylonjs/core/scene.js (for example), and the importmap settings will take care of converting it to the right URL for you

I understand now. If I need to know what file I need to import I should go here: https://unpkg.com/@babylonjs/core@6.3.1 For example, I need “engine.js” and “scene.js”:

image

image

    <script type="importmap">
        {
            "imports": {
                "Engine": "https://unpkg.com/@babylonjs/core@6.3.1/Engines/index.js",
                "Scene": "https://unpkg.com/@babylonjs/core@6.3.1/scene.js"
            }
        }
    </script>

    <script type="module">
        import { Engine } from "Engine";
        import { Scene } from "Scene";

        const canvas = document.getElementById("renderCanvas");
        const engine = new Engine(canvas, true);
        console.log(engine);
        const scene = new Scene(engine);
        console.log(Scene);
    </script>

But now I have the same problem as @neu5 had in this message: Problems loading babylon via es modules - #23 by neu5

Access to script at 'https://unpkg.com/@babylonjs/core@6.3.1/Engines/WebGPU/webgpuHardwareTexture.js' from origin 'https://run.plnkr.co' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Playground: Plunker - ES-module and Babylon.js

This is what I meant:

Plunker - ES-module and Babylon.js (plnkr.co)

1 Like

Thank you very much!

    <canvas id="renderCanvas"></canvas>

    <!-- Import maps polyfill -->
    <!-- Remove this when import maps will be widely supported -->
    <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

    <script type="importmap">
        {
            "imports": {
                "@babylonjs/core": "https://unpkg.com/@babylonjs/core@6.3.1",
                "@babylonjs/core/": "https://unpkg.com/@babylonjs/core@6.3.1/"
            }
        }
    </script>

    <script type="module">
        import { Engine } from "@babylonjs/core/Engines/engine.js";
        import { Scene } from "@babylonjs/core/scene.js";

        const canvas = document.getElementById("renderCanvas");
        const engine = new Engine(canvas, true);
        console.log(engine);
        const scene = new Scene(engine);
        console.log(Scene);
    </script>
2 Likes

@RaananW How to solve this problem: Uncaught (in promise) ShadowGeneratorSceneComponent needs to be imported before as it contains a side-effect required by your code.

Playground: Plunker - ShadowGeneratorSceneComponent needs to be imported before. Babylon.js, JavaScript

// https://unpkg.com/browse/@babylonjs/core@6.11.1/
import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera.js";
import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight.js";
import { Engine } from "@babylonjs/core/Engines/engine.js";
import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator.js";
import { Scene } from "@babylonjs/core/scene.js";
import { Vector3 } from "@babylonjs/core/Maths/math.vector.js";
import RAPIER from "rapier3d-compat";
import initRapier3D from "./init-rapier3d.js";

async function init() {
    await initRapier3D();
    const canvas = document.getElementById("renderCanvas");
    const engine = new Engine(canvas, true);

    // This creates a basic Babylon Scene object (non-mesh)
    const scene = new Scene(engine);

    // Set Gravity
    const world = new RAPIER.World({ x: 0.0, y: -9.81, z: 0.0});

    // This creates and positions a free camera (non-mesh)
    const camera =  new ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2.5, 15, new Vector3(0, 0, 0), scene);
    camera.setTarget(Vector3.Zero()); // This targets the camera to scene origin
    camera.attachControl(canvas, true); // This attaches the camera to the canvas

    // This creates a light, aiming 0,1,0 - to the sky (non-mesh)
    const light = new DirectionalLight("Light", new Vector3(0, -8, 2), scene);
    light.intensity = 0.7; // Default intensity is 1. Let's dim the light a small amount

    const shadowGen = new ShadowGenerator(1024, light);
    console.log(shadowGen);
}

init();
<!DOCTYPE html>

<html>

<head>
    <meta charset="utf-8">
    <title>Example</title>
</head>

<body style="caret-color: transparent;">
    <canvas id="renderCanvas" width="400" height="400"></canvas>

    <!-- Since import maps are not yet supported by all browsers, its is
        necessary to add the polyfill es-module-shims.js -->
    <script async src="https://unpkg.com/es-module-shims@1.7.3/dist/es-module-shims.js"></script>

    <script type="importmap">
        {
            "imports": {
                "@babylonjs/core": "https://unpkg.com/@babylonjs/core@6.11.1",
                "@babylonjs/core/": "https://unpkg.com/@babylonjs/core@6.11.1/",
                "rapier3d-compat": "https://cdn.jsdelivr.net/npm/@dimforge/rapier3d-compat@0.11.2/+esm"
            }
        }
    </script>

    <script type="module" src="./js/index.js"></script>
</body>

</html>

init-rapier3d.js

import rapier from "rapier3d-compat";

export default function initRapier3D() {
    return new Promise(resolve => {
        rapier.init().then(() => {
            resolve();
        });
    });
}

I created the issue: Uncaught StandardMaterial needs to be imported before as it contains a side-effect required by your code · Issue #14034 · BabylonJS/Babylon.js · GitHub

The minimal example demonstrating the problem. Error message: Uncaught StandardMaterial needs to be imported before as it contains a side-effect required by your code

<!DOCTYPE html>

<html>

<head>
    <meta charset="utf-8">
    <title>Example</title>
</head>

<body>
    <canvas id="renderCanvas" width="400" height="400"></canvas>

    <!-- Since import maps are not yet supported by all browsers, its is
        necessary to add the polyfill es-module-shims.js -->
    <script async src="https://unpkg.com/es-module-shims@1.7.3/dist/es-module-shims.js"></script>

    <script type="importmap">
        {
            "imports": {
                "@babylonjs/core": "https://unpkg.com/@babylonjs/core@6.11.1",
                "@babylonjs/core/": "https://unpkg.com/@babylonjs/core@6.11.1/"
            }
        }
    </script>

    <script type="module">
        import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera.js";
        import { Engine } from "@babylonjs/core/Engines/engine.js";
        import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder.js";
        import { Scene } from "@babylonjs/core/scene.js";
        import { Vector3 } from "@babylonjs/core/Maths/math.vector.js";

        const canvas = document.getElementById("renderCanvas");
        const engine = new Engine(canvas, true);

        const scene = new Scene(engine);
        const sphere = MeshBuilder.CreateSphere("Sphere", { diameter: 2, segments: 32 }, scene);

        const camera = new ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2.5, 15, new Vector3(0, 0, 0), scene);
        camera.setTarget(Vector3.Zero());
        camera.attachControl(canvas, true);

        engine.runRenderLoop(() => {
            scene.render();
        });
    </script>
</body>

</html>

Added

I’m sorry. That’s my fault. I had to import:

import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial.js";
<!DOCTYPE html>

<html>

<head>
    <meta charset="utf-8">
    <title>Example</title>
</head>

<body>
    <ul>
        <li><a href="https://github.com/BabylonJS/Babylon.js/issues/14034">Issue</a>
        <li><a href="https://forum.babylonjs.com/t/problems-loading-babylon-via-es-modules/2031/39?u=8observer8">Topic</a>
    </ul>
    <br>
    <br>
    <canvas id="renderCanvas" width="400" height="400"></canvas>

    <!-- Since import maps are not yet supported by all browsers, its is
        necessary to add the polyfill es-module-shims.js -->
    <script async src="https://unpkg.com/es-module-shims@1.7.3/dist/es-module-shims.js"></script>

    <script type="importmap">
        {
            "imports": {
                "@babylonjs/core": "https://unpkg.com/@babylonjs/core@6.11.1",
                "@babylonjs/core/": "https://unpkg.com/@babylonjs/core@6.11.1/"
            }
        }
    </script>

    <script type="module">
        import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera.js";
        import { Engine } from "@babylonjs/core/Engines/engine.js";
        import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder.js";
        import { Scene } from "@babylonjs/core/scene.js";
        import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial.js";
        import { Vector3 } from "@babylonjs/core/Maths/math.vector.js";

        const canvas = document.getElementById("renderCanvas");
        const engine = new Engine(canvas, true);

        const scene = new Scene(engine);
        const sphere = MeshBuilder.CreateSphere("Sphere", { diameter: 2, segments: 32 }, scene);

        const camera = new ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2.5, 15, new Vector3(0, 0, 0), scene);
        camera.setTarget(Vector3.Zero());
        camera.attachControl(canvas, true);

        engine.runRenderLoop(() => {
            scene.render();
        });
    </script>
</body>

</html>

Here Babylon.js ES6 support with Tree Shaking | Babylon.js Documentation
explain why do you need that material
and for the shadow, you may need

import "@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent";
2 Likes