Skip to content

Allow asynchronous initialization of Rapier #30

@viridia

Description

@viridia

Right now there are two ways to initialize rapier.js: The 'rapier-compat' package, or (for lack of a better name) the 'vanilla' version.

The reason that rapier-compat exists is to allow use with bundlers that have trouble loading .wasm resources. However, this compatibility comes at a price: the entire .wasm resource is encoded as text. While this works, it is not ideal.

Right now the only bundler (that I know of) that can handle the 'vanilla' version of rapier.js is Webpack 4. Webpack 5 will not work, nor will Snowpack. Rollup uses a strategy similar to rapier-compat, encoding the resource as text. I have not tried Parcel, Vite, or any of the other bundlers, but I imagine they have similar issues.

However, there is a third option, which is to not depend on a bundler encoding at all. This is in fact the recommended option for snowpack, as shown in this guide. This technique loads the .wasm resource directly using the browser fetch API, and then once the promise resolves, it manually bootstraps the JavaScript wrappers around the WASM resource.

However, doing it this way means that the .wasm resource will not be available until after the fetch promise resolves. Unfortunately, the current rapier.js TypeScript code imports the raw bundle as a static resource - that is, it assume that the WASM code is already ready at the time that the JavaScript code is imported. So this option will not work with the current rapier.js code.

To support this use case, it would be necessary to change the way that the rapier.js World object, and the objects within it, are constructed. Instead of statically importing all of the references to WASM classes, these would need to be passed in as part of the constructor call. Possibly it would make sense to define a TypeScript interface which has the same shape to "import * from 'raw'" and pass that object around to each class that is constructed.

Also, a lot of the import { symbol } statements would be changed to import type { symbol } to let the TypeScript compiler know that we're only interested in the type definitions, not the values of the imports. "import type" statements are always removed from the output JavaScript, so this prevents the .wasm resources from being accidentally dereferenced too early.

This is not a huge change, but unfortunately it is a backwards-incompatible one. The strategy proposed here is not that different from the way JavaScript clients use Rapier already - you have to have a handle to the rapier object before you can create a world, rb, collider, or anything else other than the basic math types.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions