Skip to content

Commit 41aa877

Browse files
committed
perf: direct WASM serialization + single-parse; bump to 0.1.1; add release automation
1 parent b321b0c commit 41aa877

8 files changed

Lines changed: 365 additions & 40 deletions

File tree

.github/workflows/release.yml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Release pipeline for jsonstat-wasm.
2+
#
3+
# Triggered when a `v*` tag is pushed (e.g. by scripts/release.sh). It rebuilds
4+
# the package exactly like CI, verifies the tag matches Cargo.toml, publishes
5+
# the patched pkg/ to npm, and creates the GitHub Release.
6+
#
7+
# Required repository secret:
8+
# NPM_TOKEN — an npm automation token with publish rights to `jsonstat-wasm`.
9+
name: Release
10+
11+
on:
12+
push:
13+
tags:
14+
- "v*"
15+
16+
permissions:
17+
contents: write # create the GitHub Release
18+
id-token: write # npm provenance (--provenance) attestation
19+
20+
concurrency:
21+
group: release-${{ github.ref }}
22+
cancel-in-progress: false
23+
24+
env:
25+
CARGO_TERM_COLOR: always
26+
27+
jobs:
28+
release:
29+
name: Build, publish & release
30+
runs-on: ubuntu-24.04
31+
32+
steps:
33+
- name: Checkout
34+
uses: actions/checkout@v4
35+
36+
- name: Install Rust toolchain
37+
uses: dtolnay/rust-toolchain@stable
38+
with:
39+
components: rustfmt, clippy
40+
targets: wasm32-unknown-unknown
41+
42+
- name: Cache cargo
43+
uses: Swatinem/rust-cache@v2
44+
45+
- name: Install wasm-pack
46+
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f --version 0.13.1
47+
48+
# ── Verify the tag matches the crate version ─────────────────────────
49+
# Guards against a tag like v0.1.2 pointing at a commit whose Cargo.toml
50+
# still says 0.1.1 (which would publish the wrong version).
51+
- name: Verify tag matches Cargo.toml version
52+
run: |
53+
CARGO_VERSION="$(grep -m1 '^version = ' Cargo.toml | sed -E 's/^version = "(.*)"/\1/')"
54+
TAG_VERSION="${GITHUB_REF_NAME#v}"
55+
echo "Cargo.toml: ${CARGO_VERSION} tag: ${TAG_VERSION}"
56+
if [[ "${CARGO_VERSION}" != "${TAG_VERSION}" ]]; then
57+
echo "::error::Tag ${GITHUB_REF_NAME} does not match Cargo.toml version ${CARGO_VERSION}"
58+
exit 1
59+
fi
60+
61+
# ── Verification gates (mirror ci.yml) ───────────────────────────────
62+
- name: Run tests
63+
run: cargo test
64+
65+
- name: Build WASM package
66+
run: bash scripts/build.sh
67+
68+
# ── Publish to npm ───────────────────────────────────────────────────
69+
- name: Setup Node
70+
uses: actions/setup-node@v4
71+
with:
72+
node-version: "20"
73+
registry-url: "https://registry.npmjs.org"
74+
75+
- name: Type-check bindings
76+
run: npx --yes -p typescript@5 tsc --noEmit
77+
78+
- name: Publish to npm
79+
run: npm publish ./pkg --access public --provenance
80+
env:
81+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
82+
83+
# ── GitHub Release ───────────────────────────────────────────────────
84+
- name: Create GitHub Release
85+
env:
86+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
87+
run: gh release create "${GITHUB_REF_NAME}" --title "${GITHUB_REF_NAME}" --generate-notes

Cargo.lock

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

Cargo.toml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "jsonstat-wasm"
3-
version = "0.1.0"
3+
version = "0.1.1"
44
edition = "2021"
55
description = "A fast JSON-stat 2.0 parser compiled to WebAssembly"
66
repository = "https://github.com/jsonstat/wasm"
@@ -10,14 +10,32 @@ license = "MIT"
1010
crate-type = ["cdylib", "rlib"]
1111

1212
[dependencies]
13-
wasm-bindgen = "0.2.92"
13+
wasm-bindgen = "0.2.125"
1414
serde = { version = "1.0", features = ["derive"] }
1515
serde_json = { version = "1.0", features = ["preserve_order"] }
1616
console_error_panic_hook = "0.1.7"
1717
serde-wasm-bindgen = "0.6.5"
18-
js-sys = "0.3.100"
18+
js-sys = "0.3.102"
1919
# Preserves insertion order for the `dimension` map so ToJSON() emits
2020
# dimensions in the same order as the source document. Already resolved
2121
# transitively via serde_json's `preserve_order` feature; declared directly
2222
# here to use IndexMap in our own model types.
2323
indexmap = { version = "2", features = ["serde"] }
24+
25+
# Release profile tuned for WebAssembly: smaller binary and faster runtime.
26+
# `lto` + `codegen-units = 1` improve both speed and size; `opt-level = "s"`,
27+
# `strip` and `panic = "abort"` further shrink the `.wasm`. wasm-pack still
28+
# runs `wasm-opt` on top of this.
29+
[profile.release]
30+
opt-level = "s"
31+
lto = true
32+
codegen-units = 1
33+
panic = "abort"
34+
strip = true
35+
36+
# wasm-opt settings for `wasm-pack build --release`. Current rustc emits the
37+
# `bulk-memory` and `nontrapping-float-to-int` WASM features by default, which
38+
# older bundled `wasm-opt` versions reject unless explicitly enabled. We keep
39+
# `-O` (size/speed optimization) and enable those features so wasm-opt runs.
40+
[package.metadata.wasm-pack.profile.release]
41+
wasm-opt = ['-O', '--enable-bulk-memory', '--enable-nontrapping-float-to-int']

