This page hosts a Pascal program transpiled by pas2js into Javascript. The program loads WebAssembly SQLite to perform database operations entirely within the web browser. Below is the program's output. Reload the web page if the output doesn't appear automatically; this may have to do with caching by your web browser, caching cleverness by HTMX, reverse proxy caching on my site, or other web weirdness.
This is placeholder text. Reload this web page to see pas2js and SQLite in action.
The program runs in the web browser's main UI thread and stores data in the browser's local storage. Open the browser's inspector, in the "Storage" tab, for "Local Storage", you'll see entries with names such as "kvvfs-local-xxx", created by SQLite's kvvfs, the key/value VFS.
Thanks to pas2js's generating Javascript source maps, the full source code for this page's Pascal program, in both Javascript and Pascal forms, is visible from the web browser's debugger; see screenshot.

The pas2js program is implemented as a module; see wiki for details. In essence, WebAssembly SQLite's Javascript file is loaded thusly at the head of the program:
program mainthread;
{$mode objfpc}
{$linklib ../dist/sqlite3.mjs sqlite3}
As a module, the generated Javascript itself, named mainthread.js, starts the pas2js runtime library. The module file is
loaded by this web page as follows:
<html>
<head>
...
<script type="module" src="/demo/mainthread.js"></script>
...
Here's the body of the program that produces the above output:
begin
await(InitSQLite);
writeln('Loaded SQLite WebAssembly ', TWSQLiteCAPI.LibVersion);
writeln('Existing database(s) total size = ', TWSQLiteJSStorageDB.TotalSize);
args := new(['filename', 'local']); // 'local' means browser 'local storage'
db := TWSQLiteJSStorageDB.New(args);
writeln('Initializing database');
i := db.Clear;
writeln('Deleted ', i, ' keys from browser local storage');
writeln('Database size = ', db.Size);
writeln('Create a table...');
db.Exec('create table if not exists t (a, b)');
writeln('Insert some data using exec()');
for i := 20 to 25 do
begin
args := new([
'sql', 'insert into t (a, b) values (?, ?)',
'bind', TJSArray._of(i, i*2)
]);
db.Exec(args);
end;
writeln('Query data with exec() returning rows of objects');
rows := TJSArray.New();
args := new([
'sql', 'select a, b from t order by b desc limit 4',
'rowMode', 'object',
'resultRows', rows
]);
db.Exec(args);
for i := 0 to 3 do // SQL returned limit 4
begin
obj := ToObject(rows[i]);
writeln(Format('a = %s, b = %s', [String(obj['a']), String(obj['b'])]));
end;
writeln('Database size = ', db.Size);
db.Close;
end;
Next up: running WebAssembly SQLite in its own worker thread, off the web browser's main UI thread.