Skip to content

Commit 5ffc016

Browse files
committed
feat: Refactor and update WASM module and build scripts
- Removed .yarnrc.yml and yarn.lock files, transitioning to npm for package management. - Enhanced build.sh and docker-build.sh scripts for improved error handling and clarity. - Updated package.json to reflect new project name and version, and added necessary fields for npm publishing. - Expanded API in index.d.ts to include InitOptions and updated function signatures for compress and decompress. - Revised README for clarity on usage with Vite and updated examples. - Reworked test suite to utilize modern JavaScript features and ensure compatibility with the new API structure. This commit prepares the project for npm trusted publishing and improves overall usability and documentation.
1 parent 13b78c2 commit 5ffc016

12 files changed

Lines changed: 371 additions & 2150 deletions

File tree

.github/workflows/ci.yml

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,21 @@ name: CI
33
on:
44
push:
55
branches: [main]
6-
tags: ["v*"]
76
pull_request:
8-
branches: ["*"]
7+
branches: [main]
98

109
jobs:
11-
wasm-zstd:
10+
build-test:
1211
runs-on: ubuntu-latest
13-
14-
permissions:
15-
contents: read
16-
# https://docs.npmjs.com/generating-provenance-statements#publishing-packages-with-provenance-via-github-actions
17-
id-token: write
18-
19-
strategy:
20-
fail-fast: false
21-
matrix:
22-
node-version: [18.x, 20.x, 22.x]
23-
2412
steps:
25-
- uses: actions/checkout@v6
26-
- run: corepack enable
27-
- uses: actions/setup-node@v6
28-
with:
29-
node-version: ${{ matrix.node-version }}
30-
registry-url: https://registry.npmjs.org
31-
cache: yarn
13+
- uses: actions/checkout@v4
3214

33-
- run: yarn install --immutable
34-
- run: yarn build
35-
- run: yarn test
15+
- uses: actions/setup-node@v4
16+
with:
17+
node-version: '24'
18+
cache: 'npm'
3619

37-
- name: Publish to NPM
38-
if: ${{ startsWith(github.ref, 'refs/tags/v') && matrix.node-version == '18.x' }}
39-
run: yarn npm publish --provenance --access public
20+
- run: npm ci
21+
- run: npm run build
22+
- run: npm test
23+
- run: npm run pack:check

.github/workflows/release.yml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
jobs:
9+
validate:
10+
name: Validate
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- uses: actions/setup-node@v4
16+
with:
17+
node-version: '24'
18+
cache: 'npm'
19+
20+
- run: npm ci
21+
- run: npm run build
22+
- run: npm test
23+
- run: npm run pack:check
24+
25+
- name: Upload package artifact
26+
uses: actions/upload-artifact@v4
27+
with:
28+
name: dist
29+
path: dist/
30+
retention-days: 1
31+
32+
publish-npm:
33+
name: Publish to npm
34+
needs: validate
35+
runs-on: ubuntu-latest
36+
permissions:
37+
id-token: write
38+
steps:
39+
- uses: actions/checkout@v4
40+
41+
- uses: actions/setup-node@v4
42+
with:
43+
node-version: '24'
44+
registry-url: 'https://registry.npmjs.org'
45+
cache: 'npm'
46+
47+
- run: npm ci
48+
49+
- name: Download package artifact
50+
uses: actions/download-artifact@v4
51+
with:
52+
name: dist
53+
path: dist/
54+
55+
- name: Publish
56+
run: npm publish --access public
57+
env:
58+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
59+
60+
github-release:
61+
name: Create GitHub Release
62+
needs: publish-npm
63+
runs-on: ubuntu-latest
64+
permissions:
65+
contents: write
66+
steps:
67+
- uses: actions/checkout@v4
68+
with:
69+
fetch-depth: 0
70+
71+
- name: Create release
72+
uses: softprops/action-gh-release@v2
73+
with:
74+
name: ${{ github.ref_name }}
75+
generate_release_notes: true
76+
draft: false
77+
prerelease: ${{ contains(github.ref_name, '-') }}

.yarnrc.yml

Lines changed: 0 additions & 1 deletion
This file was deleted.

