Birch-san / box2d-wasm

Box2D physics engine compiled to WebAssembly. Supports TypeScript and ES modules.
274 stars 21 forks source link

not work vitejs #54

Open jonlepage opened 1 year ago

jonlepage commented 1 year ago

image

scott-cornwell commented 1 month ago

It's working for me on Vite (4.3.1) but my setup is a little unconventional. Still may be helpful to Vite users but also people trying to use box2d-wasm in a worker.

My main app is Vite, but I'm building my workers with rollup and bundling them separately into IIFE format. In my worker code that wants to load box2d I have this:

import Box2DFactory from './Box2D.js'

Box2DFactory({
  locateFile: (url, srcDirectory) => {
    return `http://localhost:3000/box2d/${url}`
  }
}).then(box2d => {
  // you now have a box2d instance
})

I have created a public/ directory in my project root, which Vite will serve, then I created box2d folder with Box2D.wasm from box2d-wasm dist folder. I put Box2D.js in the same directory as my worker.

I was getting errors because the emscripten wrapper tries to access document which doesn't exist in a worker. I am wrapping my worker code like this so I can inject dependencies and programmatically get the dependencies it returns, so I just added a way to inject a fake document object that emscripten can get the file path from:

let workerCode = `(function(__dependencies, __document) {
  if (!self.isMainThread) {
    globalThis.document = __document
  }
  let exportObject = ${actualWorkerCode} // string loaded from plain js source file
  return exportObject
})`

// then when I load it I just fetch() the file and indirect eval it, passing in dependencies and the document polyfill:
const documentPolyfill = {
  currentScript: {
    get src() {
      return `http://localhost:3000/box2d`
    },
  },
  baseURI: 'http://localhost:3000/box2d'
}

const workerExports = eval?.(workerCode)(MyCustomModuleLoader.getProvider(), documentPolyfill)

It doesn't actually matter what you put for the URLs in your polyfill. It gets overridden by the locateFile callback you provide, so as long as you set that up correctly it should work. Vite is serving the actual Box2D.wasm and it sends the correct headers automatically for me.

This polyfill shouldn't be necessary, but this code is causing it to be:

var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
var _scriptDir = (_documentCurrentScript && _documentCurrentScript.src || new URL('MyWorker.js', document.baseURI).href);

They check document undefined so it doesn't fail right away, but then later when it has no document script reference they just go ahead and try to access document.baseURI anyway, making it really hard to get this running in a worker. I'm not actually sure if this is emscripten, box2d-wasm or rollup causing it, but hope it helps someone!