Add 'serve' command for WASM

closes #1
This commit is contained in:
zenith391 committed 2022-08-27 13:24:22 +02:00
1 parent aed8c11ec6
commit b19cd14c6d
4 files changed
+97 -5

No files matched your search

+3
View File
@@ -12,3 +12,6 @@ And you're ready to go!
Then if you wish to run the app simply execute
`zig build run` (`zigmod fetch` is no longer required)
In the same way, to build and run the app for WebAssembly, execute
`zig build serve`
+90 -3
View File
@@ -1,6 +1,8 @@
const std = @import("std");
const deps = @import("deps.zig");
const PATH_TO_CAPY = ".zigmod/deps/git/github.com/zenith391/capy/";
pub fn build(b: *std.build.Builder) !void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
@@ -12,11 +14,10 @@ pub fn build(b: *std.build.Builder) !void {
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("zgt-template", "src/main.zig");
const pathToCapy = ".zigmod/deps/git/github.com/zenith391/capy/";
const exe = b.addExecutable("capy-template", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
try deps.imports.capy.install(exe, pathToCapy);
try deps.imports.capy.install(exe, PATH_TO_CAPY);
exe.install();
const run_cmd = exe.run();
@@ -28,6 +29,28 @@ pub fn build(b: *std.build.Builder) !void {
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
// Building for WebAssembly
// WebAssembly doesn't have a concept of executables, so the way it works is that we make a shared library and capy exports a '_start' function automatically
const wasm = b.addSharedLibrary("capy-template", "src/main.zig", .unversioned);
@setEvalBranchQuota(5000);
// Set the target to WebAssembly
wasm.setTarget(comptime std.zig.CrossTarget.parse(.{ .arch_os_abi = "wasm32-freestanding" }) catch unreachable);
wasm.setBuildMode(mode);
wasm.install();
try deps.imports.capy.install(wasm, PATH_TO_CAPY);
if (@import("builtin").zig_backend != .stage2_llvm) {
const serve = WebServerStep.create(b, wasm);
serve.step.dependOn(&wasm.install_step.?.step);
const serve_step = b.step("serve", "Start a web server to run this example");
serve_step.dependOn(&serve.step);
} else {
var step = b.addLog("Please use 'zig build serve -fstage1'", .{});
const serve_step = b.step("serve", "Start a web server to run this example");
serve_step.dependOn(&step.step);
}
const exe_tests = b.addTest("src/main.zig");
exe_tests.setTarget(target);
exe_tests.setBuildMode(mode);
@@ -35,3 +58,67 @@ pub fn build(b: *std.build.Builder) !void {
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&exe_tests.step);
}
const http = deps.imports.apple_pie;
/// Step used for running a web server that can be run with 'zig build serve'
const WebServerStep = struct {
step: std.build.Step,
exe: *std.build.LibExeObjStep,
builder: *std.build.Builder,
pub fn create(builder: *std.build.Builder, exe: *std.build.LibExeObjStep) *WebServerStep {
const self = builder.allocator.create(WebServerStep) catch unreachable;
self.* = .{
.step = std.build.Step.init(.custom, "webserver", builder.allocator, WebServerStep.make),
.exe = exe,
.builder = builder,
};
return self;
}
const Context = struct {
exe: *std.build.LibExeObjStep,
builder: *std.build.Builder,
};
pub fn make(step: *std.build.Step) !void {
const self = @fieldParentPtr(WebServerStep, "step", step);
const allocator = self.builder.allocator;
var context = Context{ .builder = self.builder, .exe = self.exe };
const builder = http.router.Builder(*Context);
std.debug.print("Web server opened at http://localhost:8080/\n", .{});
try http.listenAndServe(
allocator,
try std.net.Address.parseIp("127.0.0.1", 8080),
&context,
comptime http.router.Router(*Context, &.{
builder.get("/", index),
builder.get("/zig-app.wasm", wasmFile),
}),
);
}
fn index(context: *Context, response: *http.Response, request: http.Request) !void {
const allocator = request.arena;
const buildRoot = context.builder.build_root;
const file = try std.fs.cwd().openFile(try std.fs.path.join(allocator, &.{ buildRoot, PATH_TO_CAPY ++ "src/backends/wasm/page.html" }), .{});
defer file.close();
const text = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
try response.headers.put("Content-Type", "text/html");
try response.writer().writeAll(text);
}
fn wasmFile(context: *Context, response: *http.Response, request: http.Request) !void {
const allocator = request.arena;
const path = context.exe.getOutputSource().getPath(context.builder);
const file = try std.fs.cwd().openFile(path, .{});
defer file.close();
const text = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
try response.headers.put("Content-Type", "application/wasm");
try response.writer().writeAll(text);
}
};
+2 -1
View File
@@ -1,2 +1,3 @@
2
git https://github.com/zenith391/zgt commit-80238123d9cab0ec83680a4958b8ed7ae1fcf1fd
git https://github.com/zenith391/capy commit-2e31fde7e328599352eb01f8894acd53389d0ec0
git https://github.com/Luukdegram/apple_pie commit-54444805f41cc958d55940bc8931cd3cf1979d8c
+2 -1
View File
@@ -1,7 +1,8 @@
id: eje8wf3r4lz8em2jnign4ocxywosgkrk1dr6lgcbb0y1ne6y
name: zgt-template
name: capy-template
license: Unlicense
description: Simple template for Capy apps
build_dependencies:
- src: git https://github.com/zenith391/capy
- src: git https://github.com/Luukdegram/apple_pie # this is only necessary if you want 'zig build serve'
root_depedencies: