What about doing it the other way around. Using for example, the http://voltframework.com and adapting it to compile the web-backend with crystal, and maybe even platform binaries?
Yes, but more exactly along the lines of hyperstack (see https: “Hyperstack” dot Org) which is based on the ideas of meteor and volt.
The difference between meteor is that its Ruby, not JS. And the difference between Volt is that it uses React.js under the hood on the client, and ActiveRecord models (on the server and client) instead of MongoDB.
So what the hyperstack core team is looking to do is port Hyperstack from Ruby to Crystal, but that requires a Crystal → JS transpiler. Once we had that I believe the rest is straight forward.
Having Crystal on the server and Ruby on the client defeats the purpose btw. You would then have to write API adapters on either side of the wire, context switch between programming languages and tool chains etc.
The HUGE advantage of transpiling to JS (rather than compiling to WASM) is that as long as you do the mapping between JS functions and crystal methods smartly, you already have the DOM bindings.
This is the approach used by the Opal Ruby transpiler.
Why would you need DOM bindings? When none of modern web UI frameworks using it. React, Vue, Angular - it’s all higher level abstraction. Browser / DOM API is just an ugly low level thing that pretty much nobody these days uses directly.
P.S.
For Opal it would be nice if it had proper async/await (or Fibers) support.
There are still occasions even with those frameworks to reach in and manipulate the DOM. However the point is that by transpiling to JS you can interface to any JS code, whether low level (DOM) or high level (React or Vue)
As far as async/wait goes: Those provide some syntactic sugar on top a lower level promise mechanism. This is useful in JS, because you can’t really build a decent Promise DSL. In Ruby the promise class gives just as nice code as async/wait, without all the crazy caveats, and inconsistencies of async/wait.
I can’t speak for Vue and Angular, but React exposes DOM events and nodes (via refs) so you can’t really escape the DOM without a framework transforming those events and nodes into a different abstraction.
Plus, you probably want to provide bindings to other browser APIs like WebSockets, XHR/fetch, IndexedDB, ServiceWorker, geolocation, or Promises, so you’d need Crystal bindings for those, as well. :-)
I can do all those things with Headless Browser emulator, without accessing the actual Browser API.
All I need inside of the Crystal Black Box are two functions browser.eval(js-code-as-string) -> response-serialised-as-string and browser.on(event-name-as-string, callback).
Using these two methods you are able to take full control over Browser and do pretty much anything, without any special api. Yes, the performance will be not good, but, the modern computers and mobile phones are so insanely fast that it will be totally fine for like 90% of apps.
- Browser
- HTTP communication
- Crystal Server with LiveView on remote Machine
But it also could work this way, and run everything in Browser, no need to implement any wrappers for Browser API.
- Browser
- stdin/stout communication with Crystal WASM in same Browser
- Crystal Server with LiveView compiled to WASM and run in same Browser
http://repl.it has Crystal REPL with Crystal compiled to WASM and stdin/stdout. So it should be possible to do all that.
The example from that topic the LiveView real estate Listing - could be run with the Crystal Server compiled to WASM and running inside of the browser. Without any access to Browser API.
It’s not immediately clear to me if repl.it is running “all locally in the browser” or just the IDE is and execution is somewhere else…they also mention a REPL?