README.md

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,62 @@
1-
# @foxglove/wasm-zstd
1+
# @ioai/wasm-zstd
22

3-
https://github.com/facebook/zstd compiled to WebAssembly and exposed as a high-level TypeScript/JavaScript API . PRs welcome!
3+
Vite-friendly WebAssembly bindings for [facebook/zstd](https://github.com/facebook/zstd).
44

55
## API
66

7-
`@foxglove/wasm-zstd` exports:
7+
`@ioai/wasm-zstd` exports:
88

99
```typescript
10-
export const isLoaded: Promise<boolean>;
10+
export interface InitOptions {
11+
wasmUrl?: string | URL;
12+
wasmBinary?: ArrayBuffer | ArrayBufferView;
13+
locateFile?: (path: string, prefix: string) => string;
14+
module?: Record<string, unknown>;
15+
}
16+
17+
export function init(options?: InitOptions): Promise<void>;
1118
export function compressBound(size: number): number;
12-
export function compress(buffer: Uint8Array, compressionLevel?: number): Buffer;
13-
export function decompress(buffer: Uint8Array, size: number): Buffer;
19+
export function compress(buffer: Uint8Array | ArrayBuffer | ArrayBufferView, compressionLevel?: number): Uint8Array;
20+
export function decompress(buffer: Uint8Array | ArrayBuffer | ArrayBufferView, size: number): Uint8Array;
1421
```
1522

16-
Here is an example of compressing then decompressing with this library:
17-
18-
```js
19-
import fs from "fs/promises";
20-
import zstd from "@foxglove/wasm-zstd";
23+
## Usage with Vite
2124

22-
async function main() {
23-
const inputData = await fs.readFile("input.txt");
25+
Import the wasm binary as an explicit URL and initialize the module once before calling
26+
`compress` or `decompress`.
2427

25-
// Wait for the wasm module to load
26-
await zstd.isLoaded;
28+
```ts
29+
import { compress, decompress, init } from "@ioai/wasm-zstd";
30+
import wasmUrl from "@ioai/wasm-zstd/wasm-zstd.wasm?url";
2731

28-
// Compress and save to a file with zstd compression level 3
29-
const compressedBytes = zstd.compress(inputData, 3);
30-
await fs.writeFile("compressed.zst", compressedBytes);
32+
await init({ wasmUrl });
3133

32-
// Currently you need to know the size of the output buffer so the wasm runtime
33-
// can allocate enough bytes to decompress into
34-
const outputSize = inputData.byteLength;
35-
36-
// Decompress
37-
const decompressedBytes = zstd.decompress(compressedBytes, inputData.byteLength);
38-
assert(decompressedBytes.byteLength === inputData.byteLength);
39-
}
34+
const compressed = compress(new TextEncoder().encode("hello zstd"), 3);
35+
const decompressed = decompress(compressed, "hello zstd".length);
4036
```
4137

42-
## Using the module in a browser
38+
This pattern works in browser main-thread code, Web Workers, and Vite production builds because
39+
Vite owns the `.wasm` asset URL.
4340

44-
Emscripten compiled WebAssembly modules are built in 2 parts: a `.js` side and a `.wasm` side. In the browser the `.js` side needs to download the `.wasm` side from the server so it can compile it. There is [more information available in the emscripten documentation](https://kripken.github.io/emscripten-site/docs/compiling/Deploying-Pages.html).
41+
## Usage with custom loaders
4542

46-
## Developing locally
43+
If you already have the wasm bytes, pass them with `wasmBinary`:
4744

48-
1. Run `yarn install` to install dependencies.
49-
2. Run `yarn build` to invoke emcc inside a Docker container and compile the code in `wasm-zstd.c` as well as the required zstd source files. The output will be in `dist/` on the host machine.
50-
3. Run `yarn test` to run the tests.
45+
```ts
46+
import { init } from "@ioai/wasm-zstd";
5147

