From f7e726714a3af60f007598d2d6c35a2bbdada1f5 Mon Sep 17 00:00:00 2001 From: Jeremy Yao Date: Tue, 13 Oct 2026 22:30:03 -0400 Subject: [PATCH] fix(text): don't rebuild every time a craft-fonts manifest is missing (#228) crates/text/build.rs asked cargo to watch both craft-fonts manifests whether or not they existed. Cargo takes a watched path that doesn't exist as changed, so figcraft-text and every crate above it were rebuilt on every build: with no craft-fonts checkout, and also with a checkout of craft-fonts' main branch, which has no fonts/latin-manifest.txt. Watch a manifest only when it exists, and its folder while it is missing, so a manifest added later is still noticed. With no checkout at all there is nothing to watch; the build warning and the README now say how to pick one up after a first build. Co-authored-by: Claude Opus 5.5 --- README.md | 2 ++ crates/text/build.rs | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4d9266c..29504a5 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,8 @@ Fonts for the UI and the Text tool come from [craft-fonts](https://github.com/st git clone https://github.com/storytold/craft-fonts ../craft-fonts ``` +If you clone it after a first build, run `cargo clean -p figcraft-text` once so the next build embeds the fonts. + **Start from a template.** The home screen's Templates tab has eight starter files (a mobile app, a landing page, a dashboard, a design system starter, a wireframe kit, social post sizes, presentation slides and an icon set starter), also under File ▸ New from template…. They are built in code from original, synthetic content, so scripts and agents can open them too: `file.newFromTemplate {template}` ([`docs/mcp.md`](docs/mcp.md#starter-templates)). For the web build, install [trunk](https://trunkrs.dev/) and run `cargo xtask wasm`. diff --git a/crates/text/build.rs b/crates/text/build.rs index e11de00..d02defe 100644 --- a/crates/text/build.rs +++ b/crates/text/build.rs @@ -25,7 +25,7 @@ fn main() { } } if !ok { - println!("cargo::warning=building without craft-fonts"); + println!("cargo::warning=building without craft-fonts (once it is there, `cargo clean -p figcraft-text` makes the next build use it)"); } } src.push_str("];\n"); @@ -35,9 +35,23 @@ fn main() { } } +/// Rebuild when `manifest` changes or, while it is missing, when it is added to its folder. +/// +/// Cargo takes a watched path that doesn't exist as changed on every build, and then rebuilds this +/// crate and every crate that depends on it each time. So a missing manifest is never watched +/// itself: its folder is, when there is one (a craft-fonts checkout without the Latin manifest). +/// With no craft-fonts at all there is nothing to watch, so the build can't notice it arriving: +/// the warning in `main` says how to pick it up. +fn watch(manifest: &std::path::Path) { + let watched = if manifest.exists() { Some(manifest) } else { manifest.parent().filter(|folder| folder.is_dir()) }; + if let Some(path) = watched { + println!("cargo::rerun-if-changed={}", path.display()); + } +} + fn craft_fonts(dir: &std::path::Path, manifest_rel: &str) -> Result { let manifest = dir.join(manifest_rel); - println!("cargo::rerun-if-changed={}", manifest.display()); + watch(&manifest); let text = std::fs::read_to_string(&manifest).map_err(|e| format!("{}: {e}", manifest.display()))?; let wasm = std::env::var("CARGO_CFG_TARGET_ARCH").is_ok_and(|a| a == "wasm32"); let mut out = String::new();