Astro + Vite Failing to Resolve Scoped Package `@babylonjs/core`

Hello,

I’m encountering a problem in my Astro project where Vite fails to resolve the scoped package @babylonjs/core during development. While TypeScript successfully recognizes the module, the browser returns the following error:

Uncaught TypeError: Failed to resolve module specifier '@babylonjs/core'

If I switch the import to a relative path like /node_modules/@babylonjs/core, the issue disappears, but this workaround is not ideal for my project setup. I’ve already confirmed that Vite is handling other libraries like P5, D3, and THREE correctly through CDN imports, but I would like to bundle BabylonJS.

Project Link:

Here’s my project for reference: GitHub Repository.

Steps I Have Taken:

  1. I have tried aliasing the path in both astro.config.mjs and tsconfig.json.
  2. I included @babylonjs/core in the optimizeDeps and ssr settings.
  3. I cleared Vite’s cache and re-installed the dependencies using pnpm install --shamefully-hoist.
  4. I tried importing the module using relative paths, which works but isn’t an acceptable long-term solution.

Configurations:

I would appreciate any guidance or advice on resolving this issue, particularly from those familiar with using Astro and Vite with scoped packages like @babylonjs/core. I’m also reaching out to the Astro Discord community, but any additional help here would be invaluable.

Thank you for your time!

1 Like

Can we see all your configs with these two included? It should work.

Configuration Details:

1. tsconfig.json

{
  "extends": "astro/tsconfigs/strict",
  "compilerOptions": {
    "noEmit": false,
    "emitDeclarationOnly": false,
    "moduleResolution": "node",
    "declaration": false,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "allowImportingTsExtensions": false,
    "baseUrl": ".",
    "paths": {
      "@SketchWrapper": ["src/components/SketchWrapper.astro"],
      //"@babylonjs/*": ["node_modules/@babylonjs/*"]
    },
    "lib": ["dom", "ESNEXT"]
  },
  "include": ["**/*.astro, src/**/*.ts"],
  "exclude": ["node_modules", "dist"]
}

2. astro.config.mjs

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';

export default defineConfig({
  integrations: [mdx()],
  vite: {
    optimizeDeps: {
      //include: ["@babylonjs/core"]
    },
    ssr: {
      //noExternal: ["@babylonjs/core"]
    },
    resolve: {
      alias: {
        //"@babylonjs/core": "/node_modules/@babylonjs/core"
      }
    }
  }
});

3. package.json

{
  "dependencies": {
    "@astrojs/mdx": "^3.1.8",
    "@picocss/pico": "^2.0.6",
    "astro": "^4.16.5"
  },
  "devDependencies": {
    "@babylonjs/core": "^7.30.0",
    "three": "^0.169.0",
    "typescript": "^5.6.3"
  }
}

4. SketchWrapper.astro

---
const libraryImports = {
  p5: "https://cdn.jsdelivr.net/npm/p5@1.11.0/+esm?name=p5",
  d3: "https://cdn.jsdelivr.net/npm/d3@7.9.0/+esm?name=d3",
  three: "https://cdn.jsdelivr.net/npm/three@0.169.0/+esm?name=three",
  //babylonjs: '/node_modules/@babylonjs/core'
  babylonjs: '@babylonjs/core'
};
---

<script type="module">
  const importLibrary = async () => {
    const BABYLON = await import(libraryImports.babylonjs);
    window.BABYLON = BABYLON;
  };
  await importLibrary();
</script>

Obviously, sry, it’s already 1:49AM here :rofl:

1 Like

Also…here is the built in Astro tsconfig, which my file extends. Thanks for taking the time to help!

base.json

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    // Enable top-level await, and other modern ESM features.
    "target": "ESNext",
    "module": "ESNext",
    // Enable module resolution without file extensions on relative paths, for things like npm package imports.
    "moduleResolution": "Bundler",
    // Allow importing TypeScript files using their native extension (.ts(x)).
    "allowImportingTsExtensions": true,
    // Enable JSON imports.
    "resolveJsonModule": true,
    // Enforce the usage of type-only imports when needed, which helps avoiding bundling issues.
    "verbatimModuleSyntax": true,
    // Ensure that each file can be transpiled without relying on other imports.
    // This is redundant with the previous option, however it ensures that it's on even if someone disable `verbatimModuleSyntax`
    "isolatedModules": true,
    // Astro directly run TypeScript code, no transpilation needed.
    "noEmit": true,
    // Report an error when importing a file using a casing different from another import of the same file.
    "forceConsistentCasingInFileNames": true,
    // Properly support importing CJS modules in ESM
    "esModuleInterop": true,
    // Skip typechecking libraries and .d.ts files
    "skipLibCheck": true,
    // Allow JavaScript files to be imported
    "allowJs": true,
    // Allow JSX files (or files that are internally considered JSX, like Astro files) to be imported inside `.js` and `.ts` files.
    "jsx": "preserve"
  }
}