52-
## License
48+
await init({ wasmBinary });
49+
```
5350

54-
@foxglove/wasm-zstd is licensed under the [MIT License](https://opensource.org/licenses/MIT).
51+
## Developing locally
5552

56-
## Releasing
53+
1. Run `npm install`.
54+
2. Run `npm run build` to invoke emcc inside Docker and compile `src/wasm-zstd.c` plus the vendored zstd sources.
55+
3. Run `npm test`.
5756

58-
1. Run `yarn version --[major|minor|patch]` to bump version
59-
2. Run `git push && git push --tags` to push new tag
60-
3. GitHub Actions will take care of the rest
57+
The generated package files are written to `dist/`.
58+
59+
## License
6160

62-
## Stay in touch
61+
`@ioai/wasm-zstd` is licensed under the [MIT License](https://opensource.org/licenses/MIT).
6362

64-
Join our [Slack channel](https://foxglove.dev/slack) to ask questions, share feedback, and stay up to date on what our team is working on.

build.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
mkdir -p dist
25

36
emcc \
47
vendor/zstd/lib/common/debug.c \
@@ -29,8 +32,9 @@ emcc \
2932
-o dist/wasm-zstd.js src/wasm-zstd.c `# this runs emscripten on the code in wasm-zstd.c` \
3033
-O3 `# compile with all optimizations enabled` \
3134
-s WASM=1 `# compile to .wasm instead of asm.js` \
32-
--pre-js pre.js `# include pre.js at the top of wasm-zstd.js` \
33-
-s MODULARIZE=1 `# include module boilerplate for better node/webpack interop` \
35+
-s MODULARIZE=1 `# expose a module factory instead of mutating globals` \
36+
-s EXPORT_ES6=1 `# emit an ES module that Vite can bundle` \
37+
-s ENVIRONMENT=web,worker `# avoid Node-only fs/path/require branches in browser builds` \
3438
-s NO_EXIT_RUNTIME=1 `# keep the process around after main exits` \
3539
-s TOTAL_STACK=1048576 `# use a 1MB stack size instead of the default 5MB` \
3640
-s INITIAL_MEMORY=2097152 `# start with a 2MB allocation instead of 16MB, we will dynamically grow` \

docker-build.sh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#!/usr/bin/env bash
2+
set -euo pipefail
23

34
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
4-
cd $SCRIPT_DIR
5+
cd "$SCRIPT_DIR"
56

6-
docker build . -t wasm-zstd
7+
docker build --progress=plain . -t ioai-wasm-zstd
78

89
mkdir -p dist
910

10-
docker run --rm -v "${SCRIPT_DIR}/dist":/src/dist -t wasm-zstd ./build.sh
11+
docker run --rm -v "${SCRIPT_DIR}/dist":/src/dist ioai-wasm-zstd ./build.sh

index.d.ts

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,32 @@
1-
declare module "@foxglove/wasm-zstd" {
2-
export const isLoaded: Promise<boolean>;
3-
export function compressBound(size: number): number;
4-
export function compress(buffer: Uint8Array, compressionLevel?: number): Buffer;
5-
export function decompress(buffer: Uint8Array, size: number): Buffer;
1+
export interface InitOptions {
2+
/**
3+
* URL for the generated wasm file. In Vite, import it with:
4+
* `import wasmUrl from "@ioai/wasm-zstd/wasm-zstd.wasm?url"`.
5+
*/
6+
wasmUrl?: string | URL;
7+
8+
/**
9+
* Raw wasm bytes. Useful for Node tests or custom loaders.
10+
*/
11+
wasmBinary?: ArrayBuffer | ArrayBufferView;
12+
13+
/**
14+
* Advanced Emscripten file resolver. Ignored when wasmUrl is provided.
15+
*/
16+
locateFile?: (path: string, prefix: string) => string;
17+
18+
/**
19+
* Additional Emscripten module options.
20+
*/
21+
module?: Record<string, unknown>;
622
}
23+
24+
export function init(options?: InitOptions): Promise<void>;
25+
export function compressBound(size: number): number;
26+
export function compress(buffer: Uint8Array | ArrayBuffer | ArrayBufferView, compressionLevel?: number): Uint8Array;
27+
export function decompress(buffer: Uint8Array | ArrayBuffer | ArrayBufferView, size: number): Uint8Array;
28+
29+
/**
30+
* Exposes the raw Emscripten module for tests and diagnostics.
31+
*/
32+
export function getModuleForTesting(): unknown;

package-lock.json

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)