ballercat / walt

:zap: Walt is a JavaScript-like syntax for WebAssembly text format :zap:

Home Page:https://ballercat.github.io/walt/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot find modules

njtrettel opened this issue · comments

Bug Report

Overview

I get the error, TypeError: WebAssembly Instantiation: Import #0 module="utils" error: module is not an object or function. I assume there is something I need to do to make these available, but I could not find anything in the docs.

Expected

Should import modules like log from the env module, as shown in the simple Walt Explorer examples and quick start guide.

Actual

TypeError - can't resolve modules.

Example

Versions

Node.js: v8.10
Webpack: 4.15.1
walt-loader: 1.0.21

import { log: LogType } from 'env'; // also tried 'console' here
type LogType = (i32) => void;

Webpack config:

const path = require('path')

module.exports = {
  resolve: {
    extensions: [".walt", ".js", ".css"]
  },
  module: {
    rules: [
      { test: /\.walt$/, use: 'walt-loader' },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: "babel-loader"
      },
      { test: /\.css$/, use: ['style-loader', 'css-loader'] }
    ]
  },
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
}

Hey, if you have a snippet of the source JS file using the import I might be able to help.

The loaded file resolves to a factory function returning the module. The factory takes an import object which is where you would provide the env object which would have your log method. It's a bit nicer wrapper around WebAssembly.instantiate https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate

There is an example here https://github.com/ballercat/walt/blob/master/packages/webpack-walt-examples/src/CounterExample.js#L8

That make* method takes an object as the importObj, the example should maybe reflect that API though heh.

The loader has not had an update in a while, but the APIs should still work.

I don't fully understand what you mean. It sounds like I am missing some init parameters?

I have a very similar setup to the CounterExample (although I didn't notice that example initially). Here is my JS snippet:

import React from 'react';
import makeSorter from '../walt/sort.walt';

class Tester extends React.Component {
  constructor() {
    super();
    this.state = {
      sorter: null
    };
  }

  componentDidMount() {
    makeSorter().then(wasmModule => (
      this.setState({ sorter: wasmModule.instance.exports.sortItems })
    ));
  }

  render() {
    if (!this.state.sorter) {
      return <div>Loading...</div>;
    }
    const result = this.state.sorter([]);

    return (
      <div>
        {result}
      </div>
    );
  }
};

export default Tester;

@ballercat AH! sorry, I just noticed the JS tab on the Walt Explorer 😄

I see the env variable you are passing into instantiate now. Where does that JS piece (you have it titled compile()) fit in to the big picture then? Should I just compile my WALT stuff on initial page load?

The Explorer uses a deconstructed compile process to expose the underlying ASTs and other metadata but the idea is still the same.

For your code snippet to pass a log method nested inside an env namespace you should do the following

  componentDidMount() {
    makeSorter({ 
      env: {
         log: console.log
      } 
    }).then(wasmModule => (
      this.setState({ sorter: wasmModule.instance.exports.sortItems })
    ));
  }

Yes, you could compile it manually and instantiate it since the compiler runs in the browser, but it's usually not what you want to deal with.

Fixed 👍, thanks for the help!

NP! Thanks for pointing out that the docs are out of date

@ballercat didn't want to open a new issue for this, because it's just a random question. a response is not urgent.

if i were to import a javascript library to use in walt (such as importing console.log in your example), would the performance be the same as if i ran it in JS? i.e, these imported JS library are still run in a JS environment right? I would assume so.

thinking wishfully - It would be super cool if I could import something like lodash and have it perform like WASM.

It still runs int the JavaScript sandbox, think of it as if you linked a .dll into your executable. You can call the methods imported but you don't change how they are written/executed.

There is even a slight penalty for crossing that wasm <> js boundary (in either direction) as the engine has to perform validation and security(?) checks. I think Firefox at least has worked around some of these speed bumps though.