Hydroper
Hydroper

Reputation: 433

How to use Rapier in TypeScript with ts-node?

The Rapier physics engine written in Rust is exposed to JavaScript by loading the library into a module dynamically. From Getting started:

import('@dimforge/rapier2d').then(RAPIER => {
    ...
});

I need to use the Rapier module to instantiate vectors from outside code from TypeScript and Node.js with ts-node. I'm not sure if the properties matter much since it's all dynamically-typed and TypeScript does structural type checks also, but when invoking new rapier.Vector it could matter.

I created a convenient layer over Rapier's JavaScript bindings (com.hydroper.matter) which uses this internally, leaving their dynamic module at the static lifetime of the JavaScript program:

import * as rapierTypings from "@dimforge/rapier2d/rapier";
import Vector from "../math/Vector";
import { RigidBodyType } from "../RigidBody";

const Rapier = {
    rapier: undefined as (typeof import("@dimforge/rapier2d/rapier") | undefined),

    get(): typeof import("@dimforge/rapier2d/rapier") {
        if (Rapier.rapier === undefined) {
            throw new Error("com.hydroper.matter must be preloaded before use; do so through the asynchronous load() method.");
        }
        return Rapier.rapier;
    },

    ...
};

Now... ts-node is reporting the following issue when I run my terminal application that uses Rapier indirectly:

Error: Cannot find module '@dimforge/rapier2d'
Require stack:
- /fooProject/matter/ts/index.ts
- /fooProject/fooProject-server/ts/car/Car.ts
- /fooProject/fooProject-server/ts/Peer.ts
- /fooProject/fooProject-server/ts/index.ts
- /fooProject/fooProject-server/bin/fooProject-server
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:1077:15)
    at Function.Module._resolveFilename.sharedData.moduleResolveFilenameHook.installedValue [as _resolveFilename] (/fooProject/fooProject-server/node_modules/@cspotcode/source-map-support/source-map-support.js:811:30)
    at Function.Module._load (node:internal/modules/cjs/loader:922:27)
    at Module.require (node:internal/modules/cjs/loader:1143:19)
    at require (node:internal/modules/cjs/helpers:110:18)
    at /fooProject/matter/ts/index.ts:47:21 {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/fooProject/matter/ts/index.ts',
    '/fooProject/fooProject-server/ts/car/Car.ts',
    '/fooProject/fooProject-server/ts/Peer.ts',
    '/fooProject/fooProject-server/ts/index.ts',
    '/fooProject/fooProject-server/bin/fooProject-server'
  ]
}

Relevant code from index.ts:

export async function load(): Promise<void> {
    if (Rapier.rapier !== undefined) {
        return;
    }
    Rapier.rapier = await import("@dimforge/rapier2d");
}

The error is on this import specifically.

Upvotes: 0

Views: 437

Answers (1)

Nomanic
Nomanic

Reputation: 1

So I solved this by adding an import map in the html

<script type="importmap">
      {
        "imports": {
          "@dimforge/rapier2d-compat": "https://cdn.skypack.dev/@dimforge/rapier2d-compat"
        }
      }
</script>

Then in my typescript file

import RAPIER from "@dimforge/rapier2d-compat";

class SetUp {

    static async getRapier() {
        await ((<any>RAPIER).init());
        console.log(`Rapier2D version: ${RAPIER.version()}`);
    };

    static async init() {
        await SetUp.getRapier();
    };
}

//Then just call 
SetUp.init();

This is for when you are NOT using webpack or such like, which I am not.

Upvotes: 0

Related Questions