Node.js Hello Rebol (and caveats)

Node.js comes up from time to time...and whether or not Rebol could run on something like a commodity Node.js server.

One of the selling points of Emscripten as a toolchain is that it can do the necessary things so WASM will run in Node. I hadn't tried it. But my impression was that if you had something working in the browser...it should be able to get working in Node also.

After Some Hours of Fiddling...

...I managed to get a test to work. I'm looking at the fundamental issues of what might be done to make it less ugly, but...here is Node calling into Rebol:

var express = require('express')
var app = express();

var reb = require('rebol')

reb.onRuntimeInitialized = function() {
    reb.Startup()

    app.get('/', function (req, res) {
        let three = reb.Spell("to text! 1 + 2");
        res.send('One plus Two is ' + three)
    });

    app.listen(3000, function () {
        console.log('Example app listening on port 3000!')
    });
}

So it adds 1 and 2, turns the sum into a string, extracts that string as a JavaScript string, and serves you a page saying One plus Two is 3.

Okay that's something... BUT...

I think the more interesting story is Rebol-calling-JavaScript...as opposed to JavaScript-calling-Rebol. But Node kind of sits as the gatekeeper at a top level. I have a hard time seeing how to graft a Node program into an app.reb that "occasionally asks Node to do things". But it seems a lot more clear with the browser.

There are some other points on why not to push on this too much right now:

  • Though Node.js has caught up with V8 features over time, Emscripten hasn't yet taken advantage of their workers or shared memory. That means that if you want rebPromise() and the other magic that makes libRebol cool, you'll have to use the emterpreter. The above program needs over 1.5mb of build products, well more than twice the size of a pure webassembly build...and as I've said, it's about 30x slower.

  • There's a way to package cross-platform native C code and build it as part of a node package--sidestepping webassembly and emscripten altogether. This would be the fastest option. It wouldn't be impossible to do, but it would be a lot of work on a new codebase that there aren't resources to allocate to. Waiting for emscripten to support WASM+pthreads on Node is probably a better bet, because it would mean being able to leverage common binding code with the browser--vs. a new project.

  • NPM modules deploy via GitHub. I don't see a turnkey way to get a static resource of a large webassembly file to go along with that installation, other than putting it in the GitHub repository itself. Strangely, if one ships native C code with a C++ binding to V8 (as described in the previous point), Node is set up to make that more turnkey. :-/

It is worth scoping out and understanding, though

It brings questions up, and they are good to think about:

  • Should we aim for modules and call like reb.Spell() instead of rebSpell(), even in the web version where we don't have to? (People talk about browsers getting a module model like Node's, so it would probably be forward-looking.)

  • Should var reb = require('rebol') give you back an interpreter instance, or should that get an "engine", so you say var rebol = require('rebol'), var reb = new rebol.Interpreter(...), and you could make several of these as independent?

  • Should rebStartup() be a Promise, if we can't generically hide the WebAssembly load? Will users of libRebol be expected to put all of their code in a callback?

It's definitely forward-thinking to be working on answers to these questions. But I think we should be looking more to Rebol-based %httpd.reb and other things like that for the server side. Worth pointing out is that Node.js's creator has decided it's too flawed, and has gone off to promote another project...

1 Like

My interest in Node.js was solely as an output target to AWS Lambdas, i.e., individual functions which can be executed natively in Amazon's cloud platform. I wanted a more scalable infrastructure to "rent" computing power from, as opposed to owning or managing a limited LAMP/Rails style stack at a hosting provider.

I've committed a primordial version of Node support, minimally tested. It allows you to do things like the code snippet above.

It's good to make sure choices in libRebol aren't making it fundamentally impossible to do. So it should be kept working and improved as time permits. If you can come up with an example scenario for a proof of concept--then it would be useful to make sure all the pieces are there to do it.

But it does not look viable to think of building a solution and saying "here, we made it, set it as a npm package dependency and use it!". It's a complex new target. And if debugging all the magic in a browser is difficult, dealing with bug reports from someone's server you can't access is going to be worse. Making a turnkey deployment for people to install doesn't look easy.

So I think focus for now should stay on the browser...packaging the library so that people can use it easily. Instead of there just being the one REPL demo, I'd like to see a bunch of little demos showing Rebol-driven sites. And if that story can build excitement and awareness of the language, maybe that can be leveraged into having some Node-experts get involved...