[Canonical page](<https://docs.dhtmlx.com/planning-engine/wasm/javascript/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Use from JavaScript

The `plen-wasm` package also ships the same [`Project`](https://docs.dhtmlx.com/wr/api/project) API as the [JavaScript library](https://docs.dhtmlx.com/wr/), running on the WebAssembly core. This page shows how to load that API in the browser and in Node, and what's different from the JavaScript library.

## Raw surface or glue

The package has two layers:

- **Glue**, the package entry. It gives you a [`Project`](https://docs.dhtmlx.com/wr/api/project) class, [`schedule`](https://docs.dhtmlx.com/wr/api/schedule), the typed [`InputError`](https://docs.dhtmlx.com/wr/api/types/errors#inputerror) and [`ProjectError`](https://docs.dhtmlx.com/wr/api/types/errors#projecterror), and optional [`Date` conversion](https://docs.dhtmlx.com/wr/plain-objects-and-dates). It takes plain objects, not JSON text. Use it in browser and Node apps.
- **Raw exports**, [`JsonProject`](<https://docs.dhtmlx.com/planning-engine/wasm/api/json-project.md>) and [`schedule`](<https://docs.dhtmlx.com/planning-engine/wasm/api/schedule.md>) from the generated `pkg/` and `pkg-node/` files. They take JSON strings and return a [JSON envelope](<https://docs.dhtmlx.com/planning-engine/wasm/wire-format.md#envelope>). Use them in custom runtimes, in servers that forward JSON as is, and in tools that work with the [wire format](<https://docs.dhtmlx.com/planning-engine/wasm/wire-format.md>). The rest of this branch documents them.

If you're building a browser or Node app, use the glue.

## Install

Build the package from source, then install the tarball:

```bash
cd crates/plen-wasm
npm pack
npm install ./plen-wasm-0.1.0.tgz
```

`npm pack` runs `npm run build`, which builds the browser target into `pkg/` and the Node target into `pkg-node/`. You need `wasm-pack` for this step. From the workspace root, `task build:wasm` and `task build:wasm:node` build the same [two targets](<https://docs.dhtmlx.com/planning-engine/wasm/module-and-handles.md#build-targets>).

## Entries

The package is ESM only (`"type": "module"`). Its `exports` map has two entries:

| Import | Resolves to | Exports |
| --- | --- | --- |
| `plen-wasm` in Node | `node.mjs` | [`Project`](https://docs.dhtmlx.com/wr/api/project), [`schedule`](https://docs.dhtmlx.com/wr/api/schedule), [`InputError`](https://docs.dhtmlx.com/wr/api/types/errors#inputerror), [`ProjectError`](https://docs.dhtmlx.com/wr/api/types/errors#projecterror), default [`init`](https://docs.dhtmlx.com/wr/api/init) |
| `plen-wasm` elsewhere | `index.mjs` | the same |
| `plen-wasm/glue` | `glue.mjs` | `createBindings` |

Type declarations for the main entry come from `index.d.ts`. The `./glue` entry has no type declarations.

`pkg/` and `pkg-node/` ship in the package, but they aren't in the `exports` map. Don't import them for the glue API.

## Initializing

### Browser

1. Import [`init`](https://docs.dhtmlx.com/wr/api/init) and the API from the package entry.
2. Call `await init()` once, before you create the first [`Project`](https://docs.dhtmlx.com/wr/api/project) or call [`schedule`](https://docs.dhtmlx.com/wr/api/schedule). `init()` fetches and instantiates the WebAssembly module, `plen_wasm_bg.wasm` from the `pkg/` directory. If you create a `Project` before `init()` resolves, the call fails.
3. Use the API.

```js
import init, { Project } from "plen-wasm";

await init();

const project = new Project({ dates: "string" });
const result = project.solve({
  tasks: [{ id: 1, start_date: "2026-01-01", duration: 2 }],
});
const preview = project.preview(
  { tasks: { update: [{ id: 1, duration: 3 }] } },
  { baselineId: result.baselineId },
);
project.dispose();
```

To load the `.wasm` from another place, pass it to `init`, as `{ module_or_path }`. It accepts a URL, a `Response`, the bytes or a compiled `WebAssembly.Module`.

`init()` resolves to the WebAssembly module's exports, not to `undefined`.

### Node

Node resolves `node.mjs`. The module loads when you import it, so there's no init step:

```js
import { schedule } from "plen-wasm";

const result = schedule({
  tasks: [{ id: 1, start_date: "2026-01-01", duration: 2 }],
});
console.log(result.updates);
```

[`init()`](https://docs.dhtmlx.com/wr/api/init) exists in Node too, so the same code runs in both environments. It's async, does nothing, and resolves to the loaded module.

## Use the API

Once the module is loaded, the API is the same as the JavaScript library's: [`Project`](https://docs.dhtmlx.com/wr/api/project) with `solve`, `preview`, `analyze`, `apply`, `level`, `loadProfile`, `evaluate`, `slots`, `suggestAssignments`, `clone` and [`dispose`](https://docs.dhtmlx.com/wr/api/project#dispose), plus [`schedule`](https://docs.dhtmlx.com/wr/api/schedule) and the two [error classes](https://docs.dhtmlx.com/wr/api/types/errors). Both packages use the same type declarations. For details, see the [JavaScript library documentation](https://docs.dhtmlx.com/wr/).

## Binding your own module

If you instantiate the WebAssembly module yourself, for example from your own build or in a worker, bind the API to it with `createBindings` from `plen-wasm/glue`. It takes any object that has the raw exports ([`JsonProject`](<https://docs.dhtmlx.com/planning-engine/wasm/api/json-project.md>) and [`schedule`](<https://docs.dhtmlx.com/planning-engine/wasm/api/schedule.md>)) and returns `{ Project, InputError, ProjectError, schedule }`:

```js
import { createBindings } from "plen-wasm/glue";
import init, * as wasm from "./build/plen_wasm.js";

await init();
const { Project, InputError, ProjectError, schedule } = createBindings(wasm);
```

Each `createBindings` call creates its own [`InputError`](https://docs.dhtmlx.com/wr/api/types/errors#inputerror) and [`ProjectError`](https://docs.dhtmlx.com/wr/api/types/errors#projecterror) classes. Errors from these bindings fail `instanceof` checks against the classes the package entry exports. Check them against the classes the same call returned.

## What differs from the js package

| Topic | JavaScript library | This package |
| --- | --- | --- |
| [`init()`](https://docs.dhtmlx.com/wr/api/init) | Optional; resolves `undefined` | Browser: required before the first `Project`; resolves to the WebAssembly module. Node: optional; resolves to the module |
| [`dispose()`](https://docs.dhtmlx.com/wr/api/project#dispose) | Marks the project unusable; frees nothing | Frees the WebAssembly memory the project holds |
| Internal engine failure | [`Error` with `name` `"Panic"`](https://docs.dhtmlx.com/wr/api/types/errors#other-errors) | `WebAssembly.RuntimeError` |
| `createBindings` | Not available | Exported from `plen-wasm/glue` |

### Dispose every project

Call [`dispose()`](https://docs.dhtmlx.com/wr/api/project#dispose) on every [`Project`](https://docs.dhtmlx.com/wr/api/project) and every [clone](https://docs.dhtmlx.com/wr/api/project#clone) you no longer need. It frees the WebAssembly memory the project holds. Each clone has its own memory, so dispose it on its own.

`dispose()` is idempotent, as in the JavaScript library. Any later call on that project throws `Error("Project has been disposed")`. If you never call `dispose()`, a finalizer frees the memory after garbage collection. The JavaScript runtime doesn't guarantee that the finalizer runs, so don't rely on it, especially in long-lived editors.

[`schedule()`](https://docs.dhtmlx.com/wr/api/schedule) creates and disposes its own temporary project, so there's nothing to free.

### Engine failures

An [internal engine failure](<https://docs.dhtmlx.com/planning-engine/wasm/error-handling.md#engine-failures>) surfaces as a `WebAssembly.RuntimeError`. After one, create the project again (or reload the module) before you continue.

## Raw API

The raw exports under the glue are documented in this branch's [API reference](<https://docs.dhtmlx.com/planning-engine/wasm/api/overview.md>). Most JavaScript apps don't need them.
