2026-05-09 13:44:00 +00:00
#!/usr/bin/env bash
# tools/check-wasm-bundle.sh — Step 1b §6 + §7.1 local bundle gate.
#
2026-06-19 04:56:43 +00:00
# What this script enforces (matches the CanvasKit production bundle gate
# and the env.* import count guard):
# 1. Required local tools are available: cargo, wasm-bindgen, wasm-opt,
# node, and gzip. CanvasKit needs no EMSDK / skia-safe / libc shim.
refactor(renderer): consolidate web shell on CanvasKit, retire skia path
Retire the from-scratch wasm32 skia raster web backend and the vendored
skia-safe fork now that CanvasKit is the sole web renderer.
- remove gl-webgl-shim + the `webgl` feature + backend/webgl.rs
- absorb chat streaming, live-sync, codegen, icon search, Figma/file IO,
and system fonts into the `canvaskit` build via a backend-agnostic
`RepaintContext` trait; wire them into `mount_ck` (chat send, image
paste routing, window resize)
- delete the skia raster modules (backend/, a11y, shell_drop/resize,
ime_target, boolean_ops, caret_pump, repaint_scheduler) + the skia
`Inner` mount; op-host-web is now `web` (stub) + `canvaskit` only
- drop [patch.crates-io]; delete vendor/skia-safe-op + crates/wasm-libc-shim
so skia-safe reverts to upstream crates.io 0.97.x (native unchanged,
byte-identical; upstream has no wasm32-unknown-unknown target)
- switch the bundle gate (check-wasm-bundle.sh) to --features canvaskit
Also float new shapes above the frame (z-order), inset the shape-picker
selected-row highlight, and align the web file-menu hover without the
traffic-light inset.
Builds clean: canvaskit + web-stub (wasm32) + native desktop; bundle gate
passes (0 env.*, 4.5 MiB gzip).
2026-06-18 01:34:37 +00:00
# 2. cargo build → wasm-bindgen → wasm-opt -Oz pipeline produces the
2026-06-19 04:56:43 +00:00
# served crates/op-host-web/pkg/op_host_web_bg.wasm. `wasm-opt` is invoked
# with the core WebAssembly features emitted by current rustc.
2026-05-09 13:44:00 +00:00
# 3. Post-bindgen bundle has 0 env.* imports
2026-05-16 16:01:35 +00:00
# (i.e. all imports come from `./op_host_web_bg.js`,
2026-05-09 13:44:00 +00:00
# the wasm-bindgen JS shim). Any env.* import = LinkError at
# load time → regression → fail.
# 4. Post wasm-opt -Oz gzip size ≤ STEP1B_SHELL_WASM_GZIP_LIMIT_BYTES
2026-06-19 04:56:43 +00:00
# (default 6 291 456 bytes = 6 MiB for the full CanvasKit app logic).
2026-05-09 13:44:00 +00:00
#
2026-06-19 04:56:43 +00:00
# This script is the local counterpart to
# `.github/workflows/wasm-bundle-build.yml`; keep the two recipes aligned.
2026-05-09 13:44:00 +00:00
#
# Exit semantics:
# 0 all four checks PASS.
# 1 any check FAILED — message names which one.
2026-06-19 04:56:43 +00:00
# 2 prerequisite missing (cargo / wasm-bindgen / wasm-opt / node / gzip).
2026-05-09 13:44:00 +00:00
set -euo pipefail
2026-05-16 16:01:35 +00:00
CRATE_DIR = "crates/op-host-web"
2026-05-09 13:44:00 +00:00
PKG_DIR = " ${ CRATE_DIR } /pkg "
2026-05-16 16:01:35 +00:00
WASM_RAW = " ${ PKG_DIR } /op_host_web_bg.wasm "
WASM_OPT = " ${ PKG_DIR } /op_host_web_bg.opt.wasm "
TARGET_WASM = "target/wasm32-unknown-unknown/release/op_host_web.wasm"
2026-07-02 16:08:17 +00:00
# The wasm feature flags rustc emits for wasm32-unknown-unknown that wasm-opt
# must be told to accept. Kept as CANDIDATES because binaryen versions disagree
# on their spelling: newer binaryen (dev machines, v117+) split bulk-memory into
# `bulk-memory` (memory.init/data.drop) + `bulk-memory-opt` (memory.copy/fill),
# while older binaryen (e.g. Ubuntu's apt `binaryen`) predates the split and its
# single `--enable-bulk-memory` already covers memory.copy/fill. Passing an
# unknown flag hard-fails wasm-opt ("Unknown option"), so we filter the list
# down to only the flags the installed wasm-opt actually advertises in --help.
WASM_OPT_CANDIDATE_FEATURES = (
2026-06-19 04:56:43 +00:00
--enable-bulk-memory
--enable-bulk-memory-opt
--enable-nontrapping-float-to-int
)
2026-05-09 13:44:00 +00:00
refactor(renderer): consolidate web shell on CanvasKit, retire skia path
Retire the from-scratch wasm32 skia raster web backend and the vendored
skia-safe fork now that CanvasKit is the sole web renderer.
- remove gl-webgl-shim + the `webgl` feature + backend/webgl.rs
- absorb chat streaming, live-sync, codegen, icon search, Figma/file IO,
and system fonts into the `canvaskit` build via a backend-agnostic
`RepaintContext` trait; wire them into `mount_ck` (chat send, image
paste routing, window resize)
- delete the skia raster modules (backend/, a11y, shell_drop/resize,
ime_target, boolean_ops, caret_pump, repaint_scheduler) + the skia
`Inner` mount; op-host-web is now `web` (stub) + `canvaskit` only
- drop [patch.crates-io]; delete vendor/skia-safe-op + crates/wasm-libc-shim
so skia-safe reverts to upstream crates.io 0.97.x (native unchanged,
byte-identical; upstream has no wasm32-unknown-unknown target)
- switch the bundle gate (check-wasm-bundle.sh) to --features canvaskit
Also float new shapes above the frame (z-order), inset the shape-picker
selected-row highlight, and align the web file-menu hover without the
traffic-light inset.
Builds clean: canvaskit + web-stub (wasm32) + native desktop; bundle gate
passes (0 env.*, 4.5 MiB gzip).
2026-06-18 01:34:37 +00:00
# Ceiling for the CanvasKit production bundle's gzipped wasm. It is far above
# the retired skia raster path's 1 MiB (spec §6) because this bundle now carries
# the FULL app logic absorbed from the skia path (codegen AI pipeline, Figma
# parser, AI/live-sync). ~4.5 MiB today. TODO(perf): code-split / lazy-load the
# codegen + Figma paths to shrink the initial download. Override via env.
LIMIT = " ${ STEP1B_SHELL_WASM_GZIP_LIMIT_BYTES :- 6291456 } "
2026-05-09 13:44:00 +00:00
step( ) { printf '\n[step %d/%d] %s\n' " $1 " " $2 " " $3 " ; }
fail( ) { printf 'FAIL: %s\n' " $1 " >& 2; exit 1; }
need( ) { command -v " $1 " >/dev/null 2>& 1 || { printf 'missing prerequisite: %s\n' " $1 " >& 2; exit 2; } ; }
step 1 5 "Verify prerequisites"
need cargo
need wasm-bindgen
need wasm-opt
need node
need gzip
refactor(renderer): consolidate web shell on CanvasKit, retire skia path
Retire the from-scratch wasm32 skia raster web backend and the vendored
skia-safe fork now that CanvasKit is the sole web renderer.
- remove gl-webgl-shim + the `webgl` feature + backend/webgl.rs
- absorb chat streaming, live-sync, codegen, icon search, Figma/file IO,
and system fonts into the `canvaskit` build via a backend-agnostic
`RepaintContext` trait; wire them into `mount_ck` (chat send, image
paste routing, window resize)
- delete the skia raster modules (backend/, a11y, shell_drop/resize,
ime_target, boolean_ops, caret_pump, repaint_scheduler) + the skia
`Inner` mount; op-host-web is now `web` (stub) + `canvaskit` only
- drop [patch.crates-io]; delete vendor/skia-safe-op + crates/wasm-libc-shim
so skia-safe reverts to upstream crates.io 0.97.x (native unchanged,
byte-identical; upstream has no wasm32-unknown-unknown target)
- switch the bundle gate (check-wasm-bundle.sh) to --features canvaskit
Also float new shapes above the frame (z-order), inset the shape-picker
selected-row highlight, and align the web file-menu hover without the
traffic-light inset.
Builds clean: canvaskit + web-stub (wasm32) + native desktop; bundle gate
passes (0 env.*, 4.5 MiB gzip).
2026-06-18 01:34:37 +00:00
# CanvasKit needs NO EMSDK / skia-safe / libc shim — the editor renders through
# the official CanvasKit skia WASM (loaded separately from /canvaskit/) and the
# Rust bundle is pure logic. (The retired skia raster path needed EMSDK.)
2026-05-09 13:44:00 +00:00
refactor(renderer): consolidate web shell on CanvasKit, retire skia path
Retire the from-scratch wasm32 skia raster web backend and the vendored
skia-safe fork now that CanvasKit is the sole web renderer.
- remove gl-webgl-shim + the `webgl` feature + backend/webgl.rs
- absorb chat streaming, live-sync, codegen, icon search, Figma/file IO,
and system fonts into the `canvaskit` build via a backend-agnostic
`RepaintContext` trait; wire them into `mount_ck` (chat send, image
paste routing, window resize)
- delete the skia raster modules (backend/, a11y, shell_drop/resize,
ime_target, boolean_ops, caret_pump, repaint_scheduler) + the skia
`Inner` mount; op-host-web is now `web` (stub) + `canvaskit` only
- drop [patch.crates-io]; delete vendor/skia-safe-op + crates/wasm-libc-shim
so skia-safe reverts to upstream crates.io 0.97.x (native unchanged,
byte-identical; upstream has no wasm32-unknown-unknown target)
- switch the bundle gate (check-wasm-bundle.sh) to --features canvaskit
Also float new shapes above the frame (z-order), inset the shape-picker
selected-row highlight, and align the web file-menu hover without the
traffic-light inset.
Builds clean: canvaskit + web-stub (wasm32) + native desktop; bundle gate
passes (0 env.*, 4.5 MiB gzip).
2026-06-18 01:34:37 +00:00
# `canvaskit` is the production browser feature set: the editor renders through
# CanvasKit on the GPU and bundles the full app logic absorbed from the retired
# skia raster path — daemon-backed AI chat (`web_chat`), live-sync, browser file
# IO, clipboard/Figma paste, icon search, system fonts, and the codegen pipeline.
step 2 5 "Build shell-web wasm32-unknown-unknown with --features canvaskit"
2026-05-16 16:01:35 +00:00
cargo build -p op-host-web \
refactor(renderer): consolidate web shell on CanvasKit, retire skia path
Retire the from-scratch wasm32 skia raster web backend and the vendored
skia-safe fork now that CanvasKit is the sole web renderer.
- remove gl-webgl-shim + the `webgl` feature + backend/webgl.rs
- absorb chat streaming, live-sync, codegen, icon search, Figma/file IO,
and system fonts into the `canvaskit` build via a backend-agnostic
`RepaintContext` trait; wire them into `mount_ck` (chat send, image
paste routing, window resize)
- delete the skia raster modules (backend/, a11y, shell_drop/resize,
ime_target, boolean_ops, caret_pump, repaint_scheduler) + the skia
`Inner` mount; op-host-web is now `web` (stub) + `canvaskit` only
- drop [patch.crates-io]; delete vendor/skia-safe-op + crates/wasm-libc-shim
so skia-safe reverts to upstream crates.io 0.97.x (native unchanged,
byte-identical; upstream has no wasm32-unknown-unknown target)
- switch the bundle gate (check-wasm-bundle.sh) to --features canvaskit
Also float new shapes above the frame (z-order), inset the shape-picker
selected-row highlight, and align the web file-menu hover without the
traffic-light inset.
Builds clean: canvaskit + web-stub (wasm32) + native desktop; bundle gate
passes (0 env.*, 4.5 MiB gzip).
2026-06-18 01:34:37 +00:00
--target wasm32-unknown-unknown --no-default-features --features canvaskit --release >/dev/null
2026-05-09 13:44:00 +00:00
step 3 5 " wasm-bindgen --target web → ${ PKG_DIR } / "
wasm-bindgen --target web --out-dir " ${ PKG_DIR } " " ${ TARGET_WASM } " >/dev/null
step 4 5 "Verify 0 env.* imports (spec §7.1 import guard)"
env_count = " $( node -e '
const fs = require( "fs" ) ;
const buf = fs.readFileSync( process.argv[ 1] ) ;
WebAssembly.compile( buf) .then( mod = > {
const imps = WebAssembly.Module.imports( mod) ;
const env = imps.filter( i = > i.module = = = "env" ) ;
console.log( env.length) ;
} ) .catch( e = > { console.error( "compile failed:" , e) ; process.exit( 1) ; } ) ;
' " ${ WASM_RAW } " ) "
if [ " ${ env_count } " != "0" ] ; then
refactor(renderer): consolidate web shell on CanvasKit, retire skia path
Retire the from-scratch wasm32 skia raster web backend and the vendored
skia-safe fork now that CanvasKit is the sole web renderer.
- remove gl-webgl-shim + the `webgl` feature + backend/webgl.rs
- absorb chat streaming, live-sync, codegen, icon search, Figma/file IO,
and system fonts into the `canvaskit` build via a backend-agnostic
`RepaintContext` trait; wire them into `mount_ck` (chat send, image
paste routing, window resize)
- delete the skia raster modules (backend/, a11y, shell_drop/resize,
ime_target, boolean_ops, caret_pump, repaint_scheduler) + the skia
`Inner` mount; op-host-web is now `web` (stub) + `canvaskit` only
- drop [patch.crates-io]; delete vendor/skia-safe-op + crates/wasm-libc-shim
so skia-safe reverts to upstream crates.io 0.97.x (native unchanged,
byte-identical; upstream has no wasm32-unknown-unknown target)
- switch the bundle gate (check-wasm-bundle.sh) to --features canvaskit
Also float new shapes above the frame (z-order), inset the shape-picker
selected-row highlight, and align the web file-menu hover without the
traffic-light inset.
Builds clean: canvaskit + web-stub (wasm32) + native desktop; bundle gate
passes (0 env.*, 4.5 MiB gzip).
2026-06-18 01:34:37 +00:00
fail " env.* import count = ${ env_count } (must be 0); the CanvasKit bundle has no libc shim, so an env.* import means a dep pulled non-wasm-clean code — find and gate it out "
2026-05-09 13:44:00 +00:00
fi
printf ' ✓ 0 env.* imports\n'
step 5 5 " Verify gzip size ≤ ${ LIMIT } bytes (spec §6 ceiling) "
2026-07-02 16:08:17 +00:00
# Keep only the candidate feature flags this wasm-opt understands (see the
# WASM_OPT_CANDIDATE_FEATURES note) so an older binaryen doesn't hard-fail on
# `--enable-bulk-memory-opt`. `--enable-bulk-memory` alone still covers
# memory.copy/fill on those versions.
wasm_opt_help = " $( wasm-opt --help 2>& 1 || true ) "
WASM_OPT_FEATURES = ( )
for flag in " ${ WASM_OPT_CANDIDATE_FEATURES [@] } " ; do
if printf '%s\n' " ${ wasm_opt_help } " | grep -qF -- " ${ flag } " ; then
WASM_OPT_FEATURES += ( " ${ flag } " )
fi
done
2026-06-19 04:56:43 +00:00
wasm-opt " ${ WASM_OPT_FEATURES [@] } " -Oz " ${ WASM_RAW } " -o " ${ WASM_OPT } " >/dev/null
refactor(renderer): consolidate web shell on CanvasKit, retire skia path
Retire the from-scratch wasm32 skia raster web backend and the vendored
skia-safe fork now that CanvasKit is the sole web renderer.
- remove gl-webgl-shim + the `webgl` feature + backend/webgl.rs
- absorb chat streaming, live-sync, codegen, icon search, Figma/file IO,
and system fonts into the `canvaskit` build via a backend-agnostic
`RepaintContext` trait; wire them into `mount_ck` (chat send, image
paste routing, window resize)
- delete the skia raster modules (backend/, a11y, shell_drop/resize,
ime_target, boolean_ops, caret_pump, repaint_scheduler) + the skia
`Inner` mount; op-host-web is now `web` (stub) + `canvaskit` only
- drop [patch.crates-io]; delete vendor/skia-safe-op + crates/wasm-libc-shim
so skia-safe reverts to upstream crates.io 0.97.x (native unchanged,
byte-identical; upstream has no wasm32-unknown-unknown target)
- switch the bundle gate (check-wasm-bundle.sh) to --features canvaskit
Also float new shapes above the frame (z-order), inset the shape-picker
selected-row highlight, and align the web file-menu hover without the
traffic-light inset.
Builds clean: canvaskit + web-stub (wasm32) + native desktop; bundle gate
passes (0 env.*, 4.5 MiB gzip).
2026-06-18 01:34:37 +00:00
cp " ${ WASM_OPT } " " ${ WASM_RAW } "
2026-05-09 13:44:00 +00:00
gz_bytes = " $( gzip -c " ${ WASM_OPT } " | wc -c | tr -d ' ' ) "
if [ " ${ gz_bytes } " -gt " ${ LIMIT } " ] ; then
fail " shell-web wasm gzip size ${ gz_bytes } bytes > ceiling ${ LIMIT } bytes "
fi
pct = $(( ( gz_bytes * 100 ) / LIMIT ))
printf ' ✓ gzip size %s bytes (%d%% of %s ceiling)\n' " ${ gz_bytes } " " ${ pct } " " ${ LIMIT } "
printf '\nAll Step 1b §6 + §7.1 bundle gates PASS.\n'