@thi.ng/wasm-api 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2022-11-28T13:36:49Z
3
+ - **Last updated**: 2022-12-01T18:02:30Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -9,6 +9,12 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ ## [1.2.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@1.2.0) (2022-12-01)
13
+
14
+ #### 🚀 Features
15
+
16
+ - add build script for user projects ([7164f5e](https://github.com/thi-ng/umbrella/commit/7164f5e))
17
+
12
18
  ## [1.1.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@1.1.0) (2022-11-28)
13
19
 
14
20
  #### 🚀 Features
package/README.md CHANGED
@@ -11,11 +11,12 @@ This project is part of the
11
11
 
12
12
  - [About](#about)
13
13
  - [Custom API modules](#custom-api-modules)
14
- - [Building Zig projects with these hybrid API modules](#building-zig-projects-with-these-hybrid-api-modules)
15
14
  - [String handling](#string-handling)
16
15
  - [Memory allocations](#memory-allocations)
17
16
  - [API module auto-initialization](#api-module-auto-initialization)
18
17
  - [Object indices & handles](#object-indices--handles)
18
+ - [Using the Zig build system](#using-the-zig-build-system)
19
+ - [Naming & structural conventions](#naming--structural-conventions)
19
20
  - [Status](#status)
20
21
  - [Support packages](#support-packages)
21
22
  - [Installation](#installation)
@@ -55,13 +56,15 @@ WebGL, WebGPU, WebAudio etc. is being actively worked on.
55
56
  defining glue code for the TypeScript [core
56
57
  API](https://docs.thi.ng/umbrella/wasm-api/interfaces/CoreAPI.html) defined
57
58
  by this package
58
- 7. Extensible shared [datatype code generator
59
+ 7. [Zig build files]() to simplify using hybrid TS/Zig packages with the
60
+ built-in build system
61
+ 8. Extensible shared [datatype code generator
59
62
  infrastructure](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api-bindgen/)
60
63
  for (currently) Zig & TypeScript and C11. For TS fully type checked and
61
64
  memory-mapped (zero-copy) accessors of WASM-side data are generated. In
62
65
  principle, all languages with a WASM target are supported, however currently
63
66
  only bindings for these mentioned langs are included.
64
- 8. [CLI
67
+ 9. [CLI
65
68
  frontend/utility](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api-bindgen/README.md#cli-generator)
66
69
  for the code generator(s)
67
70
 
@@ -148,7 +151,7 @@ Main Zig file:
148
151
 
149
152
  ```zig
150
153
  // Import JS core API
151
- const js = @import("wasmapi");
154
+ const js = @import("wasm-api");
152
155
  const custom = @import("custom.zig");
153
156
 
154
157
  export fn test_randomVec4() void {
@@ -165,19 +168,6 @@ export fn test_randomVec4() void {
165
168
  }
166
169
  ```
167
170
 
168
- ### Building Zig projects with these hybrid API modules
169
-
170
- Some example projects (see [list below](#usage-examples)) provide custom
171
- [`build.zig`](https://github.com/thi-ng/umbrella/blob/develop/examples/zig-canvas/build.zig)
172
- &
173
- [`npm.zig`](https://github.com/thi-ng/umbrella/blob/develop/examples/zig-canvas/npm.zig)
174
- build scripts to easily integrate these hybrid TS/Zig packages into users'
175
- development processes.
176
-
177
- To avoid guesswork about the internals of these API modules, all of them are
178
- using an overall uniform structure, with the main Zig entry point in
179
- `/zig/lib.zig`...
180
-
181
171
  ## String handling
182
172
 
183
173
  Most low-level languages deal with strings very differently and alas there's no
@@ -313,6 +303,38 @@ in the
313
303
  [@thi.ng/wasm-api-schedule](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api-schedule/)
314
304
  packages this is used to manage Zig-side event listeners.
315
305
 
306
+ ## Using the Zig build system
307
+
308
+ This package provides utilities to simplify using hybrid TS/Zig WASM API modules which are distributed as NPM packages. Using these utils, a build file for Zig's built-in build system is as simple as:
309
+
310
+ ```zig
311
+ const std = @import("std");
312
+
313
+ pub fn build(b: *std.build.Builder) void {
314
+ @import("node_modules/@thi.ng/wasm-api/zig/build.zig").wasmLib(b, .{
315
+ // Declare extra WASM API packages to use
316
+ // Each package can also declare its dependencies
317
+ .packages = &.{
318
+ .{ .id = "wasm-api-dom", .path = "@thi.ng/wasm-api-dom/zig/lib.zig" },
319
+ .{ .id = "wasm-api-schedule", .path = "@thi.ng/wasm-api-schedule/zig/lib.zig" },
320
+ },
321
+ // (optional) build mode override
322
+ .mode = .ReleaseSmall,
323
+ }).install();
324
+ }
325
+ ```
326
+
327
+ All bundled example projects (see [list below](#usage-examples)) are being built
328
+ via this script. **Please find more details/options in the commented source
329
+ code:**
330
+ [`/zig/build.zig`](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api/zig/build.zig)
331
+
332
+ ## Naming & structural conventions
333
+
334
+ To avoid guesswork about the internals of any of the supplied WASM API modules,
335
+ please also consult the information in
336
+ [#368](https://github.com/thi-ng/umbrella/issues/368).
337
+
316
338
  ## Status
317
339
 
318
340
  **ALPHA** - bleeding edge / work-in-progress
@@ -348,7 +370,7 @@ node --experimental-repl-await
348
370
  > const wasmApi = await import("@thi.ng/wasm-api");
349
371
  ```
350
372
 
351
- Package sizes (gzipped, pre-treeshake): ESM: 2.73 KB
373
+ Package sizes (brotli'd, pre-treeshake): ESM: 2.47 KB
352
374
 
353
375
  ## Dependencies
354
376
 
@@ -371,6 +393,7 @@ A selection:
371
393
  | Screenshot | Description | Live demo | Source |
372
394
  |:---------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------|:----------------------------------------------------|:---------------------------------------------------------------------------------|
373
395
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/zig-canvas.png" width="240"/> | Zig-based DOM creation & canvas drawing app | [Demo](https://demo.thi.ng/umbrella/zig-canvas/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/zig-canvas) |
396
+ | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/zig-cellular.jpg" width="240"/> | Zig-based 2D multi-behavior cellular automata | [Demo](https://demo.thi.ng/umbrella/zig-cellular/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/zig-cellular) |
374
397
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/zig-counter.png" width="240"/> | Simple Zig/WASM click counter DOM component | [Demo](https://demo.thi.ng/umbrella/zig-counter/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/zig-counter) |
375
398
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/zig-todo-list.png" width="240"/> | Zig-based To-Do list, DOM creation, local storage task persistence | [Demo](https://demo.thi.ng/umbrella/zig-todo-list/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/zig-todo-list) |
376
399
 
@@ -413,7 +436,7 @@ Requires [Zig](https://ziglang.org) to be installed:
413
436
 
414
437
  /// import externals
415
438
  /// see build command for configuration
416
- const js = @import("wasmapi");
439
+ const js = @import("wasm-api");
417
440
 
418
441
  export fn start() void {
419
442
  js.printStr("hello world!");
@@ -427,7 +450,7 @@ folder):
427
450
  ```bash
428
451
  # compile WASM binary
429
452
  zig build-lib \
430
- --pkg-begin wasmapi node_modules/@thi.ng/wasm-api/zig/lib.zig --pkg-end \
453
+ --pkg-begin wasm-api node_modules/@thi.ng/wasm-api/zig/lib.zig --pkg-end \
431
454
  -target wasm32-freestanding \
432
455
  -O ReleaseSmall -dynamic \
433
456
  hello.zig
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/wasm-api",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Generic, modular, extensible API bridge and infrastructure for hybrid JS & WebAssembly projects",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -35,17 +35,17 @@
35
35
  "test:build-zig": "zig build-lib -O ReleaseSmall -target wasm32-freestanding -dynamic --strip --pkg-begin wasmapi zig/lib.zig --pkg-end test/custom.zig && wasm-dis -o custom.wast custom.wasm && cp custom.wasm test"
36
36
  },
37
37
  "dependencies": {
38
- "@thi.ng/api": "^8.5.0",
39
- "@thi.ng/arrays": "^2.4.3",
40
- "@thi.ng/checks": "^3.3.3",
41
- "@thi.ng/errors": "^2.2.4",
42
- "@thi.ng/hex": "^2.3.0",
43
- "@thi.ng/idgen": "^2.1.19",
44
- "@thi.ng/logger": "^1.4.3"
38
+ "@thi.ng/api": "^8.5.1",
39
+ "@thi.ng/arrays": "^2.4.4",
40
+ "@thi.ng/checks": "^3.3.4",
41
+ "@thi.ng/errors": "^2.2.5",
42
+ "@thi.ng/hex": "^2.3.1",
43
+ "@thi.ng/idgen": "^2.1.20",
44
+ "@thi.ng/logger": "^1.4.4"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@microsoft/api-extractor": "^7.33.5",
48
- "@thi.ng/testament": "^0.3.5",
48
+ "@thi.ng/testament": "^0.3.6",
49
49
  "rimraf": "^3.0.2",
50
50
  "tools": "^0.0.1",
51
51
  "typedoc": "^0.23.20",
@@ -110,5 +110,5 @@
110
110
  "status": "alpha",
111
111
  "year": 2022
112
112
  },
113
- "gitHead": "75ec32ff7f1b7b5e72e7a04ace24732cd5d6c774\n"
113
+ "gitHead": "199dcde33bf3d0b0bbd205d3b870dff43b735b22\n"
114
114
  }
package/zig/build.zig ADDED
@@ -0,0 +1,135 @@
1
+ const std = @import("std");
2
+
3
+ /// Definition for a (usually hybrid) Zig package which will be distributed via NPM
4
+ pub const Pkg = struct {
5
+ /// Package ID used for @import
6
+ id: []const u8,
7
+ /// Package sub path (appended to base path)
8
+ path: []const u8,
9
+ /// Package dependencies aka other package IDs.
10
+ /// All of them must already have been registered
11
+ deps: ?[]const []const u8 = null,
12
+ };
13
+
14
+ pub const PkgOpts = struct {
15
+ /// Base path to common node_modules directory under which
16
+ /// all to be imported packages are located
17
+ base: []const u8 = "node_modules",
18
+ /// Additional WASM API support packages.
19
+ /// We don't need to specify core wasmapi, only custom/extra ones
20
+ /// `wasm-api` and `wasm-api-bindgen` are also auto-added
21
+ /// as dependency for each of these...
22
+ packages: ?[]const Pkg = null,
23
+ };
24
+
25
+ /// Dependency graph for WASM API packages
26
+ /// Expands & resolves the more compact/convenient/human friendly format of PkgOpts
27
+ /// into the data structures used by Zig's build system
28
+ /// Provides a `addAllTo()` function to add all declared packages to a build step
29
+ pub const PkgGraph = struct {
30
+ arena: std.heap.ArenaAllocator,
31
+ basePath: []const u8,
32
+ packages: std.StringArrayHashMap(std.build.Pkg),
33
+
34
+ const Self = @This();
35
+
36
+ pub fn init(opts: PkgOpts) Self {
37
+ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
38
+ var self = Self{
39
+ .arena = arena,
40
+ .basePath = opts.base,
41
+ .packages = std.StringArrayHashMap(std.build.Pkg).init(arena.allocator()),
42
+ };
43
+ const api = "wasm-api";
44
+ self.packages.put(api, .{
45
+ .name = api,
46
+ .source = .{ .path = self.modulePath("@thi.ng/wasm-api/zig/lib.zig") },
47
+ }) catch unreachable;
48
+ const apiTypes = "wasm-api-bindgen";
49
+ self.packages.put(apiTypes, .{
50
+ .name = apiTypes,
51
+ .source = .{ .path = self.modulePath("@thi.ng/wasm-api-bindgen/zig/lib.zig") },
52
+ }) catch unreachable;
53
+ if (opts.packages) |pkgs| {
54
+ for (pkgs) |pkg| {
55
+ self.register(pkg.id, pkg.path, pkg.deps);
56
+ }
57
+ }
58
+ return self;
59
+ }
60
+
61
+ pub fn deinit(self: *const Self) void {
62
+ self.arena.deinit();
63
+ }
64
+
65
+ /// Registers a single package and its deps (also injects core wasm-api deps)
66
+ pub fn register(
67
+ self: *Self,
68
+ name: []const u8,
69
+ path: []const u8,
70
+ dependencies: ?[]const []const u8,
71
+ ) void {
72
+ var pkg = std.build.Pkg{
73
+ .name = name,
74
+ .source = .{ .path = self.modulePath(path) },
75
+ };
76
+ const num = if (dependencies) |deps| deps.len else 0;
77
+ var dpkgs = self.arena.allocator().alloc(std.build.Pkg, num + 2) catch unreachable;
78
+ dpkgs[0] = if (self.packages.get("wasm-api")) |p| p else unreachable;
79
+ dpkgs[1] = if (self.packages.get("wasm-api-bindgen")) |p| p else unreachable;
80
+ if (dependencies) |deps| {
81
+ var i: usize = 0;
82
+ while (i < deps.len) : (i += 1) {
83
+ if (self.packages.get(deps[i])) |p| {
84
+ dpkgs[i + 1] = p;
85
+ } else @panic("unknown dependency");
86
+ }
87
+ }
88
+ pkg.dependencies = dpkgs;
89
+ self.packages.put(name, pkg) catch unreachable;
90
+ }
91
+
92
+ /// Adds all registered packages to the given build step
93
+ pub fn addAllTo(self: *const Self, step: *std.build.LibExeObjStep) void {
94
+ for (self.packages.values()) |pkg| step.addPackage(pkg);
95
+ }
96
+
97
+ fn modulePath(self: *Self, path: []const u8) []const u8 {
98
+ return std.fs.path.join(self.arena.allocator(), &.{ self.basePath, path }) catch unreachable;
99
+ }
100
+ };
101
+
102
+ /// Config options
103
+ pub const WasmLibOpts = struct {
104
+ /// Relative path to base directory for WASM API packages
105
+ base: []const u8 = "node_modules",
106
+ /// Relative path to root source file
107
+ root: []const u8 = "zig/main.zig",
108
+ /// Relative path to output directory
109
+ out: []const u8 = "src",
110
+ /// Package definitions for additional WASM API modules
111
+ packages: ?[]const Pkg = null,
112
+ /// Build mode override (else allows config via CLI args)
113
+ mode: ?std.builtin.Mode = null,
114
+ /// Additional WASM target features, e.g. `.simd128` to enable SIMD
115
+ features: ?[]const std.Target.wasm.Feature = null,
116
+ };
117
+
118
+ /// Creates and returns a build step to build a dynamic WASM library, configured
119
+ /// with given options and package declarations. The given package specs will be inserted
120
+ pub fn wasmLib(b: *std.build.Builder, opts: WasmLibOpts) *std.build.LibExeObjStep {
121
+ const lib = b.addSharedLibrary("main", opts.root, .unversioned);
122
+ lib.setTarget(.{
123
+ .cpu_arch = .wasm32,
124
+ .os_tag = .freestanding,
125
+ .cpu_features_add = if (opts.features) |features| std.Target.wasm.featureSet(features) else std.Target.Cpu.Feature.Set.empty,
126
+ });
127
+ const mode = if (opts.mode) |m| m else b.standardReleaseOptions();
128
+ lib.setBuildMode(mode);
129
+ if (mode == .ReleaseSmall or mode == .ReleaseFast) lib.strip = true;
130
+ const pkgs = PkgGraph.init(.{ .base = opts.base, .packages = opts.packages });
131
+ defer pkgs.deinit();
132
+ pkgs.addAllTo(lib);
133
+ lib.setOutputDir(opts.out);
134
+ return lib;
135
+ }