ammo.js
ammo.js copied to clipboard
Webpack issues
Hi there, for the last couple of days I've been struggling with getting this js package to work in a bundled fashion. Both with vue-cli (webpack) and vitejs (rollup) I'm having issues getting it to work properly either at build or runtime.
With webpack for example I'm getting:
TypeError: Cannot set property 'Ammo' of undefined
at ammo.js:978
at h.load (diceThrower.js:29)
My own code (diceThrower.js:29) is simply: const ammo = await Ammo();
With the ammo.js error being at the end of the file
(function() {
function a() {
b.BT_CONSTRAINT_ERP = GA();
b.BT_CONSTRAINT_STOP_ERP = HA();
b.BT_CONSTRAINT_CFM = IA();
b.BT_CONSTRAINT_STOP_CFM = JA();
b.PHY_FLOAT = KA();
b.PHY_DOUBLE = LA();
b.PHY_INTEGER = MA();
b.PHY_SHORT = NA();
b.PHY_FIXEDPOINT88 = OA();
b.PHY_UCHAR = PA()
}
Ta ? a() : Ra.unshift(a)
}
)();
this.Ammo = b; // <-- this line
return Ammo.ready
}
);
}
)();
if (typeof exports === 'object' && typeof module === 'object')
module.exports = Ammo;
else if (typeof define === 'function' && define['amd'])
define([], function() {
return Ammo;
});
else if (typeof exports === 'object')
exports["Ammo"] = Ammo;
Is there anyone that has a working example with webpack/rollup or some insights into what I might be doing wrong :(
I've had the same problem. Depending on which version of webpack your using you can try adding this to your webpack config
Webpack 5:
resolve: {
fallback: {
fs: false,
'path': false, // ammo.js seems to also use path
}
}
Webpack 4:
node: {
fs: 'empty'
}
Here's a link to the Babylon.js forums where this issue is discussed more in depth. https://forum.babylonjs.com/t/ammo-js-webpack-issues/2987
I have not been able to find a way to get it working with vite/rollup. If you figure it out please let us know.
For now I've opted for sideloading the ammo.js file manually instead of bundling it with my other dependencies, because I indeed cannot get it to work with vite/rollup.
I am facing the same issue when I try to bundle to library module with Rollup and TypeScript.
@Kruptein How did you "sideload" the ammo.js successfully, or what does this even mean in practice?
While digging around I found some library/framework that was using ammo (I can't recall the name) and it did something like this:
(it's far from ideal, but it does the job)
const loadScriptAsync = (url: string): Promise<void> => {
return new Promise((resolve) => {
const tag = document.createElement("script");
tag.onload = () => {
resolve();
};
tag.onerror = () => {
throw new Error(`failed to load ${url}`);
};
tag.async = true;
tag.src = url;
document.head.appendChild(tag);
});
};
export const loadAmmoModule = async (): Promise<void> => {
// there were some wasm checks here that I never tested out so I don't remember the og source here
// console.log(wasmSupported ? 'WebAssembly is supported' : 'WebAssembly is not supported')
// if (wasmSupported) loadScriptAsync(`${path}/ammo.wasm.js`, () => doneCallback())
await loadScriptAsync("${path}/ammo.js");
};
So basically manually injecting a
That's pretty wild. I will give it a try tomorrow. Thanks for sharing!
@kaphula yes, this does work. It would be far better to find a vite/rollup solution, but for now at least I'm up and running. Thanks for the sleuthing, @Kruptein.
While digging around I found some library/framework that was using ammo (I can't recall the name) and it did something like this:
(it's far from ideal, but it does the job)
const loadScriptAsync = (url: string): Promise<void> => { return new Promise((resolve) => { const tag = document.createElement("script"); tag.onload = () => { resolve(); }; tag.onerror = () => { throw new Error(`failed to load ${url}`); }; tag.async = true; tag.src = url; document.head.appendChild(tag); }); }; export const loadAmmoModule = async (): Promise<void> => { // there were some wasm checks here that I never tested out so I don't remember the og source here // console.log(wasmSupported ? 'WebAssembly is supported' : 'WebAssembly is not supported') // if (wasmSupported) loadScriptAsync(`${path}/ammo.wasm.js`, () => doneCallback()) await loadScriptAsync("${path}/ammo.js"); };
So basically manually injecting a
Credits to: https://github.com/enable3d/enable3d/blob/master/packages/common/src/wasmLoader.ts
Following up on this older post - in case others are having the same problem.
In my application, I am using vite/rollup with BabylonJS / Ammo.js. I am also using the directions on the BabylonJS site for using Ammo.js with the library. In doing so, I get the error mentioned above.
I discovered that I can change my app to this:
// this is suggested code from the BabylonJS site
// OLD (gives error)
import ammo from "ammo.js";
const Ammo = await ammo();
// NEW (removes error)
import ammo from "ammo.js";
const Ammo = await ammo.bind(window)();
By merely binding a new 'this' to the Ammo module, the library loaded correctly.
Hopefully this will help, or at least give you clues in solving your particular issues.
This is what worked for me on an Angular 14 project:
import Ammo from 'ammojs-typed'
export const initPhysics = async (scene: Scene) => {
const ammo = await Ammo.bind(window)();
const physics: AmmoJSPlugin = new AmmoJSPlugin(true, ammo)
scene.enablePhysics(Vector3.Zero(), physics)
}
and
"browser": {
"fs": false,
"path": false
},