Skip to content

Commit da39c71

Browse files
Self-host MathJax via @prosemark/latex vite plugin (url-import) (#150)
* Use top-level static MathJax import in LaTeX webview Replace deferred dynamic imports with a build-time side-effect import of mathjax/tex-svg.js (peer dependency of @prosemark/latex) so Vite fully bundles MathJax into webview.js before the webview loads. Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Keep latex setup handler async for readability Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Disable MathJax a11y speech worker in VS Code webview The tex-svg combined component loads sre/speech-worker.js at runtime, but Vite only emits webview.js. Turn off speech/enrichment for editor preview. Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Copy MathJax sre assets into webview dist via Vite plugin The tex-svg bundle loads sre/speech-worker.js at runtime as a web worker. Vite inlines the main IIFE but cannot bundle workers loaded via importScripts, so copy mathjax/sre/ next to webview.js after each build. Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Add @prosemark/latex vite-plugin-mathjax and self-host MathJax Export copyMathJaxAssets from @prosemark/latex/vite-plugin-mathjax with a configurable copy list (default tex-svg.js + sre). The LaTeX VS Code webview loads MathJax via url-import from dist/webview/mathjax/ instead of bundling tex-svg into webview.js (~48 KB vs ~1.8 MB). Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Keep latex setup handler async Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Fix MathJax URL resolution when multiple webview scripts load mathJaxPackageUrlFromWebviewScript used the last script tag, which was cspell-integration's webview.js when both companions are installed. Add scriptSrcIncludes and use latex-integration in the LaTeX webview. Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Pass MathJax package URL from extension host via asWebviewUri Extend SubExtensionCallback with the webview instance so sub-extensions can resolve local resource URLs with webview.asWebviewUri instead of reverse-engineering script tags in the webview. The LaTeX integration now passes mathJaxPackageUrl into setup from the extension host, removing the scriptSrcIncludes workaround. Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Remove mathJaxPackageUrlFromWebviewScript from @prosemark/latex VS Code integrations should pass mathJaxPackageUrl from the extension host via webview.asWebviewUri; script-tag discovery is no longer needed. Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Pass SubExtensionCallback context as a single object Sub-extension factories now receive { document, callProcAndForget, callProcWithReturnValue, webview } so each integration can destructure only what it needs without breaking when new fields are added. Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Document MathJax a11y/speech worker options for static-import Explain that tex-svg loads sre/speech-worker.js separately, and that static-import setups must either disable a11y or copy and serve sre/. Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Fix strict lint issues in latex package and extension Use a type guard for the webview vscode API instead of an unsafe cast, tighten the MathJax loader test helper, and include vite.config.mts in eslint file patterns. Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Fix MathJax 4 config: use startup.typeset instead of skipStartupTypeset MathJax 4 removed skipStartupTypeset; use startup.typeset: false to skip automatic page typesetting. Update @prosemark/latex preconfiguration, docs, and tests accordingly. Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Revert vite.config.mts in latex-integration eslint files list vite.config.mts is git-tracked source, but sibling VS Code extensions do not list their vite configs in eslint.config.ts and lint passes without it. Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Docs: drop unsupported claim that editor preview typically skips a11y The VS Code extension keeps speech support via url-import and copied sre/. Frame disabling a11y as a static-import tradeoff, not a preview default. Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Changeset: use patch bumps while packages are 0.x Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Changeset: drop startup.typeset note (introduced in this PR) Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Changeset: document pre-0.0.2 VS Code math rendering regression Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Changeset: split per package and fix VS Code regression wording Describe the 0.0.2 bug as math failing when MathJax was bundled into the extension; drop the speech-worker cause (introduced in this PR). Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Changeset: describe VS Code math bug as blocked CDN access Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Changeset: emphasize webview in integrator callback context Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com> * Fix LaTeX math rendering in VS Code webview Self-host MathJax in the extension to resolve rendering issues. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
1 parent d41f8e0 commit da39c71

24 files changed

Lines changed: 335 additions & 166 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@prosemark/vscode-extension-integrator': patch
3+
---
4+
5+
Pass sub-extension callback context as a single object including `webview`, so companion extensions can resolve webview resource URLs.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@prosemark/latex': patch
3+
---
4+
5+
Add `@prosemark/latex/vite-plugin-mathjax` to copy configurable paths from the `mathjax` npm package into a Vite build output.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
vscode-prosemark-latex-integration: patch
3+
---
4+
5+
Fix LaTeX math rendering issue in the VS Code extension webview by self-hosting MathJax inside the extension instead of using a CDN.

apps/docs/src/content/docs/guides/latex-math.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ If you assemble markdown extensions yourself (without `prosemarkMarkdownSyntaxEx
7676

7777
## How MathJax is loaded
7878

79-
In **`url-import`** mode (the default), this package sets `window.MathJax` with `skipStartupTypeset: true` and loader paths, then dynamically imports the startup bundle. Do not set conflicting `tex` / `svg` / `chtml` options on `window.MathJax` yourself before that runs.
79+
In **`url-import`** mode (the default), this package sets `window.MathJax` with `startup.typeset: false` and loader paths, then dynamically imports the startup bundle. Do not set conflicting `tex` / `svg` / `chtml` options on `window.MathJax` yourself before that runs.
8080

8181
### Runtime URL — `mathJaxLoadMode: 'url-import'` (default)
8282

@@ -113,6 +113,27 @@ import 'mathjax/tex-svg.js';
113113
}),
114114
```
115115

116+
**Accessibility / speech worker:** the combined startup bundle includes MathJax a11y support and loads **`sre/speech-worker.js` as a web worker** at runtime. Your bundler typically only ships the main JS file, so the worker is missing unless you also copy `sre/` and configure MathJax’s loader paths, or use **`url-import`** with a self-hosted `mathjax/` folder (see [`@prosemark/latex/vite-plugin-mathjax`](https://www.npmjs.com/package/@prosemark/latex) on npm).
117+
118+
If you do not need speech or enrichment and want to avoid shipping the `sre/` worker, configure `window.MathJax` **before** importing MathJax:
119+
120+
```javascript
121+
window.MathJax = {
122+
startup: {
123+
typeset: false,
124+
},
125+
options: {
126+
enableSpeech: false,
127+
enableBraille: false,
128+
enableEnrichment: false,
129+
menuOptions: {
130+
settings: { enrich: false, speech: false, braille: false },
131+
},
132+
},
133+
};
134+
import 'mathjax/tex-svg.js';
135+
```
136+
116137
Use one load mode per page (`url-import` or `static-import`, not both).
117138

118139
## Block vs inline

apps/vscode-extensions/core/src/sub-extensions/core.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ export class Core implements SubExtension<
249249
export function createCore(
250250
extensionUri: vscode.Uri,
251251
): SubExtensionCallback<typeof extId, unknown, unknown> {
252-
return (document, callProcAndForget, _callProcWithReturnValue) => {
252+
return ({ document, callProcAndForget }) => {
253253
return new Core(extensionUri, document, callProcAndForget);
254254
};
255255
}

apps/vscode-extensions/core/src/sub-extensions/word-count-status-bar-item.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export const createWordCountStatusBarItem: SubExtensionCallback<
6767
typeof extId,
6868
Record<string, never>,
6969
WordCountVSCodeProcs
70-
> = (document) => {
70+
> = ({ document }) => {
7171
return new WordCountStatusBarItem(document);
7272
};
7373

apps/vscode-extensions/cspell-integration/src/sub-extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ export function createCSpellIntegration(
151151
extensionUri: vscode.Uri,
152152
cSpellApi: CSpell.ExtensionApi,
153153
): SubExtensionCallback<typeof extId, WebviewProcMap, VSCodeExtensionProcMap> {
154-
return (document, callProcAndForget, callProcWithReturnValue) => {
154+
return ({ document, callProcAndForget, callProcWithReturnValue }) => {
155155
return new CSpellIntegration(
156156
extensionUri,
157157
cSpellApi,

apps/vscode-extensions/latex-integration/README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,35 @@ Please report bugs on the [GitHub issues page](https://github.com/jsimonrichard/
2424

2525
## Developing this extension
2626

27-
After `bun install`, run `bun run build`. **Vite** produces `dist/webview/webview.js` with MathJax SVG output inlined into that bundle (see `src/webview/main.ts`). Bump the **`mathjax`** dependency when you want a different MathJax version.
27+
After `bun install`, run `bun run build`. **Vite** produces `dist/webview/webview.js` and copies `tex-svg.js` plus `sre/` from the **`mathjax`** npm package into `dist/webview/mathjax/` via `@prosemark/latex/vite-plugin-mathjax`. The webview loads MathJax with `url-import` from that folder. Bump the **`mathjax`** dependency when you want a different MathJax version.
28+
29+
### MathJax load modes
30+
31+
This extension uses **`url-import`**: the extension host passes a webview URL for `dist/webview/mathjax/`, and the webview dynamically imports `tex-svg.js` from there. That keeps `webview.js` small and lets MathJax load `sre/speech-worker.js` as a separate file (copied by the Vite plugin).
32+
33+
If you switch to **`static-import`** (`import 'mathjax/tex-svg.js'` bundled into `webview.js`), note that the combined `tex-svg` startup includes MathJax **a11y** support. It tries to load **`sre/speech-worker.js` as a web worker** at runtime. A bundler usually only emits your main bundle, so the worker is missing unless you handle it explicitly.
34+
35+
Pick one approach:
36+
37+
1. **Disable a11y** (simplest with `static-import` when you are not copying `sre/`) — set options on `window.MathJax` **before** the static import:
38+
39+
```ts
40+
window.MathJax = {
41+
startup: {
42+
typeset: false,
43+
},
44+
options: {
45+
enableSpeech: false,
46+
enableBraille: false,
47+
enableEnrichment: false,
48+
menuOptions: {
49+
settings: { enrich: false, speech: false, braille: false },
50+
},
51+
},
52+
};
53+
import 'mathjax/tex-svg.js';
54+
```
55+
56+
2. **Keep a11y** — copy `sre/` from the `mathjax` npm package next to where `tex-svg.js` is served, and point MathJax at that root (for example with `preconfigureMathJaxLoader` and `loader.paths.mathjax`, or `@prosemark/latex/vite-plugin-mathjax` with `url-import`). The worker cannot be inlined into an IIFE the way the main startup script can.
57+
58+
The shipped extension uses **url-import + copied `sre/`** so math renders without bundling ~1.8 MB of MathJax into `webview.js`.
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
/** VS Code extension host: no procedures exposed to the webview for LaTeX. */
22
export type VSCodeExtensionProcMap = Record<string, never>;
33

4+
export interface LatexSetupConfig {
5+
mathJaxPackageUrl: string;
6+
}
7+
48
export interface WebviewProcMap {
5-
setup: () => Promise<void>;
9+
setup: (config: LatexSetupConfig) => Promise<void>;
610
}
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
11
declare module '*.css';
2-
3-
declare module 'mathjax/tex-svg.js';

0 commit comments

Comments
 (0)