atproto Thingiverse but good
1# polymodel development commands
2
3set dotenv-load := false
4
5# Canonical SQLite database URL for the projection store and the compile-time
6# `query!` macros. Scoping it here (rather than via .env) keeps `just` recipes
7# hermetic — see `set dotenv-load := false` above.
8db-url := 'sqlite:./data/polymodel.db'
9
10default:
11 @just --list
12
13# Format Rust sources. Run clippy/check separately; clippy --fix can corrupt RSX.
14fix:
15 cargo fmt --all
16# Run clippy without --fix; automatic clippy rewrites can corrupt Dioxus RSX.
17lint:
18 cargo clippy --workspace --all-targets -- -D warnings -A clippy::useless_format
19 cargo clippy -p polymodel --all-targets --features server -- -D warnings -A clippy::useless_format
20 cargo clippy -p polymodel --target wasm32-unknown-unknown --features web -- -D warnings -A clippy::useless_format
21# Compile checks across the whole workspace plus the app's server/wasm targets.
22# The server check resolves compile-time `query!` macros against the committed
23# `.sqlx` offline cache; regenerate it with `just sqlx-prepare` after changing
24# SQL or migrations.
25check:
26 cargo check --workspace
27 cargo check -p polymodel --features server
28 cargo check -p polymodel --target wasm32-unknown-unknown --features web
29 RUSTFLAGS='--cfg getrandom_backend="wasm_js"' cargo check -p polymodel-renderer-worker --target wasm32-unknown-unknown
30
31# Create and migrate the SQLite projection database.
32# Required when regenerating the `.sqlx` cache, and re-run after editing migrations.
33migrate:
34 mkdir -p ./data
35 cargo sqlx migrate run --source migrations --database-url '{{ db-url }}'
36
37# Regenerate the committed `.sqlx` offline query cache after changing SQL.
38# Self-contained: migrates the local database first, then points `cargo sqlx
39# prepare` at it via DATABASE_URL so no manual env setup is required.
40sqlx-prepare: migrate
41 DATABASE_URL='{{ db-url }}' cargo sqlx prepare -- -p polymodel --features server
42
43# Run unit tests across the workspace.
44test:
45 cargo nextest run --workspace
46
47# Run server-feature tests (app only; polymodel-api has no server feature).
48test-server:
49 cargo nextest run -p polymodel --features server
50
51# Run browser-backed wasm tests for the renderer worker.
52test-renderer:
53 RUSTFLAGS='--cfg getrandom_backend="wasm_js"' cargo test -p polymodel-renderer-worker --target wasm32-unknown-unknown
54
55# Run all local validation expected before review.
56test-all: fix check lint test test-server test-renderer
57# Run browser end-to-end tests.
58e2e:
59 cd e2e && npm test
60# Start the Dioxus dev server. Builds the renderer worker first if missing.
61serve *ARGS:
62 @if [ ! -f public/renderer_worker_bg.wasm ] || [ ! -f public/renderer_worker_loader.js ]; then echo "renderer worker not built — running just build-renderer-worker"; just build-renderer-worker; fi
63 dx serve {{ ARGS }}
64
65# Build the renderer worker WASM bundle (separate from the app WASM).
66build-renderer-worker:
67 RUSTFLAGS='--cfg getrandom_backend="wasm_js"' cargo build -p polymodel-renderer-worker --bin renderer_worker --target wasm32-unknown-unknown --profile worker-release
68 wasm-bindgen target/wasm32-unknown-unknown/worker-release/renderer_worker.wasm --target web --out-dir public --no-typescript
69 @if command -v wasm-opt &>/dev/null; then wasm-opt public/renderer_worker_bg.wasm -O4 --enable-bulk-memory --enable-simd --enable-nontrapping-float-to-int --enable-sign-ext -o public/renderer_worker_bg.wasm; else echo "wasm-opt not found, skipping optimization"; fi
70
71# Build and stage the single-threaded OpenCascade.js STEP conversion artifacts.
72build-opencascade-step:
73 node tools/renderer-step/build-and-stage-opencascade.mjs
74
75# Build the Dioxus app for web (includes renderer worker build).
76build-web: build-renderer-worker
77 dx build --platform web
78
79# Build the Dioxus app for web (release, optimized). Strips debug symbols and runs wasm-opt.
80build-web-release: build-renderer-worker build-opencascade-step
81 #!/usr/bin/env bash
82 set -e
83 dx build --platform web --release --debug-symbols=false
84 if command -v wasm-opt &>/dev/null; then
85 WASM=$(find target/dx/polymodel/release/web/public -name "polymodel_bg*.wasm" -print -quit 2>/dev/null)
86 if [ -n "$WASM" ]; then
87 echo "==> Running wasm-opt on $WASM"
88 BEFORE=$(stat -c%s "$WASM")
89 wasm-opt "$WASM" -Oz --enable-bulk-memory --enable-simd --enable-nontrapping-float-to-int --enable-sign-ext -o "$WASM" || { echo "==> wasm-opt failed, keeping unoptimized wasm"; exit 0; }
90 AFTER=$(stat -c%s "$WASM")
91 echo " $BEFORE -> $AFTER bytes"
92 fi
93 else
94 echo "==> wasm-opt not found, skipping optimization"
95 fi
96
97# Verify the renderer split: no heavy deps in the app, worker wasm exists, bundle size under ceiling.
98verify-renderer-split: build-web
99 @echo "==> AC.1: checking app dependency tree for forbidden crates..."
100 @if cargo tree -p polymodel --target wasm32-unknown-unknown --features web --edges normal 2>/dev/null | grep -qE '(^| )three-d v|three-d-asset v|stl_io v|polymodel-mesh v'; then echo "FAIL: forbidden crate found in app dependency tree"; exit 1; else echo "PASS: no forbidden crates"; fi
101 @echo "==> AC.1b: checking app Cargo.toml for forbidden deps..."
102 @if grep -qE '^\s*(three-d|three-d-asset|stl_io|polymodel-mesh)\b' Cargo.toml; then echo "FAIL: forbidden dep found in Cargo.toml"; exit 1; else echo "PASS: no forbidden deps in Cargo.toml"; fi
103 @echo "==> AC.2: checking app wasm bundle size (debug build, debuginfo-dominated)..."
104 @APP_WASM="target/dx/polymodel/debug/web/public/wasm/polymodel_bg.wasm" && test -f "$APP_WASM" && SIZE=$(stat -c%s "$APP_WASM") && echo "app wasm: $SIZE bytes" && test "$SIZE" -lt 134217728 && echo "PASS: app wasm < 128MB ceiling" || { echo "FAIL: app wasm >= 128MB or not found"; exit 1; }
105 @echo "==> AC.2b: checking worker wasm exists..."
106 @test -f public/renderer_worker_bg.wasm && echo "PASS: worker wasm exists" || { echo "FAIL: worker wasm not found"; exit 1; }
107 @echo "==> All renderer-split checks passed."
108
109# Regenerate crates/polymodel-api from authored lexicons via the local Jacquard checkout.
110generate-api:
111 nix run ../jacquard
112# Create a sibling jj workspace for a Jira ticket or feature slug, then start a fresh change.
113workspace-create name:
114 root="$(jj workspace root)" && workspace_path="$(dirname "$root")/{{ name }}" && jj workspace add "$workspace_path" -r @
115 root="$(jj workspace root)" && workspace_path="$(dirname "$root")/{{ name }}" && cd "$workspace_path" && jj desc -m "{{ name }}"
116
117# List jj workspaces.
118workspace-list:
119 jj workspace list
120
121# Forget a jj workspace after the work is safely landed or intentionally abandoned.
122workspace-forget name:
123 jj workspace forget {{ name }}
124
125# Show current jj state and diff.
126status:
127 jj status
128 jj diff --summary
129
130# Clean build artifacts.
131clean:
132 cargo clean
133 rm -rf target/dx