Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatibility issues with Node 14.4.0 and Typescript #241

Closed
ernoaapa opened this issue Aug 17, 2020 · 4 comments
Closed

Compatibility issues with Node 14.4.0 and Typescript #241

ernoaapa opened this issue Aug 17, 2020 · 4 comments

Comments

@ernoaapa
Copy link

Hi,
I'm interested in using the @wasmer/wasi library in the Typescript project, but I have challenges with it. Anyone using the @wasmer libraries in a Typescript project?

It can be that there's just something wrong with my setup (I'm not expert in this), or there are some changes needed in this library, I'm not sure, but would really appreciate the help.

Example project

package.json

{
  "name": "ems-example",
  "type": "module",
  "scripts": {
    "start": "node --loader ts-node/esm.mjs ./src/index.ts"
  },
  "dependencies": {
    "@wasmer/wasi": "^0.11.2",
    "ts-node": "^8.10.2",
    "typescript": "^3.9.7"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "lib": ["ES2020", "dom"],
    "module": "ES2020",
    "moduleResolution": "node",
    "target": "ES2020"
  }
}

src/index.ts

import { WASI } from '@wasmer/wasi';

console.log(new WASI());

The problem

I get the following error:

> node --loader ts-node/esm.mjs ./src/index.ts

(node:65110) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
file:///example/src/index.ts:1
import { WASI } from '@wasmer/wasi';
         ^^^^
SyntaxError: The requested module '@wasmer/wasi' is expected to be of type CommonJS, which does not support named exports. CommonJS modules can be imported by importing the default export.
For example:
import pkg from '@wasmer/wasi';
const { WASI } = pkg;
    at ModuleJob._instantiate (internal/modules/esm/module_job.js:97:21)
    at ModuleJob.run (internal/modules/esm/module_job.js:135:5)
    at Loader.import (internal/modules/esm/loader.js:178:24)

Typescript does not show any errors.

So far, I figure out that, because in the @wasmer/wasi's package.json there's no "type":"module", the CommonJS module gets loaded. That's not the problem, but the problem might be that the Typescript typing doesn't match with the CommonJS module.

Workaround

Managed to get around the Typescript typing and importing the module, but it's a pretty ugly hack

import * as wasipkg from '@wasmer/wasi';
import { WASI as WASIType } from '@wasmer/wasi';

const { WASI } = <any>wasipkg.default || wasipkg;

const wasi: WASIType = new WASI();
console.log(wasi);

Any tips how to load the module properly in the Typescript project?

@corwin-of-amber
Copy link
Contributor

Hi, I'm not so sure what node --loader is actually doing. Wasmer-JS itself is written in TypeScript and I have several TypeScript projects using it (e.g. https://github.com/corwin-of-amber/wasi-kernel). My build setup is to compile the .ts files -- I am currently using Parcel, but just invoking tsc should also work.

E.g.:

// exec.ts
import { WASI, WASIConfig } from '@wasmer/wasi';
import { WasmFs } from '@wasmer/wasmfs';
import * as transformer from '@wasmer/wasm-transformer';
...
% tsc exec.ts
% node exec.js

@dunnock
Copy link

dunnock commented Aug 27, 2020

Had same compilation issue. I managed it to compile with typescript with following rollup config:

// Allowing to compile wasmer-js for browser
const replaceBrowserOptions = {
    delimiters: ["", ""],
    "/*ROLLUP_REPLACE_BROWSER": "",
    "ROLLUP_REPLACE_BROWSER*/": "",
};

const sourcemapOption = process.env.PROD ? undefined : "inline";

const plugins = [
  replace(replaceBrowserOptions),
  resolve({
    preferBuiltins: true,
  }),
  commonjs(),
  globals(),
  builtins(),
  typescript(),
  json(),
  process.env.PROD ? compiler() : undefined,
  process.env.PROD ? bundleSize() : undefined,
];

with pretty much standard tsconfig.

Though as rollup is trying to embed index.js instead of bundled version it does not work as they try to execute following code which is on top of index.js:

"use strict";
/* eslint-disable no-unused-vars */
Object.defineProperty(exports, "__esModule", { value: true });
const bigint_1 = require("./polyfills/bigint");
const dataview_1 = require("./polyfills/dataview");
const buffer_1 = require("./polyfills/buffer");
// Import our default bindings depending on the environment
let defaultBindings;

It seems currently exported wasi/lib/index.js either does not make sense or it should be exported as a code which can run in browser.

@dunnock
Copy link

dunnock commented Aug 28, 2020

Managed to fix the issue, so the reason is tsc emits in commonjs format with exports.default which is not recognized by @rollup/commonjs-plugin with rollup version 2. Here is workaround which works in browser:

import WASI from  "@wasmer/wasi";
import wasiBindings from "@wasmer/wasi/lib/bindings/browser";

let wasi = new WASI({
  bindings: {
    // @ts-ignore
    ...wasiBindings.default,
  }
});

it works with following config:

// Rollup Config for Web Workers

import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import json from "@rollup/plugin-json";
import typescript from "@rollup/plugin-typescript";
import replace from '@rollup/plugin-replace';
import globals from "rollup-plugin-node-globals";
import builtins from "rollup-plugin-node-builtins";

// Allowing to compile wasmer-js for browser
const replaceBrowserOptions = {
    delimiters: ["", ""],
    "/*ROLLUP_REPLACE_BROWSER": "",
    "ROLLUP_REPLACE_BROWSER*/": "",
    'Object.defineProperty(exports, "__esModule", { value: true });': "",
};

const sourcemapOption = process.env.PROD ? undefined : "inline";

const plugins = [
  replace(replaceBrowserOptions),
  typescript(),
  resolve({
    preferBuiltins: false,
  }),
  commonjs({
      transformMixedEsModules: true,
    }),
  globals(),
  builtins(),
];

const workerBundles = [
  {
    input: "./src/worker.ts",
    output: [
      {
        dir: "dist",
        format: "umd",
        sourcemap: sourcemapOption,
        name: "Process"
      }
    ],
    plugins: plugins
  }
];

export default workerBundles;

@Michael-F-Bryan
Copy link
Contributor

We've re-implemented this package from the ground up, including the build system, so this is no longer relevant.

@Michael-F-Bryan Michael-F-Bryan closed this as not planned Won't fix, can't repro, duplicate, stale Dec 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants