ammo.js icon indicating copy to clipboard operation
ammo.js copied to clipboard

Webpack issues

Open Kruptein opened this issue 3 years ago • 9 comments

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 :(

Kruptein avatar Jun 17 '21 22:06 Kruptein

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.

FX-Wizard avatar Sep 01 '21 12:09 FX-Wizard

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.

Kruptein avatar Sep 01 '21 12:09 Kruptein

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?

kaphula avatar Dec 16 '21 22:12 kaphula

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

Kruptein avatar Dec 16 '21 22:12 Kruptein

That's pretty wild. I will give it a try tomorrow. Thanks for sharing!

kaphula avatar Dec 17 '21 00:12 kaphula

@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.

TheVirtuoid avatar Dec 17 '21 16:12 TheVirtuoid

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

DontMash avatar Aug 03 '22 17:08 DontMash

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.

TheVirtuoid avatar Sep 10 '22 21:09 TheVirtuoid

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
  },

AlvaroHerreroDev avatar Nov 19 '22 19:11 AlvaroHerreroDev