How to call Rust from JS and back? - javascript

I'm trying to adapt the game of life tutorial to call user-defined JS (instead of alert) from Rust:
index.js:
import * as wasm from "testing-wasm";
export const jsfunc = () => {
console.log("jsfunc called");
};
// Call Rust from JS. This function will call `jsfunc`, declared above.
wasm.rustfunc();
lib.rs:
mod utils;
use wasm_bindgen::prelude::*;
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen(module = "/www/index.js")]
extern "C" {
fn jsfunc();
}
#[wasm_bindgen]
pub fn rustfunc() {
// call JS
jsfunc();
}
wasm-pack build runs fine. But running the web project (npm run start) can't resolve the import anymore:
ERROR in ../pkg/snippets/testing-wasm-8ea926e8de57779d/www/index.js
Module not found: Error: Can't resolve 'testing-wasm' in '/Users/ischuetz/dev/ct-an/testing-wasm/pkg/snippets/testing-wasm-8ea926e8de57779d/www'
# ../pkg/snippets/testing-wasm-8ea926e8de57779d/www/index.js 1:0-37 7:0-13
# ../pkg/testing_wasm_bg.wasm
# ../pkg/testing_wasm.js
# ./index.js
# ./bootstrap.js
It works before introducing the circular dependency.
Any ideas? I also found import_js in wasm-bindgen but there's no direct call to Rust from JS.

in your Cargo.toml file add this:
[lib]
# if you want to integrate your rust code with javascript we use cdylib
crate-type=["cdylib"]
since you are using wasm-bindgen and wee_alloc and I assume it is already in your .toml file:
[dependencies]
wasm-bindgen="0.2.63"
wee_alloc="0.4.5"
When you build your code, pkg folder is created which includes glue javascript code wasm code. Now you need to get this pkg folder into the node modules. To do so, you have to link it to your javascript project's package.json:
"dependencies": {
// your path to ../pkg might be different
"rust_project": "file:../pkg",
},
Then in your javascript project directory, npm install. You will see that rust_project module is in your node_modules directory.
In your javascript file:
import rustfunc from "rust_project";
Now you can call your function

Related

Uncaught ReferenceError: require is not defined (How to use a javascript library from the command line, or an html file)

I'm new to javascript and programming in general. I would like to use this:
https://github.com/CesiumGS/gltf-pipeline
It's a tool to convert models into compressed formats.
This is my code:
const gltfPipeline = require("gltf-pipeline");
const fsExtra = require("fs-extra");
const processGltf = gltfPipeline.processGltf;
const gltf = fsExtra.readJsonSync("model.gltf");
const options = {
dracoOptions: {
compressionLevel: 10,
},
separateTextures: true,
};
processGltf(gltf, options).then(function (results) {
fsExtra.writeJsonSync("modeldraco.gltf", results.gltf);
console.log('done');
const separateResources = results.separateResources;
for (const relativePath in separateResources) {
if (separateResources.hasOwnProperty(relativePath)) {
const resource = separateResources[relativePath];
fsExtra.writeFileSync(relativePath, resource);
}
}
});
I copied this file, saved it as compress.js (because it rhymes) and I then ran it with
node compress.js - this is how I'd run a python file.
Error is: Cannot find module 'gltf-pipeline' which makes sense. So, I did:
node -r gltf-pipeline compress.js but I get the same error.
So, I moved to HTML/JS, where I made an index.html file and linked with a <script> tag compress.js and the gltf-pipeline index.js file. These are the errors:
index.js:3 Uncaught ReferenceError: module is not defined
at index.js:3
(anonymous) # index.js:3
compress.js:3 Uncaught ReferenceError: require is not defined
So how is this done? Either as a webpage or command line would be helpful.
This is my folder structure by the way, maybe that's the issue.
basefolder|
|- gltf-pipeline| library files in here
|- compress.js
|- index.html
|- model.gltf
gltf-pipeline works when used as a command line tool.
No.
You can't do that with Javascript.
JS is served to the client.
Whilst NodeJS runs on a server.
These are the differences between node and browser JS.
also for the module error try
npm install gltf-pipeline
Look at NPM to install Node Packages
Also take a look at the NodeJS Tutorial