docs/INSTALL.md

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,14 @@ esm.sh). Two entry points are available:
134134
| `…/jsonstat.js` | **High-level facade**`JSONstat()` toolkit function with automatic one-time init (recommended) |
135135
| `…/jsonstat_wasm.js` | **Low-level glue** — raw `JSONstat` class + `init()` you call yourself |
136136

137-
Always **pin the version** (here `0.1.0`, matching `Cargo.toml` / `package.json`).
137+
Always **pin the version** (here `0.1.1`, matching `Cargo.toml` / `package.json`).
138138

139139
#### High-level facade (recommended)
140140

141141
```html
142142
<script type="module">
143143
import { JSONstat }
144-
from 'https://cdn.jsdelivr.net/npm/jsonstat-wasm@0.1.0/jsonstat.js';
144+
from 'https://cdn.jsdelivr.net/npm/jsonstat-wasm@0.1.1/jsonstat.js';
145145
146146
// No init() needed — the facade initializes the WASM module exactly once
147147
// on first import and gates every call behind that shared promise.
@@ -158,7 +158,7 @@ at the exact `.js` file the binary is fetched automatically:
158158

159159
```js
160160
import init, { JSONstat, init_panic_hook }
161-
from 'https://cdn.jsdelivr.net/npm/jsonstat-wasm@0.1.0/jsonstat_wasm.js';
161+
from 'https://cdn.jsdelivr.net/npm/jsonstat-wasm@0.1.1/jsonstat_wasm.js';
162162

163163
await init(); // .wasm resolved via import.meta.url ✅
164164
init_panic_hook();
@@ -171,9 +171,9 @@ case pass the binary URL directly to `init()`, which accepts a
171171
`string` / `URL` / `Request`:
172172

173173
```js
174-
import init, { JSONstat } from 'https://esm.sh/jsonstat-wasm@0.1.0/glue';
174+
import init, { JSONstat } from 'https://esm.sh/jsonstat-wasm@0.1.1/glue';
175175

176-
await init('https://esm.sh/jsonstat-wasm@0.1.0/jsonstat_wasm_bg.wasm');
176+
await init('https://esm.sh/jsonstat-wasm@0.1.1/jsonstat_wasm_bg.wasm');
177177
const ds = new JSONstat(jsonStr);
178178
```
179179

@@ -254,3 +254,40 @@ cargo test
254254
# Rust unit tests (WASM target)
255255
wasm-pack test --node
256256
```
257+
258+
## Releasing & Publishing
259+
260+
Releases are tag-driven and fully automated. Pushing a `v<version>` tag triggers
261+
[`.github/workflows/release.yml`](../.github/workflows/release.yml), which
262+
rebuilds the package, verifies the tag matches `Cargo.toml`, runs the test and
263+
type-check gates, **publishes the patched `pkg/` to npm**, and **creates the
264+
GitHub Release**.
265+
266+
### One-time setup
267+
268+
Add an npm **automation** access token as a repository secret so the workflow
269+
can publish:
270+
271+
1. Create the token at npm → **Account → Access Tokens → Generate New Token →
272+
Automation** (it needs publish rights to `jsonstat-wasm`).
273+
2. In GitHub: **Settings → Secrets and variables → Actions → New repository
274+
secret**, name it `NPM_TOKEN`, and paste the token.
275+
276+
> The workflow publishes with [npm provenance](https://docs.npmjs.com/generating-provenance-statements)
277+
> (`--provenance`), which relies on the `id-token: write` permission already
278+
> declared in the workflow. Drop the `--provenance` flag if you don't want it.
279+
280+
### Cutting a release
281+
282+
1. Bump the version in [`Cargo.toml`](../Cargo.toml) (and update any pinned
283+
`@<version>` CDN references), then commit and push to `main`.
284+
2. Run the release helper from a clean tree on `main`:
285+
286+
```bash
287+
./scripts/release.sh # tags v<version> and pushes it
288+
./scripts/release.sh --dry-run # preview without tagging
289+
```
290+
291+
The script validates the working tree, builds locally as a sanity check,
292+
then creates and pushes the annotated `v<version>` tag. The push is what
293+
triggers the publish workflow above — no manual `npm publish` needed.

jsonstat.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
// That means a CDN consumer can simply:
2626
//
2727
// import { JSONstat }
28-
// from 'https://cdn.jsdelivr.net/npm/jsonstat-wasm@0.1.0/jsonstat.js';
28+
// from 'https://cdn.jsdelivr.net/npm/jsonstat-wasm@0.1.1/jsonstat.js';
2929
//
3030
// and initialization is fully automatic.
3131
//

0 commit comments

Comments
 (0)