WebAssembly (abbreviated Wasm) is "a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications." Currently, all major web browsers support Wasm. Standalone and embeddable Wasm runtimes also exist that allow running Wasm programs outside of the web browser.
So far, Wasm seems be have been of more interest among the AOT compile-to-native programming languages. Free Pascal, which works across a large number of processor architectures, operating systems, and embedded platforms, also support Wasm compilation targets; see this wiki page on setting it up. Additionally, Free Pascal also comes with a Pascal-to-Javascript transpiler known as pas2js.
I've put up a reworked Free Pascal Wasm demo of Conway's Game of Life. The game play was implemented by Dmitry Boyarintsev, in Pascal, and compiled to Wasm. The user interface is implemented by me, in Pascal, and transpiled to Javascript. For good measure, I've included a simple web server, also implemented in Pascal, that serves the Wasm, Javascript and other static content.
So, to build all Pascal programs in the demo from source, three Free Pascal compilation targets are used:
Here's a screenshot of the user interface running on my desktop web browser in mobile-responsive mode:
I've implemented an embedded localhost web server demo for fpwebview. The demo runs on Linux macOS, and Windows 10. Here's a Linux screenshot:
The program consists of a multi-threaded web server listening on localhost:8000
,
and the web browser widget showing the content, styled by CSS, all loaded from
said web server.
Because the embedded web server is listening on localhost:8000
, you
could visit it with a regular web browser running on the same machine.
However, in the demo program, the buttons work by using webview
APIs
to perform what is effectively in-process RPC between Javascript and
Pascal. From a regular web browser, clicking those buttons will have no
effect, since the browser's Javascript runtime has nothing to do with the
Pascal procedures implementing the buttons' functionalities.
For serious usage beyond a demo, additional security measures are possible to ensure that the embedded web server serves only the web browser widget and no other client.
I've implemented bidirectional Javascript-Pascal calling for fpwebview. Here's the demo program:
program js_bidir;
{$linklib libwebview}
{$mode objfpc}{$H+}
uses
{$ifdef unix}cthreads,{$endif}
math,
webview;
var
w: PWebView;
html: String;
procedure SayHello(const seq: PAnsiChar; const req: PAnsiChar; arg: Pointer); cdecl;
var
s: String;
begin
s := 'var p = document.createElement("p")' + LineEnding +
'p.innerHTML = "Yo again!"' + LineEnding +
'document.body.appendChild(p)';
webview_eval(w, PAnsiChar(s));
webview_return(w, seq, WebView_Return_Ok, '{result: "<p>Yo!</p>"}');
end;
begin
{ Set math masks. libwebview throws at least one of these from somewhere deep inside. }
SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]);
html := 'data:text/html,<html>' + LineEnding +
'<head></head>' + LineEnding +
'<body><button onClick="SayHello()">Say Hello</button>' + LineEnding +
'<div id="greeting"></div>' + LineEnding +
'<script>var SayHello = function() {' + LineEnding +
' HostSayHello().then((x) => document.getElementById("greeting").innerHTML = x.result)' + LineEnding +
'}</script>' + LineEnding +
'</body>' + LineEnding +
'</html>';
w := webview_create(WebView_DevTools, nil);
webview_set_size(w, 700, 200, WebView_Hint_None);
webview_set_title(w, PAnsiChar('WebView - Pascal Javascript Bidirectional'));
webview_bind(w, PAnsiChar('HostSayHello'), @SayHello, nil);
webview_navigate(w, PAnsiChar(html));
webview_run(w);
webview_destroy(w);
end.
In the program, the Pascal procedure SayHello
is made accessible to
Javascript as HostSayHello
. When Javascript calls HostSayHello
,
the Pascal code in turns invokes Javascript to update the DOM, then returns
a response to the Javascript caller.
Next up, an embedded web server to serve HTML, CSS and other content including Javascript source.
Webview is a "tiny cross-platform webview library for C/C++/Golang to build modern cross-platform GUIs." Webview uses Cocoa/WebKit on macOS, gtk-webkit2 on Linux, and Edge on Windows 10.
There exist various language bindings for Webview, as listed on Webview's Github page. I've just published my Free Pascal binding here.
Here's a simple Pascal program that uses Webview to implement a web browser.
program browser_cli;
{$linklib libwebview}
uses
{$ifdef unix}cthreads,{$endif}
math,
webview;
var
w: PWebView;
begin
{ Set math masks. libwebview throws at least one of these from somewhere deep inside. }
SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]);
writeln('Hello, webview, from Pascal!');
w := webview_create(WebView_DevTools, nil);
webview_set_size(w, 1024, 768, WebView_Hint_None);
webview_set_title(w, PAnsiChar('WebView Free Pascal'));
webview_navigate(w, PAnsiChar('https://www.freepascal.org/'));
webview_run(w);
webview_destroy(w);
writeln('Goodbye, webview.');
end.
Coincidentally, Tomaž Turk recently announced Pharo-WebView.