[Canonical page](<https://docs.dhtmlx.com/planning-engine/js/how-to/switch-from-the-wasm-package/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Switch from the WASM package

Move code written for the `plen-wasm` glue API to `plen-js` and drop the WebAssembly module and its async startup.

Both packages expose the same [`Project`](<https://docs.dhtmlx.com/planning-engine/js/api/project.md>) API: the same methods, options, data and result types, and the same [`schedule`](<https://docs.dhtmlx.com/planning-engine/js/api/schedule.md>), [`InputError`](<https://docs.dhtmlx.com/planning-engine/js/api/types/errors.md#inputerror>) and [`ProjectError`](<https://docs.dhtmlx.com/planning-engine/js/api/types/errors.md#projecterror>) exports. Results match the WASM package's, and result keys come back in the same sorted order. Most code moves over with an import change.

## Prerequisites

- Code that uses the glue entry of `plen-wasm` (`Project`, `schedule`, `InputError`, `ProjectError`, default `init`). Code built on the raw `JsonProject` exports and JSON strings has no counterpart here.
- Node 18 or later, or a browser.

## Steps

1. Replace the dependency:

   ```bash
   npm uninstall plen-wasm
   npm install plen-js
   ```

2. Change the import specifier. The export names stay the same:

   ```js
   // before
   import init, { Project, schedule, InputError, ProjectError } from "plen-wasm";

   // after
   import init, { Project, schedule, InputError, ProjectError } from "plen-js";
   ```

   For CommonJS, use `require`. The named exports are direct, and `init` is `.default`:

   ```js
   const { Project, schedule, InputError, ProjectError } = require("plen-js");
   ```

3. Remove the [`await init()`](<https://docs.dhtmlx.com/planning-engine/js/api/init.md>) call. A `Project` works right after the import:

   ```js
   import { Project } from "plen-js";

   const project = new Project();
   const result = project.solve({
     tasks: [
       { id: 1, start_date: "2026-08-10 08:00", duration: 2 },
       { id: 2, start_date: "2026-08-10 08:00", duration: 1 },
     ],
     links: [{ id: 1, source: 1, target: 2 }],
   });
   ```

   You don't need to call [`init()`](<https://docs.dhtmlx.com/planning-engine/js/api/init.md>); it exists only so code written for the WASM package works unchanged. If you keep the call, it resolves `undefined` immediately. It doesn't return the module exports the WASM `init()` returns, so remove any code that reads its result. Drop the `.wasm` file path or bytes you passed to it too: `init` ignores its argument.

4. Keep or remove the [`dispose()`](<https://docs.dhtmlx.com/planning-engine/js/api/project.md#dispose>) calls. `dispose()` is optional in JavaScript; after it, every call on that project throws `Error("Project has been disposed")`. Garbage collection frees the memory either way. Keep the calls if the same code must also run on the WASM package.

5. Check code that depends on WASM-specific failures. Everything else, including [`InputError`](<https://docs.dhtmlx.com/planning-engine/js/api/types/errors.md#inputerror>) `kind`, `message` and `path` and [`ProjectError`](<https://docs.dhtmlx.com/planning-engine/js/api/types/errors.md#projecterror>) `code`, stays the same:

   | Case | `plen-wasm` | `plen-js` |
   | --- | --- | --- |
   | A required argument is `undefined`, e.g. `preview(undefined)` | wasm-bindgen argument error | `InputError` |
   | A string contains a lone surrogate | rejected | accepted |
   | An input object has a getter | read twice | read once |
   | Internal engine failure | WebAssembly trap | `Error` named `Panic` |

   See [Error handling](<https://docs.dhtmlx.com/planning-engine/js/error-handling.md>) for the full list of errors.

## Result

The project schedules with no WebAssembly download or `init()` wait, and `result` has the same shape and values the WASM package returned:

```js
{ baselineId: "1-…", conflicts: [], converged: true, cycles: [], notes: [],
  updates: [{ end_date: "2026-08-13 08:00", id: 2, kind: "task", start_date: "2026-08-12 08:00" }] }
```

`baselineId` is an opaque token, so its value can differ from the one the WASM package returned for the same data.

Every method still runs synchronously on the calling thread, as it did on the WASM package. To keep long leveling or evaluate runs off the UI thread, see [Run in a worker](<https://docs.dhtmlx.com/planning-engine/js/how-to/run-in-a-worker.md>).
