Web Assembly
Based on ❤️ wasmoon
The lrocket-build-wasm compiler extension adds three WebAssembly build targets to lrc: .html, .js and .wasm.
It is based on the wasmoon project and works by loading base64-encoded versions of custom-tailored Lua binaries. This allows to embed compiled Lua bundles and native Lua modules (e.g. written in C) via WebAssembly.
The result is a single Javascript file which runs Lua code that can interact with the DOM / Javascript APIs and vice versa – meaning that other <script>-tags can interact with variables and functions provided by Lua (see Interacting with Javascript APIs).
Requirements
Compiling for Web Browsers
Usage with LuaRocks [ Recommended ]
To use the extension via the LuaRocks package manager, simply create a rockspec-file with the following contents:
Note The LRocket LuaRocks Integration will automatically install the
lrocket-build-wasmpackage when theotypeis set towasm[-...]in your rockspec. LuaRocksv3.11.0+will even install the LRocket integration automatically when the buildtypeis set tolrocket.
-- lua-example-website-scm-0.rockspec
...
build = {
type = 'lrocket',
otype = 'wasm-html' -- or 'wasm-js' or 'wasm'
entrypoint = 'main.lua'
output = 'main.html'
}
Command-Line Usage
The extension provides three targets for WebAssembly:
Javascript
You can compile to Javascript, to include your Lua code as Javascript module:
> lrc --otype wasm-js main.lua -o output-lib.js
HTML
You can compile directly to HTML, to write your complete page in Lua (starting off with document.body.innerHTML = [[...]]):
> lrc --otype wasm-html main.lua -o index.html
WASM
Or compile to .wasm to handle the embedding into the libwasmoon template yourself:
> lrc --otype wasm main.lua -o lua-module.wasm
If you would like to handle the compilation yourself (e.g. use a different compiler than lrc) virtually any compiler that targets wasm32 can be used to build your own Lua binary script.
For details see Using a Different Compiler.
Interacting with Javascript APIs
Libwasmoon makes the window-object available inside the global Lua environment – This allows to use any desired Javascript API via Lua syntax!
All is made possible by the fantastic work of the wasmoon project!
Examples
Button Callback
document.innerHTML = '<button>Click me!</button>'
local button = document.querySelector 'button'
button.addEventListener('click', function()
alert('Lua function called!')
end)
Lua Function in Javascript
Tip
selfis an alias for thewindowobject and since Javascript compiled with lrc works in Service Workers too, it is good practice to useselfas it works in both regular and Service Worker contexts:
To export a function to the global Javascript environment you can add it to the self object:
-- better: self.myLuaFunction()
function window.myLuaFunction()
return math.random(1, 42)
end
// in javascript
alert('The answer to everything is: ' + myLuaFunction());
Geo Location
navigator.geolocation.getCurrentPosition(function(loc)
-- prints to console.log()
print('You are here', loc.coords.latitude, loc.coords.longitude)
end)
Advanced Use
Using a Different Compiler
Any compiler that targets wasm32 (ideally wasm32-wasip1 / wasm32-wasip1-threads) can be used to build the binary that will be embedded into the libwasmoon template.
The compiled binary should export a symbol named void __lr_entrypoint(lua_State *L) (called by libwasmoon after the Lua-state has been initialized).
We recommend linking against lua-wasm32, which is a static lua library (the one lrc links against when compiling bundles for WebAssembly). It is available via luarocks (note that the rock also ships a copy of the libwasmoon template):
> luarocks install lua-wasm32
For example, the clang-compiler could be used to compile a custom lua interpreter which can then be embedded into the libwasmoon template:
> clang --target=wasm32-wasip1-threads -o lua-module.wasm my-custom-interpreter.c \
<path-to-lua-wasm32>/lib/liblua-5.4.a
Turining lua-module.wasm into Javascript:
> sed dist/loader.js.tpl "s/{{libwasmoon:wasm_bytes}}/$(base64 -w0 lua-module.wasm)/g" > \
output-lib.js
Using the module in HTML:
<!DOCTYPE html>
<body></body>
<script src="output-lib.js"></script>
You may also embed the script between an inline <script>...</script>-tag.