DEV Community

Cover image for Go WebAssembly Meets WebForms Core 2.1
Elanat Framework
Elanat Framework

Posted on

Go WebAssembly Meets WebForms Core 2.1

WebAssembly is often used to move application logic into the browser and build increasingly large client-side applications.

WebForms Core takes a different approach.

Instead of making WebAssembly the frontend architecture, WebAssembly can be used as an execution layer inside a server-orchestrated UI architecture.

In this example, Go is compiled to WebAssembly and participates in the WebForms Core execution flow.

The examples in this article are designed to demonstrate the server-orchestrated capabilities of WebForms Core. They could also be configured differently so that some operations do not require server participation.

The general architecture is:

Server → WebForms → Commands → WebFormsJS → HTML DOM
Enter fullscreen mode Exit fullscreen mode

With WebAssembly, the architecture can also include a local execution layer:

Server → WebForms → WebAssembly → WebForms Commands → WebFormsJS → HTML DOM
Enter fullscreen mode Exit fullscreen mode

The important idea is that WebAssembly does not have to replace the UI architecture. It can become another execution capability inside that architecture.


What is WebForms Core?

WebForms Core is a server-orchestrated UI technology that allows the server to generate commands for manipulating the browser DOM and controlling UI behavior.

Its architecture can be summarized as:

Server → WebForms → Commands → WebFormsJS → HTML DOM
Enter fullscreen mode Exit fullscreen mode

WebForms Core does not require a separate frontend project, component framework, JSX, or a virtual DOM.

It works with standard HTML and lets the WebForms class generate UI operations.

WebFormsJS is responsible for interpreting and executing the resulting WebForms Core commands in the browser.

With WebAssembly support, selected methods can also execute locally in the browser.

This creates an important distinction:

WebAssembly can provide an execution layer without becoming the UI architecture.


Go WebAssembly

Go is a general-purpose programming language with built-in WebAssembly support.

Go can compile code directly to the WebAssembly target used by modern browsers:

GOOS=js
GOARCH=wasm
Enter fullscreen mode Exit fullscreen mode

A Go WebAssembly module can execute application logic in the browser while communicating with JavaScript through the Go WebAssembly runtime.

In this example, Go is used together with WebForms Core 2.1.

The Go module can:

  • execute numerical methods
  • receive parameters from JavaScript
  • create WebForms Core commands
  • return WebForms Core responses
  • generate HTML
  • participate in WebForms Core events

The important detail is that the Go code in this example does not manipulate the browser DOM directly.

Instead, it can use the WebForms class to generate a WebForms Core response.

The response can then be interpreted by WebFormsJS.

Go WebAssembly by WebForms Core Technology


Creating the Go WebAssembly Project

A Go WebAssembly project can be created as a normal Go module.

A typical project can contain:

your-project-name/
    go.mod
    main.go
    webformscore/
    build.bat
Enter fullscreen mode Exit fullscreen mode

The go.mod file defines the Go module:

module your-project-name

go 1.25.5
Enter fullscreen mode Exit fullscreen mode

The webformscore directory contains the Go implementation of the WebForms Core API.

The WebAssembly build can be automated with a Windows batch file:

@echo off

set GOOS=js
set GOARCH=wasm

go build -o webforms-go.wasm

for /f "delims=" %%i in ('go env GOROOT') do set GOROOT=%%i

copy "%GOROOT%\lib\wasm\wasm_exec.js" wasm_exec.js

pause
Enter fullscreen mode Exit fullscreen mode

The resulting WebAssembly module is:

webforms-go.wasm
Enter fullscreen mode Exit fullscreen mode

Go WebAssembly Runtime

Unlike a minimal WebAssembly module that can be instantiated directly through the WebAssembly JavaScript API, Go WebAssembly applications use the Go browser runtime.

The runtime is provided by:

wasm_exec.js
Enter fullscreen mode Exit fullscreen mode

The WebForms Core application therefore keeps both files available to the browser:

/web-assembly/go/
    webforms-go.wasm
    wasm_exec.js
Enter fullscreen mode Exit fullscreen mode

webforms-go.wasm contains the compiled Go application.

