Skip to content

Commit c9e5ff8

Browse files
committed
wasm: Add support for extra JS functions
This allows to extend the capabilities of capy.js with access to other DOM APIs which can be used by external libraries
1 parent 5f12ecb commit c9e5ff8

File tree

3 files changed

+53
-9
lines changed

3 files changed

+53
-9
lines changed

build_capy.zig

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub const CapyBuildOptions = struct {
88
// TODO: disable android build if password is not set
99
// TODO: use optional
1010
android: AndroidOptions = .{ .password = "foo", .package_name = "org.capyui.example" },
11+
wasm: WasmOptions = .{},
1112
args: ?[]const []const u8 = &.{},
1213

1314
pub const AndroidOptions = struct {
@@ -20,15 +21,21 @@ pub const CapyBuildOptions = struct {
2021
password: []const u8,
2122
};
2223

24+
pub const WasmOptions = struct {
25+
extras_js_file: ?[]const u8 = null,
26+
debug_requests: bool = true,
27+
};
28+
2329
pub const LinuxOptions = struct {};
2430
};
2531

2632
/// Step used to run a web server for WebAssembly apps
2733
const WebServerStep = struct {
2834
step: std.build.Step,
2935
exe: *std.build.CompileStep,
36+
options: CapyBuildOptions.WasmOptions,
3037

31-
pub fn create(owner: *std.build.Builder, exe: *std.build.LibExeObjStep) *WebServerStep {
38+
pub fn create(owner: *std.build.Builder, exe: *std.build.LibExeObjStep, options: CapyBuildOptions.WasmOptions) *WebServerStep {
3239
const self = owner.allocator.create(WebServerStep) catch unreachable;
3340
self.* = .{
3441
.step = std.build.Step.init(.{
@@ -38,6 +45,7 @@ const WebServerStep = struct {
3845
.makeFn = WebServerStep.make,
3946
}),
4047
.exe = exe,
48+
.options = options,
4149
};
4250
return self;
4351
}
@@ -69,7 +77,8 @@ const WebServerStep = struct {
6977

7078
fn handler(self: *WebServerStep, build: *std.Build, res: *Server.Response) !void {
7179
const allocator = build.allocator;
72-
const build_root = build.build_root.path orelse unreachable;
80+
const prefix = comptime std.fs.path.dirname(@src().file).? ++ std.fs.path.sep_str;
81+
7382
while (true) {
7483
defer _ = res.reset();
7584
try res.wait();
@@ -82,20 +91,27 @@ const WebServerStep = struct {
8291
var file_path: []const u8 = "";
8392
var content_type: []const u8 = "text/html";
8493
if (std.mem.eql(u8, path, "/")) {
85-
file_path = try std.fs.path.join(req_allocator, &.{ build_root, "src/backends/wasm/index.html" });
94+
file_path = try std.fs.path.join(req_allocator, &.{ prefix, "src/backends/wasm/index.html" });
8695
content_type = "text/html";
8796
} else if (std.mem.eql(u8, path, "/capy.js")) {
88-
file_path = try std.fs.path.join(req_allocator, &.{ build_root, "src/backends/wasm/capy.js" });
97+
file_path = try std.fs.path.join(req_allocator, &.{ prefix, "src/backends/wasm/capy.js" });
8998
content_type = "application/javascript";
9099
} else if (std.mem.eql(u8, path, "/capy-worker.js")) {
91-
file_path = try std.fs.path.join(req_allocator, &.{ build_root, "src/backends/wasm/capy-worker.js" });
100+
file_path = try std.fs.path.join(req_allocator, &.{ prefix, "src/backends/wasm/capy-worker.js" });
92101
content_type = "application/javascript";
93102
} else if (std.mem.eql(u8, path, "/zig-app.wasm")) {
94103
file_path = self.exe.getOutputSource().getPath2(build, &self.step);
95104
content_type = "application/wasm";
105+
} else if (std.mem.eql(u8, path, "/extras.js")) {
106+
if (self.options.extras_js_file) |extras_path| {
107+
file_path = extras_path;
108+
content_type = "application/javascript";
109+
}
96110
}
97111

98-
std.log.info("{s}", .{path});
112+
if (self.options.debug_requests) {
113+
std.log.debug("{s} -> {s}", .{ path, file_path });
114+
}
99115
const file: ?std.fs.File = std.fs.cwd().openFile(file_path, .{ .mode = .read_only }) catch |err| blk: {
100116
switch (err) {
101117
error.FileNotFound => break :blk null,
@@ -107,6 +123,7 @@ const WebServerStep = struct {
107123
defer f.close();
108124
break :blk try f.readToEndAlloc(req_allocator, std.math.maxInt(usize));
109125
} else {
126+
res.status = .not_found;
110127
break :blk "404 Not Found";
111128
}
112129
};
@@ -301,7 +318,7 @@ pub fn install(step: *std.Build.CompileStep, options: CapyBuildOptions) !*std.Bu
301318
step.export_symbol_names = &.{"_start"};
302319
step.import_memory = true;
303320

304-
const serve = WebServerStep.create(b, step);
321+
const serve = WebServerStep.create(b, step, options.wasm);
305322
const install_step = b.addInstallArtifact(step, .{});
306323
serve.step.dependOn(&install_step.step);
307324
return &serve.step;

src/backends/wasm/capy-worker.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,20 @@ const env = {
226226
},
227227
};
228228

229+
async function loadExtras() {
230+
const obj = await import("./extras.js");
231+
for (const key in obj.envWorker) {
232+
env[key] = obj.envWorker[key];
233+
}
234+
}
235+
229236
(async function() {
237+
try {
238+
await loadExtras();
239+
} catch (e) {
240+
console.debug("No extras.js (worker)");
241+
}
242+
230243
const importObject = {
231244
env: env,
232245
};

src/backends/wasm/capy.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ function readString(addr, len) {
7272

7373
return utf8Decoder.decode(view.slice(addr, addr + len));
7474
}
75-
const env = {
75+
76+
let env = {
7677
jsPrint: function(arg, len) {
7778
console.log(readString(arg, len));
7879
},
@@ -171,6 +172,7 @@ const env = {
171172
domObjects[root].style.width = "100%";
172173
domObjects[root].style.height = "100%";
173174
rootElementId = root;
175+
window.onresize(); // call resize handler atleast once, to setup layout
174176
},
175177
setText: function(element, text) {
176178
const elem = domObjects[element];
@@ -370,11 +372,24 @@ const env = {
370372
},
371373
};
372374

375+
async function loadExtras() {
376+
const obj = await import("./extras.js");
377+
for (const key in obj.env) {
378+
env[key] = obj.env[key];
379+
}
380+
}
373381

374382
(async function() {
375383
if (!window.Worker) {
376384
alert("Capy requires Web Workers until Zig supports async");
377385
}
386+
387+
try {
388+
await loadExtras();
389+
} catch (e) {
390+
console.debug("No extras.js");
391+
}
392+
378393
const wasmWorker = new Worker("capy-worker.js");
379394
wasmWorker.postMessage("test");
380395
wasmWorker.onmessage = (e) => {
@@ -440,5 +455,4 @@ const env = {
440455
window.onresize = function() {
441456
pushEvent({ type: 0, target: rootElementId });
442457
};
443-
window.onresize(); // call resize handler atleast once, to setup layout
444458
})();

0 commit comments

Comments
 (0)