strict.json

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./base.json",
  "compilerOptions": {
    // Enable strict mode. This enables a few options at a time, see https://www.typescriptlang.org/tsconfig#strict for a list.
    "strict": true
  }
}
1 Like

No error here.

EDIT: sry, the error is in the console

1 Like

I should have better explained that, when hitting F12 with the browser tools, here is the error:

which takes me here:

1 Like

Yep, I already got it :wink:

1 Like

my post got flagged as spam, not sure why, any way to un-flag it? i edited like recommended, but still flagged.

@sebavan Deltakosh @Evgeni_Popov anyone to help with the Spam flag?

1 Like

I believe this could help you:

I think this would be an acceptable solution:

or you could use UMD.

Btw. you have the babylon.js packages defined in the devDependecies section.

If this doesn’t help let’s ask & summon @RaananW, the master of packages.

1 Like

I don’t see any posts marked as “spam” in this thread? Is everything okay now (as far as spam is concerned)?

The original post was marked as spam for a while. Now it seems to be ok. Thanks!

1 Like

@RaananW - at the advice of @roland, do you think you could help with this one? It looks like UMD is a different direction than what I’m trying to do, which is use Vite because its part of Astro.

2 Likes

Hey!
Of course, I was looking for a reason to sharpen my Astro skills.
I will find time later today/tomorrow to go over this and see what’s going on.

Oh, and - UMD is not the solution. Let’s find a better one :slight_smile:

3 Likes

Hi @RaananW thanks for taking a look. I tried again this week, and I still can’t get the Babylon modules to work as scoped packages. It’s up on GitHub pages now though:

Here is the current page with Babylon.js referenced:
https://rdthree.github.io/astro-rd3-sketchbook/240818-p5js-d3-three-ts-test/

The wrapper file I use to reference libraries:

1 Like

I am very confused as to why this entire wrapper is needed. I just pulled the project but couldn’t really understand how to reproduce this.

Babylon does not export the namespace BABYLON (as you write in the types.ts file), nor does it expect you to use the BABYLON namespace. It does expect you to use Babylon as an esm module, importing what you need from where you need it.

I am not entirely familiar with Astro, though it does look quite straight forward. especially if it is built with Vite (and therefore rollup), you shoul dbe able to bundle the @babylonjs/core library into your code without using a CDN or the module loading script you added in the .astro file.

I mean - if you just add this:

import { Engine } from '/node_modules/@babylonjs/core';
console.log(Engine);

To the script tag you added you will see it is working as expected. Not sure why Vite doesn’t recognize it as an npm package, but that must be some configuration issue with Astro (which I haven’t found a solution for yet :slight_smile: )

1 Like

Thanks! You put me back on the right track, it was indeed an Astro-specific issue. Wouldn’t you know it that the thing that works for 99% of Astro users, did not work for my setup.

As it turns out because I’m writing my site with MDX files, the babylon.js sketches are dynamically loaded and specific to each page. Astro’s built-in script handling forces inline scripts when passing variables like filenames or paths, which breaks Vite’s module bundling capabilities. (Scripts and Event Handling | Docs)

As a workaround, Astro makes it easy to use React as middleware, which avoids this limitation , allowing Vite to properly bundle the scripts and modules.

Now it works both in dev mode and in build-preview mode, and the final problem to solve is how to set this thing up so it works both in build mode and also on gh-pages, which have a sub-path issue to deal with.

https://github.com/rdthree/astro-rd3-sketchbook/blob/master/src/components/SketchLoader.jsx

https://github.com/rdthree/astro-rd3-sketchbook/blob/master/src/content/sketches/241029%20Sketches%20with%20ES%20Modules%20in%20Astro/sketch.mdx

https://github.com/rdthree/astro-rd3-sketchbook/blob/master/src/content/sketches/241029%20Sketches%20with%20ES%20Modules%20in%20Astro/babylontest.ts

Appreciate the help @RaananW and @roland

3 Likes