wasm_exec.js provides the JavaScript-side Go runtime required to execute the Go WebAssembly module.

WebForms Core can load this runtime automatically when a Go WebAssembly method is requested.


Install the Go Package

The Go implementation of WebForms Core can be installed as a Go module.

CLI:

go get github.com/webforms-core/go
Enter fullscreen mode Exit fullscreen mode

github.com/webforms-core/go provides the WebForms Core API used by the Go implementation.


WebFormsJS Installation via Package

WebFormsJS is available through npm.

JavaScript in npm: webformsjs on npm

CLI:

npm install webformsjs
Enter fullscreen mode Exit fullscreen mode

WebFormsJS is also available directly from the following GitHub repository:

WebFormsJS GitHub Repository

If you install WebFormsJS through npm, the package can be imported and used directly in your JavaScript project.

Alternatively, the source files can be obtained from the GitHub repository.


Using WebForms Core from Go

The interesting part of this example is that the Go WebAssembly code uses the WebForms Core API directly.

The main.go file contains the exported JavaScript-facing methods:

package main

import (
    "syscall/js"

    WebFormsCore "your-project-name/webformscore"
)

func add(this js.Value, args []js.Value) interface{} {
    a := int32(args[0].Int())
    b := int32(args[1].Int())

    return a + b
}

func setData(this js.Value, args []js.Value) interface{} {
    inputPlace := args[0].String()
    text := args[1].String()
    backgroundColor := args[2].String()
    fontSize := args[3].String()

    form := WebFormsCore.New()

    form.SetText(inputPlace, text)
    form.SetBackgroundColor("-", backgroundColor)
    form.SetFontSize("-", fontSize)

    return form.Response()
}

func getHtml(this js.Value, args []js.Value) interface{} {
    return "<marquee>Tag From Wasm!</marquee>"
}

func main() {
    js.Global().Set("add", js.FuncOf(add))
    js.Global().Set("setData", js.FuncOf(setData))
    js.Global().Set("getHtml", js.FuncOf(getHtml))

    select {}
}
Enter fullscreen mode Exit fullscreen mode

There are three methods used by the WebForms Core example:

  • add
  • setData
  • getHtml

Each demonstrates a different way a Go WebAssembly method can participate in the WebForms Core execution model.


add

The add method performs a simple calculation:

add(10000, 3)
Enter fullscreen mode Exit fullscreen mode

It returns:

10003
Enter fullscreen mode Exit fullscreen mode

The method receives two numeric arguments through the JavaScript-to-Go WebAssembly interface.

This demonstrates a basic WebAssembly method that returns a value.

However, WebForms Core can also use WebAssembly methods that produce UI responses.


setData

The setData method receives four strings:

inputPlace
text
backgroundColor
fontSize
Enter fullscreen mode Exit fullscreen mode

It creates a WebForms object and generates a WebForms Core response:

form := WebFormsCore.New()

form.SetText(inputPlace, text)
form.SetBackgroundColor("-", backgroundColor)
form.SetFontSize("-", fontSize)

return form.Response()
Enter fullscreen mode Exit fullscreen mode

The important detail is that the Go method is not returning JavaScript DOM operations.

It is generating a WebForms Core response.

That response can then be interpreted by WebFormsJS.


getHtml

The third method returns HTML:

<marquee>Tag From Wasm!</marquee>
Enter fullscreen mode Exit fullscreen mode

The HTML can then be placed into the browser through a WebForms Core event.

This demonstrates that a WebAssembly method can also return content that participates in the WebForms Core output flow.


The WebForms Class in Go

The important architectural detail is that WebForms is not a browser component.

The Go code uses it as a command generator.

For example:

form := WebFormsCore.New()

form.SetText(inputPlace, text)
form.SetBackgroundColor("-", backgroundColor)
form.SetFontSize("-", fontSize)

return form.Response()
Enter fullscreen mode Exit fullscreen mode

The resulting response is interpreted by WebFormsJS in the browser.

Therefore, the flow becomes:

Go
 ↓
WebForms
 ↓
WebForms Core Commands
 ↓
WebFormsJS
 ↓
HTML DOM
Enter fullscreen mode Exit fullscreen mode

Go does not need to know how WebFormsJS applies the commands to the browser DOM.

That responsibility belongs to WebFormsJS.

This separation allows the Go WebAssembly layer to focus on application logic and command generation while WebFormsJS remains the browser-side UI runtime.


Go WebAssembly and JavaScript

Go WebAssembly uses syscall/js to communicate with the browser.

In this example, the Go methods are registered as JavaScript functions:

js.Global().Set("add", js.FuncOf(add))
js.Global().Set("setData", js.FuncOf(setData))
js.Global().Set("getHtml", js.FuncOf(getHtml))
Enter fullscreen mode Exit fullscreen mode

This makes the functions available to the WebAssembly execution layer.

For example, after the Go runtime is initialized, the JavaScript environment can access:

add
setData
getHtml
Enter fullscreen mode Exit fullscreen mode

WebFormsJS can therefore invoke these methods as part of the WebForms Core execution flow.

The important distinction is that JavaScript provides the browser integration required by the Go WebAssembly runtime, while WebFormsJS provides the WebForms Core browser-side execution environment.


Using Go WebAssembly from WebForms Core

The server-side controller can invoke Go WebAssembly methods through the WebForms Core WASM API.

The controller is:

using CodeBehind;

public partial class WasmGOController : CodeBehindController
{
    public void PageLoad(HttpContext context)
    {
        string WasmPath = "/web-assembly/go/webforms-go.wasm"; 
        //string WasmPath = "/web-assembly/go/wasm_exec.js"; 

        WebForms form = new WebForms();

        form.AddText("<b>", Fetch.WasmMethod(WasmLanguage.GO, WasmPath, "add", [10000, 3]));

        form.SetWasmEvent("WasmEvent", HtmlEvent.OnClick, WasmLanguage.GO, WasmPath, "setData", ["h3Tag", "Text From Wasm", "lightgreen", "30px"]);
        form.SetWasmEvent("WasmEventWithOutput", HtmlEvent.OnClick, WasmLanguage.GO, WasmPath, "getHtml", [], "WasmHtmlOutput");

        Write(form.ExportToHtmlComment());
    }
}
Enter fullscreen mode Exit fullscreen mode

The controller does not contain the Go implementation details.

It defines how the WebAssembly methods participate in the WebForms Core UI flow.

This is an important separation:

Server-side controller
        ↓
WebForms Core definition
        ↓
WebAssembly method
        ↓
WebForms response
        ↓
WebFormsJS
Enter fullscreen mode Exit fullscreen mode

HTML

The page itself remains ordinary HTML:

@page
@controller WasmGOController
@layout "/layout.aspx"
@{
  ViewData.Add("title","GO Wasm");
}
<h3>GO Wasm</h3>
<b>GO WASM Result: </b>
<br>
<button id="WasmEvent">Wasm Event</button>
<br>
<h3 id="h3Tag">Wasm Tag Changing!</h3>
<button id="WasmEventWithOutput">Wasm Event With Output</button>
<p id="WasmHtmlOutput">Wasm Html Output</p>
Enter fullscreen mode Exit fullscreen mode

There is no Go-specific markup.

There is no custom WebAssembly element.

There is no component declaration.

The HTML remains standard HTML.

WebForms Core can assign behavior to these existing HTML elements without requiring the page to be redesigned around WebAssembly.


The Interesting Part

The interesting part is not simply that Go can run inside WebAssembly.

The more important point is that a WebAssembly method can participate in the WebForms Core command architecture.

A Go method can return a normal value:

Go → Value
Enter fullscreen mode Exit fullscreen mode

But it can also generate a WebForms Core response:

Go → WebForms → Commands → WebFormsJS → DOM
Enter fullscreen mode Exit fullscreen mode

For example:

form.AddText(
    "<b>",
    Fetch.WasmMethod(
        WasmLanguage.GO,
        WasmPath,
        "add",
        [10000, 3]
    )
);
Enter fullscreen mode Exit fullscreen mode

The add method is implemented in Go, but its result can be consumed by WebForms Core.

The second method is more interesting:

form.SetWasmEvent(
    "WasmEvent",
    HtmlEvent.OnClick,
    WasmLanguage.GO,
    WasmPath,
    "setData",
    ["h3Tag", "Text From Wasm", "lightgreen", "30px"]
);
Enter fullscreen mode Exit fullscreen mode

When the button is clicked, WebFormsJS can invoke the Go WebAssembly method.

The method creates a WebForms response:

form := WebFormsCore.New()

form.SetText(inputPlace, text)
form.SetBackgroundColor("-", backgroundColor)
form.SetFontSize("-", fontSize)

return form.Response()
Enter fullscreen mode Exit fullscreen mode

The response is then interpreted by WebFormsJS.

The resulting execution chain is:

HTML Event
    ↓
WebFormsJS
    ↓
Go WASM
    ↓
WebForms
    ↓
WebForms Core Response
    ↓
WebFormsJS
    ↓
DOM
Enter fullscreen mode Exit fullscreen mode

This is different from simply calling a WebAssembly function and returning a number.

The WebAssembly method can become a producer of UI commands.

That is what allows Go WebAssembly to participate in the WebForms Core UI execution model.


WASM Event With Output

The third method demonstrates another possibility:

form.SetWasmEvent(
    "WasmEventWithOutput",
    HtmlEvent.OnClick,
    WasmLanguage.GO,
    WasmPath,
    "getHtml",
    [],
    "WasmHtmlOutput"
);
Enter fullscreen mode Exit fullscreen mode

The Go method returns HTML:

func getHtml(this js.Value, args []js.Value) interface{} {
    return "<marquee>Tag From Wasm!</marquee>"
}
Enter fullscreen mode Exit fullscreen mode

WebForms Core can then place the returned value into:

<p id="WasmHtmlOutput">Wasm Html Output</p>
Enter fullscreen mode Exit fullscreen mode

This demonstrates that WebAssembly methods can participate directly in the WebForms Core output flow.


Where Does the Execution Take Place?

This architecture does not require every operation to execute on the server.

The server can generate the initial WebForms Core commands and define the UI behavior, while selected WebAssembly methods can execute locally in the browser.

For an interactive event, the flow can be:

Browser Event
    ↓
WebFormsJS
    ↓
Go WebAssembly
    ↓
WebForms Response
    ↓
WebFormsJS
    ↓
HTML DOM
Enter fullscreen mode Exit fullscreen mode

This allows the application to keep a server-orchestrated UI model while selectively executing code locally in the browser through WebAssembly.

The examples in this article intentionally demonstrate this integration with WebForms Core. Other configurations can reduce or eliminate server participation for selected operations.


Go Is an Execution Layer

This example demonstrates an important distinction.

WebAssembly is not being used here to build a complete frontend application.

Go is being used as an execution layer.

The UI architecture remains:

HTML
  +
WebForms Core
  +
WebFormsJS
Enter fullscreen mode Exit fullscreen mode

Go WebAssembly is inserted where local WebAssembly execution provides value:

                 WebForms Core
                      │
             ┌────────┴────────┐
             │                 │
       Server WebForms      Go WASM
                               │
                              Go
Enter fullscreen mode Exit fullscreen mode

This allows the application to use WebAssembly selectively instead of moving the entire application into a WebAssembly frontend.


No Custom JavaScript Required for These UI Operations

In this example, the application does not need custom JavaScript business logic to perform these UI operations.

The Go method performs the computation or generates the WebForms Core response.

WebFormsJS remains the browser runtime responsible for executing the resulting commands.

Therefore, the flow is:

Go → WebForms Commands → WebFormsJS → DOM
Enter fullscreen mode Exit fullscreen mode

rather than requiring a separate custom JavaScript layer between the Go code and the UI.

This separation keeps the WebAssembly layer independent from the application's browser-side DOM implementation.


Standard HTML Remains the UI

The Go example does not introduce a new component model.

The page still contains standard HTML:

<h3 id="h3Tag">Wasm Tag Changing!</h3>
Enter fullscreen mode Exit fullscreen mode

and:

<button id="WasmEvent">Wasm Event</button>
Enter fullscreen mode Exit fullscreen mode