Error: A dynamic link library (DLL) initialization routine failed on electron but it's fine on node js

I'm trying to load a custom module in electron written in D with node_dlang package, which is fine with node, but it fails within electron.
the test with node, that runs just fine, goes like this:
const nativeModule = require('./module.node');
const assert = require('assert');
assert(nativeModule != null);
assert(nativeModule.ultimate() == 42);
But when I went to use it within electron.js, through the preload script, it returns in an error.
the preload script goes like this:
const {
contextBridge,
ipcRenderer
} = require("electron");
const nativeModule = require('./module.node');
const assert = require('assert');
assert(nativeModule.ultimate() == 42);
function pageLoaded()
{
// ...
}
window.addEventListener('DOMContentLoaded', pageLoaded);
the error when I attempt to load the module within electron application is:
A JavaScript error occured in the browser process
--------------------------- Uncaught Exception: Error: A dynamic link library (DLL) initialization routine failed.
\\?\C:\Users\001\Desktop\ele\module.node
at process.func [as dlopen] (VM70 asar_bundle.js:5)
at Object.Module._extensions..node (VM43 loader.js:1138)
at Object.func [as .node] (VM70 asar_bundle.js:5)
at Module.load (VM43 loader.js:935)
at Module._load (VM43 loader.js:776)
at Function.f._load (VM70 asar_bundle.js:5)
at Function.o._load (VM75 renderer_init.js:33)
at Module.require (VM43 loader.js:959)
at require (VM50 helpers.js:88)
at Object.<anonymous> (VM88 C:\Users\001\Desktop\ele\preload.js:6)
What's causing this and how do I fix this?
version
node version is: v14.17.0
electron.js: v13.1.1
both are 64-bit.
the module source code goes like this:
import std.stdio : stderr;
import node_dlang;
extern(C):
void atStart(napi_env env)
{
import std.stdio;
writeln ("Hello from D!");
}
int ultimate()
{
return 42;
}
mixin exportToJs! (ultimate, MainFunction!atStart);
it's compiled with dub command line. No arguments.
UPDATE 1 Do I need to rebuild this module? I found this but it didn't work for me either. I installed the electron-rebuild package by npm install --save-dev electron-rebuild and rebuild with .\node_modules\.bin\electron-rebuild.cmd -v 13.1.1 the command ran fine but I still got same error.
UPDATE 2: inside the console, I clicked in the javascript source code file link in the error message (from the exception) it points to this line of code, where there's this comment saying that:
no static exports found
what does that mean? is this related to the methods in D class? they're marked as public... not sure if related
Electron is a Windows-Application and therefore you need to remove output to std. Try to remove
import std.stdio : stderr;
and
import std.stdio;
writeln ("Hello from D!");
and retry import to Electron.
Please refer this (https://stackoverflow.com/a/74280836/9558119) post from me regarding same. Since it is electron build might be missing Visual C++ Build Environment: Visual Studio Build Tools

Cannot call unknown function

I'm trying to compile a medium-size existing code base with emscripten. Everything currently compiles, but when I try to call it from javascript I'm getting the error:
Assertion failed: Cannot call unknown function InitHOG (perhaps LLVM optimizations or closure removed it?)
I've declared this as:
extern "C" {
void EMSCRIPTEN_KEEPALIVE InitHOG()
{ ... }
}
I'm linking the function from javascript with:
InitHog = Module.cwrap('InitHOG', 'void', []);
My code base is being compiled into libraries; the function call into the library is in my guihtml library, where the final linking command is:
emcc -o ../../../../html/debug/bidirnecessary.js ../../../../objs_html/bidirnecessary.js/debug/demos/bidirnecessary/Driver.o -lenvironments -lmapalgorithms -lalgorithms -lgraphalgorithms -lgraph -lutils -lguihtml -L../../../../html/debug -Lapps/libs -Ldemos/libs -lpthread -g
Any ideas on why it can't find my function from javascript?
While the EMSCRIPTEN_KEEPALIVE keyword works when you are compiling a single file to .js output, it doesn't work in my makefile system where I compile individual files, use emar to make a library, and then link everything together at the end.
Instead, you need to use the -s directive to specify which functions you want to export. So, something like this works.
emcc -o ../../../../html/debug/bidirnecessary.js ../../../../objs_html/bidirnecessary.js/debug/demos/bidirnecessary/Driver.o -lenvironments -lmapalgorithms -lalgorithms -lgraphalgorithms -lgraph -lutils -lguihtml -lgui -L../../../../html/debug -Lapps/libs -Ldemos/libs -lpthread -g -s EXPORTED_FUNCTIONS="['_InitHOG', '_DoFrame', '_MouseEvent']"

JS, Browserify: function not defined

I have files as represented:
-js/
- calc.js
- tool.js
-index.html
calc.js is a node module of following structure:
module.exports = {
calculate: function() {...},
getPrecision: function() {...}
}
and tool.js use require and adds some functions, like that:
const fpcalc = require('./fpcalc');
function changeState() {
//some code using fpcalc
}
I used Browserify to generate bundle.js and added that as script src.
One of my buttons on HTML page is using onclick=changeState(). After clicking I'm getting
ReferenceError: changeState is not defined
at HTMLAnchorElement.onclick
Why is that? Is there any other way to make it work?
The function "changeState" is not exported in your tool.js.
That means it is only visible inside your bundle.js, but not outside.
Have a look at this: https://makerlog.org/posts/creating-js-library-builds-with-browserify-and-other-npm-modules
It shows you how to expose your code to the global namespace in javascript.
Here's a very simple way to make it work like you want.
const fpcalc = require('./fpcalc');
window.changeState = () => {
//some code using fpcalc
}
I have same error, here is my working example.
mac, browserify https://github.com/perliedman/reproject
Must use sudo install globally
sudo npm install -g brwoserify
https://github.com/perliedman/reproject
sudo npm install reproject // install locally is fine
Must manually create 'dist' folder for later output file use
Must use --s expose global variable function 'reproject' and or 'toWgs84' you will use later in browser js.
Without --s , will get 'reproject' undefined error . https://makerlog.org/posts/creating-js-library-builds-with-browserify-and-other-npm-modules
browserify --help will list all options.
-o means output file directory
browserify node_modules/reproject/index.js --s reproject -o node_modules/reproject/dist/reproject.js
HTML script tag include your above dist/reproject.js
Now, you will not get 'reproejct' undefined error
return reproject(_geometry_, ___from_projection, proj4.WGS84, crss)

Integrating React components with Pux - where does require() come from?

The Pux documentation tells me to use require() in the browser. Where does that function come from and how do I use it?
Background:
I'm trying to integrate the Quill editor with my web application that uses purescript-pux.
Following the Pux documentation I created a file MyEditor.js like this:
// module MyEditor
var React = require("react");
var Pux = require("purescript-pux");
var MyEditor = React.createClass({
displayName: "MyEditor",
onTextChange: function onTextChange(value) {
this.setState({ text: value });
},
render: function render() {
return React.createElement(ReactQuill, { value: this.state.text,
onChange: this.onTextChange });
}
});
exports.fromReact = Pux.fromReact(MyEditor);
and a file MyEditor.purs as follows:
module MyEditor where
import Pux.Html (Html, Attribute)
foreign import fromReact :: forall a. Array (Attribute a) -> Array (Html a) -> Html a
I then use MyEditor.fromReact [value p.description] in my Html Action and the code compiles, but the browser complains about ReferenceError: require is not defined.
I'm not very familiar with the javascript ecosystem. I'm aware that several libraries providing a require() function exist, but which one do I use with Pux and how?
require is the NodeJS way of importing modules, it's not supported in the browser so you'll need to run your project through a bundler like browserify or webpack to produce a bundle that the browser can understand.
If you are using the pulp build tool it's as simple as running
pulp browserify --to app.js
and then loading app.js in your html through a script tag.
pulp browserify documentation: https://github.com/bodil/pulp#commonjs-aware-builds
In addition to Christophs answer (but can't comment since comments don't allow code blocks):
Using Thermite 4.1.1 this worked for me:
add a package.json file with:
{
"dependencies": {
"react": "^0.14",
"react-dom": "^0.14"
}
}
run npm install
from then on pulp browserify --optimise gets the whole shebang packaged.
This is really badly documented and I opened an issue about that on purescript-react.

Categories

Resources