Mastering Flutter with Golang WebAssembly: A Step-by-Step Guide
What is WebAssembly?
WebAssembly is low-level binary format, closer to machine code than JavaScript. When compiled, a WebAssembly module can achieve performance levels close to native execution. Unlike JavaScript, which relies on a text-based language requiring parsing and interpretation, WebAssembly files are delivered in a binary format, significantly smaller and quicker to decode and execute.
Why Choose WebAssembly?
The adoption of WebAssembly in web development is driven by the constraints of JavaScript. While JavaScript has long been the go-to language for the web, it was not originally crafted to meet the performance demands of contemporary web applications. JavaScript code can face challenges in terms of download speed, parsing efficiency, and execution, especially on mobile devices with limited resources.
Enter WebAssembly. With WebAssembly, developers can script in languages like C, C++, Rust, Go and Dart, compile their code into a WebAssembly module, and execute it in the browser at nearly native speed. This capability empowers the creation of web applications that boast enhanced speed, efficiency, and responsiveness.
What is Flutter?
Flutter, created and maintained by Google, is an open-source framework. It serves as a tool for creating the user interface (UI) of applications across various platforms using a unified codebase. It now facilitates application development on next platforms: iOS, Android, the web, Windows, MacOS, and Linux.
The advantages of Flutter
Flutter interesting as a cross-platform development framework in several ways:
- Near-Native Performance: Flutter utilizes the Dart programming language, compiling into machine code.
- Swift, Consistent, and Customizable Rendering: Instead of depending on rendering tools specific to each platform, Flutter uses Skia graphic library for UI rendering. This approach guarantees uniform visuals across various platforms, offering users a consistent experience.
- Developer-Friendly Tools: Google designed Flutter with a strong emphasis on user-friendliness. Tools like hot reload allow developers to preview code changes seamlessly without losing state. Additionally, features like the widget inspector simplify the identification and resolution of issues related to UI layouts.
Interoperability Between Dart(Flutter) and WebAssembly
Dart code can be compiled and run on platforms that support JavaScript. This platform flexibility allows us to seamlessly call existing JavaScript code within our Dart code, aided by the JavaScript bindings offered through the js package.
This mutual calling of JavaScript code from Dart and Dart code from JavaScript is commonly called “Dart-JavaScript interop.”
he js package provides us with annotations and functions to describe the interaction between our Dart code and JavaScript code. In the JavaScript API, the WebAssembly object serves as the namespace that houses all WebAssembly-related functions. This includes loading WebAssembly modules, creating new memory and table instances, and managing WebAssembly errors.
WebAssembly manifests in two file formats:
- .wasm: binary assembly code and functioning as the executable file.
- .wat: human-readable text format of the .wasm file, compiling to .wasm. Primarily utilized for editing or debugging purposes.
To interact with WebAssembly in our Dart web code, we use the WebAssembly JavaScript object through js bindings.
To use js bindings in our Dart code, add the @JS annotation to the method and precede it with the external keyword:
@JS('WebAssembly.instantiate')
external Object instantiate(Object bytesOrBuffer, Object import);
Using WebAssembly modules in a Flutter app
We need to do next steps:
- Edit wasm_exec.js and include a wrapper for GoRuntime:
2. Edit pubspec.yaml and add next instructions:
dependencies:
wasm_interop: ^2.0.1
flutter:
assets:
- assets/wasm/
3. Move the WebAssembly (wasm) file generated from your Golang code to the “assets/wasm” folder.
4. Add mention about wasm_exec.js in index.html:
... your code ...
<script src="wasm_exec.js" type="application/javascript"></script>
... your code ...
5. Implement wasm_loader.dart:
6. Implement helper go.dart to access functions from wasm:
7. Use it in widget:
import 'package:gotalk/widgets/wasm_loader.dart';
import 'dart:html' as html;
import 'package:gotalk/helpers/go.dart';
...your code ...
late WasmLoader loader;
Future<void> _init() async {
loader = WasmLoader(path: 'assets/wasm/gocode.wasm');
final isLoaded = await loader.initialized();
if (isLoaded) {
loader.callRun();
setState(() {});
}
}
void _evalCommand() {
try {
var jsWindow = html.window as JSWindow;
var result = jsWindow.evalCommand(_inputController.text).toString();
if (result != null) {
setState(() {
_inputController.text = "${_inputController.text} $result";
});
}
} catch (e) {
print('Unknown exception: $e');
}
}
... your code ...
Congratulations, you’re now ready to integrate Go WebAssembly into your Flutter projects. Look at the example GotalkInterpreter . =)