The server assigns behavior to these existing elements.

This is one of the important characteristics of WebForms Core.

WebAssembly does not require the UI to be redesigned around WebAssembly components.

The HTML remains the UI, while WebForms Core and WebFormsJS provide the command and execution layers.


Go and WebForms Core

The Go implementation demonstrates that a WebAssembly language can use the same WebForms Core model as other supported languages.

The important relationship is:

Go
 ↓
WebForms Class
 ↓
Action Controls / Response
 ↓
WebFormsJS
 ↓
Browser DOM
Enter fullscreen mode Exit fullscreen mode

The WebForms class acts as the bridge between application logic and WebForms Core command generation.

This makes the WebAssembly module more than an isolated computational library.

It can participate in the UI execution model.


WebAssembly Does Not Have to Replace the UI Architecture

A common approach to WebAssembly applications is to move a large portion of the frontend into the WebAssembly runtime.

WebForms Core takes a different approach.

WebAssembly can be introduced only where it provides value.

For example, an application can continue using:

  • standard HTML
  • server-side WebForms
  • WebFormsJS
  • server-generated commands

while selectively executing Go code through WebAssembly.

This makes WebAssembly an execution capability rather than a mandatory application architecture.

The result is a hybrid execution model in which the UI architecture remains based on HTML and WebForms Core while WebAssembly can provide additional local execution capabilities.


Go WebAssembly and WebFormsJS

Go provides the WebAssembly execution environment, while WebFormsJS remains responsible for browser-side UI execution.

A simple method can be written as:

func add(this js.Value, args []js.Value) interface{} {
    a := int32(args[0].Int())
    b := int32(args[1].Int())

    return a + b
}
Enter fullscreen mode Exit fullscreen mode

The method executes inside the Go WebAssembly environment.

When combined with WebForms Core, the overall flow can be represented as:

Server
  ↓
WebForms
  ↓
WebAssembly Method
  ↓
Go
  ↓
WebForms Response
  ↓
WebFormsJS
  ↓
DOM
Enter fullscreen mode Exit fullscreen mode

The browser therefore remains responsible for UI execution while Go provides a WebAssembly execution layer.


WebForms Core 2.1 and WebAssembly Languages

WebForms Core 2.1 allows the WebAssembly execution layer to work with different programming languages while keeping the UI command architecture unchanged.

In this example, Go provides the WebAssembly implementation.

The same architectural model can be used with other supported WebAssembly languages:

                 WebForms Core
                       │
          ┌────────────┼────────────┐
          ↓            ↓            ↓
       Go WASM      C# WASM      Rust WASM
          │            │            │
          └────────────┼────────────┘
                       ↓
                  WebFormsJS
                       ↓
                      DOM
Enter fullscreen mode Exit fullscreen mode

The WebAssembly implementation can change without requiring the HTML UI to be redesigned around a language-specific component model.

The UI command architecture remains the same.


Final Result

The final application combines four technologies:

CodeBehind
     ↓
WebForms Core 2.1
     ↓
Go WebAssembly
     ↓
WebFormsJS
Enter fullscreen mode Exit fullscreen mode

Each layer has a different responsibility.

CodeBehind provides the server-side application environment.

WebForms Core provides the command-generation and UI orchestration model.

Go WebAssembly provides a local execution layer in the browser.

WebFormsJS provides the browser-side execution environment.

HTML remains the UI.

The result is a WebAssembly-enabled application model without requiring a separate WebAssembly frontend architecture.


Conclusion

Go WebAssembly does not have to become the frontend architecture.

With WebForms Core 2.1, Go can be used as a WebAssembly execution layer inside a server-orchestrated UI architecture.

The resulting model can be represented as:

Server → WebForms → WebAssembly → WebForms Commands → WebFormsJS → DOM
Enter fullscreen mode Exit fullscreen mode

Go can perform computation, respond to browser events, generate WebForms Core responses, and participate in interactive UI operations.

At the same time, the application can continue using standard HTML and WebForms Core commands.

The key idea is simple:

WebAssembly can be an execution layer without becoming the UI architecture.


Related Links

In Elanat:

In GitHub:

In PKG:

Top comments (0)