# Developing Typst Math Building, testing and releasing the plugin. For what it does and how to use it, see [README.md](README.md); for the design it was built to, [SPEC.md](SPEC.md). ## Getting set up The repository ships a Nix flake with everything pinned: ```bash nix develop # node 22, typst CLI, the NewCM fonts, jq npm install npm run dist # -> publish/com.github.justinvulz.typst-math.jpl npm test # 33 tests, real compiler, real wasm npm run typecheck # both tsconfigs, including the worker npm run bench # the §13 performance budgets ``` Point Joplin at this directory under **Tools → Options → Plugins → Advanced settings → Development plugins**, then reload. `nix develop .#joplin` adds Joplin desktop and the CLI to the shell. Without Nix, Node 22 and npm are enough for `npm install && npm run dist`. A bare `typst` in the dev shell sees exactly the fonts the plugin bundles, which makes it a much shorter loop than a Joplin reload when working on the source wrapping or the baseline probe. ## How it fits together ``` plugin process │ note viewer ───────────────────────────────────┼────────────────────────────────── src/index.ts │ · settings, registration │ · serves config, paths, bytes ◄┼──── webviewApi.postMessage ──┐ │ │ src/rendererScript.ts ─────────────┼──► placeholder HTML │ · calls Joplin's KaTeX renderer │ + declares assets │ · keeps its output as fallback │ │ │ assets/typstMath.js ────────┘ src/shared/wrap.ts │ · scans pending nodes src/worker/compiler.worker.ts ─────┼──► · compiles in a Worker │ · post-processes the SVG │ assets/typstMath.css ``` `scripts/stage-assets.mjs` bundles the worker and lifts the wasm out of `node_modules` into `dist/assets/`, between webpack's build and archive steps. Note that `assets/typstMath.js` is copied verbatim rather than compiled, so it is plain ES2017 with no imports. The few identifiers it shares with the TypeScript side are repeated there as literals and have to be kept in sync by hand. ## Mobile Desktop and mobile run the same code, but four things differ underneath, and each is handled rather than assumed away. `assets/typstMath.js` documents them where they are dealt with; in short: - Assets arrive over `joplin-content://` on desktop and `file://` on mobile, and `fetch()` cannot read the latter in a WebView. The reader picks the mechanism the scheme supports. - The mobile plugin process is a sandboxed iframe with no filesystem, so it cannot serve asset bytes as a fallback — only say where it was installed. - A Worker must be same-origin with its document, which means a blob URL on desktop and possibly the file itself on mobile. Both routes are tried. - `joplin-noteDidUpdate` fires once per webview on recent mobile versions, so a `MutationObserver` drives re-rendering instead. To debug on a device, enable webview debugging in Joplin's plugin settings and attach Chrome DevTools over `chrome://inspect`. The runtime logs why it could not start a compiler, and the same reason appears in the tooltip on any equation that fell back to KaTeX. ## Testing `test/` runs against the built artefacts, not the sources: the compiled content script, the bundled worker on a real worker thread, and the real 28 MB compiler. Run `npm run dist` before `npm test`. `test/helpers/joplinKatexRule.mjs` reproduces Joplin's own KaTeX rule so the handoff under test is the real one. `test/helpers/viewer.mjs` stands up a note viewer under the constraints of whichever host is being simulated — `delivery` picks the asset channel, `blobWorkers` whether the host allows a blob-backed Worker, `unreadable` which files it refuses. Every asset-delivery path is covered — desktop, mobile, a host that inlines the script, and the `postMessage` fallback — as are both routes to a worker, a host that allows neither, and a worker killed part-way through a note. ## Releasing The Joplin plugin repository builds itself from npm: it searches for packages keyed `joplin-plugin` and reads `publish/` out of them. 1. Bump `version` in **both** `package.json` and `src/manifest.json`. They must match, and npm will not let you republish a version. 2. `npm test && npm run typecheck`. 3. `npm publish` — the `prepare` script rebuilds the `.jpl` first. The repository bot picks the new version up within about half an hour. Note that a plugin ID is claimed permanently by the first npm package and repository URL to publish it, so neither can change afterwards.