<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Webassembly on despatches</title><link>https://icle.es/tags/webassembly/</link><description>Recent content in Webassembly on despatches</description><generator>Hugo</generator><language>en</language><lastBuildDate>Fri, 19 Sep 2025 14:19:34 +0100</lastBuildDate><atom:link href="https://icle.es/tags/webassembly/index.xml" rel="self" type="application/rss+xml"/><item><title>Using `locateFile` to have js and wasm in different locations with emscripten</title><link>https://icle.es/2025/09/18/using-locatefile-to-have-js-and-wasm-in-different-locations-with-emscripten/</link><pubDate>Thu, 18 Sep 2025 10:15:42 +0100</pubDate><guid>https://icle.es/2025/09/18/using-locatefile-to-have-js-and-wasm-in-different-locations-with-emscripten/</guid><description>&lt;p>As part of building &lt;a href="https://icle.es/excursions/shine.md">shine&lt;/a>, I am using
&lt;a href="https://lume.land">lume&lt;/a> and webassembly with zig.&lt;/p>
&lt;p>zig, through emscripten generates both a js and wasm file, which, by default are
expected to be in the same directory.&lt;/p>
&lt;p>I wanted to put them in different places, and struggled to get that working with
lume for a bit. I did eventually solve it though:&lt;/p>
&lt;h2 id="include-emscripten-js-file">Include emscripten js file&lt;/h2>
&lt;p>Firstly, the js file output from emscripten should be included in you page
manually. I had used &lt;code>site.add&lt;/code> which meant that it was loaded &lt;em>before&lt;/em> we could
put the override for &lt;code>locateFile&lt;/code> in &lt;code>window.Module&lt;/code>.&lt;/p></description><content:encoded><![CDATA[<p>As part of building <a href="https://icle.es/excursions/shine.md">shine</a>, I am using
<a href="https://lume.land">lume</a> and webassembly with zig.</p>
<p>zig, through emscripten generates both a js and wasm file, which, by default are
expected to be in the same directory.</p>
<p>I wanted to put them in different places, and struggled to get that working with
lume for a bit. I did eventually solve it though:</p>
<h2 id="include-emscripten-js-file">Include emscripten js file</h2>
<p>Firstly, the js file output from emscripten should be included in you page
manually. I had used <code>site.add</code> which meant that it was loaded <em>before</em> we could
put the override for <code>locateFile</code> in <code>window.Module</code>.</p>
<p>I am using the
<a href="https://github.com/lumeland/theme-simple-blog">simple-blog theme</a>, so I add the
following line to the top of <code>src/index.vto</code></p>
```html
<script defer src="/js/shine.js"></script>
```
<h2 id="override-module">Override <code>Module</code></h2>
<p>You can override how emscripten finds the wasm file in the
<a href="https://emscripten.org/docs/api_reference/module.html#Module.locateFile">Module Object</a>.</p>
<p>This can be done in the html file in a script block, or even better, in a js
file that is included automatically.</p>
<p><code>js/main.js</code> felt like a good place.</p>
```javascript
window.Module = {
  locateFile: function (path, scriptDirectory) {
    if (path === "shine.wasm") {
      return "/static/shine/shine.wasm";
    } else {
      return scriptDirectory + path;
    }
  },
};
```
<h2 id="closing">Closing</h2>
<p>With this setup, I can not only have the js and wasm files in different
locations, it&rsquo;s also easy to modify / augment the <code>Module</code> object.</p>
]]></content:encoded></item><item><title>Calling Javascript from Zig through WebAssembly</title><link>https://icle.es/2025/09/17/calling-javascript-from-zig-through-webassembly/</link><pubDate>Wed, 17 Sep 2025 15:52:20 +0100</pubDate><guid>https://icle.es/2025/09/17/calling-javascript-from-zig-through-webassembly/</guid><description>&lt;p>The next step for &lt;a href="https://icle.es/excursions/shine.md">shine&lt;/a> is to build a bridge
between &lt;a href="https://icle.es/tags/zig">zig&lt;/a> and &lt;a href="https://icle.es/tags/javascript">javascript&lt;/a>.&lt;/p>
&lt;p>I am currently planning to using &lt;a href="https://supabase.com/">supabase&lt;/a> for storage.
Unsurprisingly, it does not have a zig sdk. It does, however, have a javascript
sdk.&lt;/p>
&lt;p>If I can write basic CRUD operations in javascript and call that from zig
through webassembly, that could make that integration a lot easier.&lt;/p>
&lt;h2 id="goals">Goals&lt;/h2>
&lt;p>There are a few ideal restrictions for me - mainly because writing javascript is
not fun for me.&lt;/p></description><content:encoded><![CDATA[<p>The next step for <a href="https://icle.es/excursions/shine.md">shine</a> is to build a bridge
between <a href="https://icle.es/tags/zig">zig</a> and <a href="https://icle.es/tags/javascript">javascript</a>.</p>
<p>I am currently planning to using <a href="https://supabase.com/">supabase</a> for storage.
Unsurprisingly, it does not have a zig sdk. It does, however, have a javascript
sdk.</p>
<p>If I can write basic CRUD operations in javascript and call that from zig
through webassembly, that could make that integration a lot easier.</p>
<h2 id="goals">Goals</h2>
<p>There are a few ideal restrictions for me - mainly because writing javascript is
not fun for me.</p>
<ul>
<li>Use the Supabase js/ts library through zig</li>
<li>Use TypeScript as much as possible. (I don&rsquo;t love TypeScript, but at least
it&rsquo;s not javascript)</li>
<li>Keep as much of the supabase related code in the web part so that
<a href="https://icle.es/tags/deno">deno</a> and <a href="https://icle.es/tags/lume">lume</a> can handle any heavy lifting.</li>
</ul>
<h2 id="options">Options</h2>
<p>I can&rsquo;t use FFI(Foreign Function Interface):</p>
```zig
extern "env" fn jsLog(ptr: [*]const u8, len: usize) void;
```
```javascript
const wasm = await WebAssembly.instantiateStreaming(fetch("prog.wasm"), {
  env: {
    jsLog: (ptr, len) => {
      /* read from memory and console.log */
    },
  },
});
```
<p>because imgui pulls in emscripten, which means we don&rsquo;t have the ability to call
<code>instantiateStreaming</code>.</p>
<p>With emscripten, declaring an external function is easy enough.</p>
```zig
extern fn jsLog(ptr: [*]const u8, len: usize) void;
```
<p>There are a couple of options to wire them up to the javascript:</p>
<h3 id="libraryjs--mergeinto"><code>library.js</code> / <code>mergeInto</code></h3>
<p>This option requires javascript files on the zig side. If you want to start with
typescript, you&rsquo;ll need to integrate a transpiler into the build chain as well.</p>
<p>First, you want a javascript file - let&rsquo;s call it <code>libshine.js</code>, and pop it into
a <code>js</code> dir.</p>
```javascript
// js/libshine.js
// Emscripten will provide these globals at link/runtime
declare var mergeInto: (lib: any, funcs: Record<string, Function>) => void;
declare var LibraryManager: { library: any };
declare function UTF8ToString(ptr: number, len?: number): string;

mergeInto(LibraryManager.library, {
  jsLog: (ptr: number) => {
    const msg = UTF8ToString(ptr);
    console.log("🟢 Zig says:", msg);
  },
});
```
<p>We then need to pass this <code>js</code> file into the build step</p>
<p>as part of my sokol build step, I pass it in as <code>.extra_args</code>.</p>
```zig
// create a build step which invokes the Emscripten linker
const link_step = try sokol.emLinkStep(b, .{
    .lib_main = shine,
    .target = opts.mod_main.resolved_target.?,
    .optimize = opts.mod_main.optimize.?,
    .emsdk = dep_emsdk,
    .use_webgl2 = true,
    .use_emmalloc = true,
    .use_filesystem = false,
    .shell_file_path = opts.dep_sokol.path("src/sokol/web/shell.html"),
    // set the js file here
    .extra_args = &.{
        "--js-library", "js/libshine.js",
    },
});
```
<p>We can then call it from zig, with something like:</p>
```zig
pub fn main() void {
    jsLog("hello from zig");
}

extern fn jsLog(ptr: [*]const u8) void;
```
<p>From my firefox console:</p>
```
Lume live reloading is ready. Listening for changes...     localhost:3000:102:15
🟢 Zig says: hello from zig                                shine.js:3168:11
```
<h3 id="em_js--em_asm"><code>EM_JS</code> / <code>EM_ASM</code></h3>
<p>The other option is to use
<a href="https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#interacting-with-code-call-javascript-from-native"><code>EM_JS</code></a>
which involves writing a wee bit of <code>C</code>, which can embed the <code>javascript</code>.</p>
<p>In theory, it&rsquo;s as simple as:</p>
```c
#include <emscripten.h>

EM_JS_DEPS(bla, "$UTF8ToString");

EM_JS(void, jsLog, (const char* s), {
  console.log(UTF8ToString(s));
});
```
<p>and adding it into the build file:</p>
```zig
// build the main file into a library, this is because the WASM 'exe'
// needs to be linked in a separate build step with the Emscripten linker
const shine = b.addLibrary(.{
    .name = "shine",
    .root_module = opts.mod_main,
});

// get the Emscripten SDK dependency from the sokol dependency
const dep_emsdk = opts.dep_sokol.builder.dependency("emsdk", .{});

// need to inject the Emscripten system header include path into
// the cimgui C library otherwise the C/C++ code won't find
// C stdlib headers
const emsdk_incl_path = dep_emsdk.path("upstream/emscripten/cache/sysroot/include");

shine.root_module.addCSourceFile(.{
    .file = b.path("src/libjs.c"),
    .flags = &.{}, // optional extra emcc flags
});
shine.addSystemIncludePath(emsdk_incl_path);
```
<p>The calling code in <code>main.zig</code> remains the same:</p>
```zig
pub fn main() void {
    jsLog("hello from zig");
}

extern fn jsLog(ptr: [*]const u8) void;
```
<p>However, this didn&rsquo;t work, and failed with:</p>
```
error: undefined symbol: jsLog (referenced by root reference (e.g. compiled C/C++ code))
warning: To disable errors for undefined symbols use `-sERROR_ON_UNDEFINED_SYMBOLS=0`
warning: _jsLog may need to be added to EXPORTED_FUNCTIONS if it arrives from a system library
Error: Aborting compilation due to previous errors
```
<p>Thanks to
<a href="https://ziggit.dev/t/help-with-getting-a-simple-call-to-js-through-emscripten-working/12090/3">some help</a>
from <a href="https://ziggit.dev/u/floooh">flooh</a> (who btw put together the
<a href="https://github.com/floooh/sokol">sokol</a> and
<a href="https://github.com/floooh/sokol-zig">sokol-zig</a> packages as well the
<a href="https://github.com/floooh/sokol-zig-imgui-sample">sokol-imgui-sample</a> template
which I used to kick start this project.), I was able to get it working.</p>
<p>Turns out the c file needs to have a function in it that is used in the zig
file - it doesn&rsquo;t need to do anything.</p>
<p>So, based on the suggestion, <code>libjs.c</code> changes to:</p>
```c
#include <emscripten.h>

EM_JS_DEPS(bla, "$UTF8ToString");

EM_JS(void, jsLog, (const char* s), {
  console.log(UTF8ToString(s));
});

void dummy(void) {};
```
<p>and in <code>main.zig</code>:</p>
```zig
pub fn main() void {
    dummy();
    jsLog("hello from zig");
}

extern fn jsLog(ptr: [*]const u8) void;

extern fn dummy() void;
```
<p>From my firefox console:</p>
```
Lume live reloading is ready. Listening for changes...     localhost:3000:102:15
🟢 Zig says: hello from zig                                shine.js:3168:11
```
<p>You can see a working example in [my forked repo](</p>
<h2 id="em_js-directly-through-zig-unsuccessful"><code>EM_JS</code> directly through <code>zig</code> [unsuccessful]</h2>
<p>Looking at the macro for <code>EM_JS</code> and with my good friend ChatGPT, I attempted
translating it to zig and made some progress, but ultimately failed to get it
working. I&rsquo;ll leave the work here in the hopes it might be helpful.</p>
```c
#define _EM_JS(ret, c_name, js_name, params, code)                             \
  _EM_BEGIN_CDECL                                                              \
  ret c_name params EM_IMPORT(js_name);                                        \
  __attribute__((visibility("hidden")))                                        \
  void* __em_js_ref_##c_name = (void*)&c_name;                                 \
  EMSCRIPTEN_KEEPALIVE                                                         \
  __attribute__((section("em_js"), aligned(1))) char __em_js__##js_name[] =    \
    #params "<::>" code;                                                       \
  _EM_END_CDECL
```
<p>The above macro translates to zig roughly (with help from ChatGPT) as:</p>
```zig
extern fn jsLog(ptr: [*]const u8) void;

/// 2. Keep a reference to avoid the linker removing the function.
///    Same role as __em_js_ref_* in the C macro.
pub export const __em_js_ref_jsLog = &jsLog;

/// 3. Embed the JS implementation in a special section called "em_js".
///    Emscripten will scan this and inject the code into the output JS.
export const __em_js__jsLog align(1) linksection("em_js") =
    "(const char* s)<::>{ console.log(UTF8ToString(s)); }\x00";

pub export fn dummy() void {}
```
<p>I added a <code>pub fn</code> and called it from main:</p>
```zig
pub fn log(ptr: [*]const u8) void {
    jsLog(ptr);
}
```
<p>Which gave me the familiar error about not being able to find <code>jsLog</code>.</p>
<p>comparing the linker sections gave some clues:</p>
```
❯ wasm-objdump --section=linking -x <path/to/libjs.o>

libjs.o:        file format wasm 0x1

Section Details:

Custom:
 - name: "linking"
  - symbol table [count=9]
   - 0: F <dummy> func=1 [ binding=global vis=hidden ]
   - 1: D <__em_js_ref_jsLog> segment=0 offset=0 size=4 [ binding=global vis=hidden ]
   - 2: F <jsLog> func=0 [ undefined explicit_name binding=global vis=default ]
   - 3: D <__em_js__jsLog> segment=1 offset=0 size=53 [ exported no_strip binding=global vis=hidden ]
   - 4: S <.debug_abbrev> section=7 [ binding=local vis=default ]
   - 5: G <env.__stack_pointer> global=0 [ undefined binding=global vis=default ]
   - 6: S <.debug_str> section=9 [ binding=local vis=default ]
   - 7: T <env.__indirect_function_table> table=0 [ undefined exported no_strip binding=global vis=default ]
   - 8: S <.debug_line> section=10 [ binding=local vis=default ]
  - segment info [count=2]
   - 0: .data.__em_js_ref_jsLog p2align=2 [ ]
   - 1: em_js p2align=0 [ RETAIN ]
```
<p>and the zig object:</p>
```
❯ wasm-objdump --section=linking -x js.o

js.o:   file format wasm 0x1

Section Details:

Custom:
 - name: "linking"
  - symbol table [count=6]
   - 0: F <dummy> func=1 [ binding=global vis=default ]
   - 1: D <__em_js_ref_jsLog> segment=0 offset=0 size=4 [ binding=global vis=default ]
   - 2: F <jsLog> func=0 [ undefined explicit_name binding=global vis=default ]
   - 3: D <__em_js__jsLog> segment=1 offset=0 size=4 [ binding=global vis=default ]
   - 4: D <__anon_946> segment=2 offset=0 size=54 [ binding=local vis=default ]
   - 5: T <env.__indirect_function_table> table=0 [ undefined exported no_strip binding=global vis=default ]
  - segment info [count=3]
   - 0: .rodata.__em_js_ref_jsLog p2align=2 [ ]
   - 1: em_js p2align=0 [ ]
   - 2: .rodata.__anon_946 p2align=0 [ ]`
```
<p>From what I could understand (which is little), it looks like <code>__em_js__jsLog</code>
in the zig obj is a pointer while from C, it&rsquo;s the full string.</p>
<p>hardcoding it as a static array helped:</p>
```zig
export const __em_js__jsLog align(1) linksection("em_js") = [_]u8{
    '(', 'c','o','n','s','t',' ','c','h','a','r','*',' ','s',')',
    '<',':',':','>','{',' ',
    'c','o','n','s','o','l','e','.','l','o','g','(',
    'U','T','F','8','T','o','S','t','r','i','n','g','(',
    's',')',')',';',' ','}','\x00',
};
```
<p>The output from this is a little more promising</p>
```
❯ wasm-objdump --section=linking -x js.o

js.o:   file format wasm 0x1

Section Details:

Custom:
 - name: "linking"
  - symbol table [count=5]
   - 0: F <dummy> func=1 [ binding=global vis=default ]
   - 1: D <__em_js_ref_jsLog> segment=0 offset=0 size=4 [ binding=global vis=default ]
   - 2: F <jsLog> func=0 [ undefined explicit_name binding=global vis=default ]
   - 3: D <__em_js__jsLog> segment=1 offset=0 size=53 [ binding=global vis=default ]
   - 4: T <env.__indirect_function_table> table=0 [ undefined exported no_strip binding=global vis=default ]
  - segment info [count=2]
   - 0: .rodata.__em_js_ref_jsLog p2align=2 [ ]
   - 1: em_js p2align=0 [ ]
```
<p>Let&rsquo;s look at the two side by side</p>
```
# From C
- 3: D <__em_js__jsLog> segment=1 offset=0 size=53 [ exported no_strip binding=global vis=hidden ]
# From zig
- 3: D <__em_js__jsLog> segment=1 offset=0 size=53 [ binding=global vis=default ]
```
<p>There are some clear differences in how the two are output and I am already
beyond my knowledge level here - so I&rsquo;ll leave it to someone who knows this
stuff better (or wait until I do)</p>
<p>You can
<a href="https://github.com/drone-ah/sokol-zig-imgui-sample/tree/zig_em_js">check out the code in the branch of my forked repo</a></p>
<h2 id="next-steps">Next steps</h2>
<p>My plan is to use <code>EM_JS</code> through <code>C</code> to implement glue JavaScript functions -
something like:</p>
```c
EM_JS(void, jsLog, (const char* s), {
	Module.jsLog(UTF8ToString(s));
});
```
<p>By doing this, I can have one-line js code in the <code>.c</code> file and all the
implementation can go into the web side (and can easily be TypeScript too).</p>
```javascript
window.Module = {
  jsLog: function (msg) {
    console.log("🟢 Zig says:", msg);
  },
};
```
]]></content:encoded></item><item><title>Auto reload WASM with zig+lume</title><link>https://icle.es/2025/09/16/auto-reload-wasm-with-zig-lume/</link><pubDate>Tue, 16 Sep 2025 15:56:42 +0100</pubDate><guid>https://icle.es/2025/09/16/auto-reload-wasm-with-zig-lume/</guid><description>&lt;p>I’ve been taking some time off to rest and recover from health issues that made
it hard to focus. To ease back in, I’ve started a small project:
&lt;a href="https://icle.es/excursions/shine.md">shine&lt;/a>&lt;/p>
&lt;p>The project would do well to be multiplatform - mobile and web. The obvious
choice was &lt;a href="https://icle.es/tags/flutter">flutter&lt;/a> and I have enjoyed working with it before.&lt;/p>
&lt;p>However, as I&amp;rsquo;m currently in love with &lt;a href="https://icle.es/tags/zig">zig&lt;/a>, I wanted to work with
that instead.&lt;/p>
&lt;h2 id="libraries">Libraries&lt;/h2>
&lt;h3 id="graphics">Graphics&lt;/h3>
&lt;p>I&amp;rsquo;ve been playing with &lt;a href="https://icle.es/tags/raylib">raylib&lt;/a> and that was my initial instinct.
However, raylib
&lt;a href="https://github.com/raysan5/raylib/discussions/2681">does not support iOs&lt;/a> and
&lt;a href="https://github.com/raysan5/raylib/discussions/3626">has issues with wasm&lt;/a>&lt;/p></description><content:encoded><![CDATA[<p>I’ve been taking some time off to rest and recover from health issues that made
it hard to focus. To ease back in, I’ve started a small project:
<a href="https://icle.es/excursions/shine.md">shine</a></p>
<p>The project would do well to be multiplatform - mobile and web. The obvious
choice was <a href="https://icle.es/tags/flutter">flutter</a> and I have enjoyed working with it before.</p>
<p>However, as I&rsquo;m currently in love with <a href="https://icle.es/tags/zig">zig</a>, I wanted to work with
that instead.</p>
<h2 id="libraries">Libraries</h2>
<h3 id="graphics">Graphics</h3>
<p>I&rsquo;ve been playing with <a href="https://icle.es/tags/raylib">raylib</a> and that was my initial instinct.
However, raylib
<a href="https://github.com/raysan5/raylib/discussions/2681">does not support iOs</a> and
<a href="https://github.com/raysan5/raylib/discussions/3626">has issues with wasm</a></p>
<p>I considered a few options, including</p>
<ul>
<li><a href="https://www.libsdl.org/">sdl</a>, which looked great but was perhaps a little
too low level for me.</li>
<li><a href="https://github.com/Jack-Ji/jok">jok</a> - does not support mobile and possibly
has a little more than I needed.</li>
</ul>
<p>In the end, I decided to go with <a href="https://github.com/floooh/sokol">sokol</a> and
<a href="https://github.com/floooh/sokol-zig">sokol-zig</a>.</p>
<p>While a little more lower level than raylib, it has:</p>
<ul>
<li>a modern clean api</li>
<li>first class mobile support</li>
<li>first class wasm support</li>
</ul>
<h3 id="ui">UI</h3>
<p>I&rsquo;ve been working with <a href="https://icle.es/tags/dvui">dvui</a> a lot recently. Unfortunately, it
doesn&rsquo;t support sokol. <a href="https://github.com/SpexGuy/Zig-ImGui">imgui</a> is a better
option.</p>
<p>There is even a
<a href="https://github.com/floooh/sokol-zig-imgui-sample">template project that I could start from</a>.</p>
<h2 id="wasm-first">WASM first</h2>
<p>To keep things straightforward, I decided to start with wasm. If I make the site
mobile friendly, I could see how it goes and see if it needs a mobile version.</p>
<p>I will need some shared data storage and have been considering
<a href="https://supabase.com/">supabase</a>, which has <a href="https://icle.es/tags/javascript">javascript</a>
libs. By using <a href="https://icle.es/tags/wasm">wasm</a>, I can effectively shim in js functions to
handle that instead of having to write bare rest calls from zig.</p>
<h3 id="structuring-the-project">Structuring the project</h3>
<p>Is this a zig project with a web component, vice versa or indeed two independent
parts that work together.</p>
<p>I did a fair amount of web searching to see if there was some guidance I could I
find for a good way to structure a relatively straightforward zig+js project.</p>
<p>I could not find one. In the end, I decided to keep it fairly straightforward.</p>
```
- shine/
  - src/ # zig code
  - web/ # all the web stuff
```
<h3 id="frontend">Frontend</h3>
<p>After a bit of research, and realising that I will probably need a little bit of
supporting content around <a href="https://icle.es/excursions/shine.md">shine</a>, I decided to go
with <a href="https://lume.land/">lume</a></p>
<p>I used the <a href="https://github.com/lumeland/theme-simple-blog">simple-blog theme</a> as
a template to start from. I could have just pulled the template in but I wanted
a custom homepage.</p>
<p>When I tried to add an <code>index.md</code>, it complained about two files wanting to
write <code>index.html</code>. From what I could find, the easiest way to override the
homepage was to just pick up the theme and edit it - which was easy enough.</p>
<h3 id="wasm--frontend">WASM =&gt; frontend</h3>
<p>I didn&rsquo;t want to copy over the wasm and the js file every time, so I added a
couple of steps to <code>build.zig</code> right after the <code>link_step</code> (also included below)</p>
```zig
// build.zig
// create a build step which invokes the Emscripten linker
const link_step = try sokol.emLinkStep(b, .{
    .lib_main = shine,
    .target = opts.mod_main.resolved_target.?,
    .optimize = opts.mod_main.optimize.?,
    .emsdk = dep_emsdk,
    .use_webgl2 = true,
    .use_emmalloc = true,
    .use_filesystem = false,
    .shell_file_path = opts.dep_sokol.path("src/sokol/web/shell.html"),
});
// attach to default target
b.getInstallStep().dependOn(&link_step.step);

// Copy shine.js from default emscripten output
const js_install = b.addInstallFileWithDir(
    b.path("zig-out/web/shine.js"),
    .{ .custom = "../web/src/static/shine" },
    "shine.js",
);
js_install.step.dependOn(&link_step.step);
b.getInstallStep().dependOn(&js_install.step);

// Copy shine.wasm from default emscripten output
const wasm_install = b.addInstallFileWithDir(
    b.path("zig-out/web/shine.wasm"),
    .{ .custom = "../web/src/static/shine" },
    "shine.wasm",
);
wasm_install.step.dependOn(&link_step.step);
```
<p>These steps will copy across the wasm and the js file across to <code>static/shine</code>.
I wanted to put the js in <code>src/js</code> and the wasm in the static dir. However, the
js file expects the wasm in the same dir. <del>I tried overriding <code>locateFile</code> but
it didn&rsquo;t
work.</del>(<a href="https://icle.es/lume/wasm.md">you can use a different location by overriding <code>locateFile</code></a>)</p>
```html
<!-- index.vto -->
<script>
  window.Module = {
    locateFile: (path, prefix) => {
      if (path.endsWith(".wasm")) {
        return "/static/shine/shine.wasm";
      }
      return prefix + path;
    },
  };
</script>
<script src="/js/shine.js"></script>
```
<p>I was able to get lume to process the javascript file by <code>add</code>ing it.</p>
```javascript
// _config.ts
site.add("static/shine/shine.js");
```
<h2 id="conclusion">Conclusion</h2>
<p>With all of these set up, I was able to run:</p>
```bash
zig build -Dtarget=wasm32-emscripten --watch
```
```

```
<p>in one window. This command will rebuild wasm and provide it to lume whenever
the zig code changes.</p>
```bash
deno task serve
```
<p>Running this in another window will mean that lume will rebuild on any changes,
including a new wasm file and redeploy. The redeploy will trigger an auto-reload
of the page as well if I have it in a browser.</p>
<p>I now effectively have automated reload with changes if I make changes in either
zig or the frontend.</p>
<p>I don&rsquo;t have <em>hot</em> reload - but this is pretty good for now.</p>
]]></content:encoded></item></channel></rss>