Fresnel WebAssembly: WASM runs correctly, but TMainForm is not created
Hi,
I'm trying to get the Fresnel WebAssembly backend working on Windows with a recent Lazarus/FPC trunk installation.
My environment is:
Windows
Lazarus trunk installed with fpcupdeluxe
FPC 3.3.1 trunk
Lazarus/FPC installation: C:\lazarus\20260903
Fresnel from the current Git repository
Skia4Delphi installed
Firefox for testing
I initially asked how to compile the Fresnel ComboBox demo for the browser and was advised to:
build pas2js if needed;
build the WASM cross-compiler;
reference the WASM binary from the browser host.
I successfully built ppcrosswasm32, located at:
C:\lazarus\20260903\fpc\bin\x86_64-win64\ppcrosswasm32.exe
I also found pas2js.exe at:
C:\lazarus\20260903\ccr\pas2js-rtl\bin\x86_64-win64\pas2js.exe
C:\lazarus\20260903\fpc\bin\x86_64-win64\pas2js.exe
Building the WASM
The original compile.cfg used:
-FUlib/wasm32-wasi
but on Windows this caused object files to be generated in an incorrect nested directory.
I changed it to:
-FUlib/wasm32-wasip1
and then I was able to successfully compile:
ComboBox.wasm
with:
"C:\lazarus\20260903\fpc\bin\x86_64-win64\ppcrosswasm32.exe" @compile.cfg ComboBox.lpr
The resulting WASM is approximately 6.4 MB.
WebHost
I then compiled the fresnelhost pas2js project. The generated files are:
browser.dom.js
browser.min.js
fresnelhost.js
hostconfig.js
ComboBox.wasm
index.html
I also built simpleserver from the Lazarus trunk and used it to serve the WebHost directory on:
http://localhost:4040Serving the files over HTTP solved the CORS problem that occurred when opening index.html directly from file://.
The server initially returned JavaScript files as application/octet-stream, producing MIME warnings in Firefox, but the JavaScript was nevertheless executed.
First important problem: _initialize
The browser initially reported:
Loading and starting Webassembly module: ComboBox.wasm
Running Webassembly resulted in exception.
aExports[$Self.FRunEntryFunction] is not a function
I inspected the generated WASM exports and found:
memory
_start
_start_promising
wasiAlloc
wasiFree
__fresnel_tick
__fresnel_process_message
__fresnel_main_thread_wake
__fresnel_timer_tick
__fresnel_menu_click
...
There was no _initialize export.
The generated fresnelhost.js contained:
if ($Self.FRunEntryFunction === "") {
if (aExports["_initialize"] != null) {
aExports._initialize()
}
else aExports._start()
}
else aExports[$Self.FRunEntryFunction]();
However, FRunEntryFunction was set to _initialize, so the fallback to _start was not reached.
For diagnostic purposes, I modified this section so that if the requested entry point does not exist, it falls back to _start.
With that temporary change, the WASM starts successfully.
This is now working
After using _start, the browser console shows many Fresnel renderer messages, for example:
TWasmFresnelRenderer.DrawElBorder("TMainForm.Body1.TDiv.CheckBox")
TWasmFresnelRenderer.DrawElBorder("TMainForm.Body1.TDiv.GroupedBox")
and finally:
Wasm initialized, control now goes to Javascript event loop
So it appears that:
the WASM loads correctly;
the WASM executes;
Fresnel initializes;
the WASM renderer is active;
controls are being processed/rendered.
Current problem
The remaining error is:
Form resource TMainForm not found.
For resourceless forms CreateNew constructor must be used.
The browser then reports:
Wasm initialized, control now goes to Javascript event loop
but the actual form is not visible.
I checked the browser-specific entry point:
library wasmCombobox;
{$mode objfpc}{$H+}
uses
nothreads,
Fresnel,
Fresnel.Forms,
MainUnit;
begin
Application.Initialize;
Application.CreateFormNew(TMainForm, MainForm);
Application.Run;
end.
So I am already using:
Application.CreateFormNew(TMainForm, MainForm);
and not Application.CreateForm.
I also checked MainUnit.pas. TMainForm derives from TFresnelForm and has an explicit CreateNew constructor:
constructor TMainForm.CreateNew(aOwner: TComponent);
which calls:
inherited CreateNew(aOwner);
and creates the controls programmatically.
I also temporarily added a log at the beginning of TMainForm.CreateNew, but that message never appeared.
Therefore, it seems that TMainForm.CreateNew is not actually being called, despite the application using:
Application.CreateFormNew(TMainForm, MainForm);
Instead, Fresnel appears to be trying to locate a form resource named TMainForm.
Another important detail
I also tried following the apparent official browser compilation command:
ppcrosswasm32 -tbrowser @compile.cfg wasmCombobox.lpr
but my FPC installation reports:
Error: Subtarget BROWSER specified but no corresponding config file fpc-browser.cfg found.
Therefore, at the moment I am using:
-Twasip1
to generate the working WASM, with the _start workaround described above.
My questions are therefore:
Is -tbrowser the correct target for the current Fresnel WebAssembly backend?
If so, where should fpc-browser.cfg come from when using an FPC/Lazarus trunk installation created with fpcupdeluxe?
Is the Form resource TMainForm not found error a consequence of compiling the application with -Twasip1 instead of the Fresnel browser target?
Why does Application.CreateFormNew(TMainForm, MainForm) appear not to call TMainForm.CreateNew?
What is the recommended/current build procedure for the Fresnel ComboBox WebAssembly demo on Windows?
At this point the WASM is definitely executing and Fresnel's WASM renderer is producing output; the remaining issue is getting the actual TMainForm instance displayed correctly.
Thanks for any guidance.