Skip to content

Comments

fix: use globalThis instead of window for non-browser compatibility#150

Merged
fasterthanlime merged 2 commits intomainfrom
fix-148-window-not-defined
Feb 9, 2026
Merged

fix: use globalThis instead of window for non-browser compatibility#150
fasterthanlime merged 2 commits intomainfrom
fix-148-window-not-defined

Conversation

@fasterthanlime
Copy link
Collaborator

@fasterthanlime fasterthanlime commented Feb 9, 2026

Summary

  • Replace window with globalThis in the ESM loader so arboriumHost works in Node.js, Deno, and workers (not just browsers)
  • Add registerGrammar() API that lets users pre-load grammar modules, bypassing CDN/dynamic-import resolution entirely

registerGrammar usage

// Deno
import * as pythonGrammar from "npm:@arborium/python";
import { readFile } from "node:fs/promises";
const wasm = await readFile("node_modules/@arborium/python/grammar_bg.wasm");
const grammar = await registerGrammar(pythonGrammar, wasm);
const html = await grammar.highlight("print('hello')");

Test plan

  • Verify browser behavior unchanged (globalThis === window in browsers)
  • Verify registerGrammar works in Deno with npm: specifiers

Fixes #148
Fixes #149

…148)

Replace all references to `window.arboriumHost` with `globalThis.arboriumHost`
so the host interface works in Node.js, SSR, and Web Worker environments
where `window` is not defined.
Allows pre-loading grammar modules without CDN resolution,
fixing grammar loading in non-browser environments.

Fixes #149
@fasterthanlime fasterthanlime added this pull request to the merge queue Feb 9, 2026
Merged via the queue into main with commit 8a61187 Feb 9, 2026
19 checks passed
@fasterthanlime fasterthanlime deleted the fix-148-window-not-defined branch February 9, 2026 18:41
@qt-dork
Copy link

qt-dork commented Feb 9, 2026

Sorry to bother, but was this PR written using LLMs? There doesn’t seem to be any sort of indication in the repo of agent usage, and it was not disclosed anywhere.

@fasterthanlime
Copy link
Collaborator Author

Sorry to bother, but was this PR written using LLMs? There doesn’t seem to be any sort of indication in the repo of agent usage, and it was not disclosed anywhere.

Yes, large parts of arborium were co-developed with LLMs.

Adding to my TODO to add disclosures to, uh, too many projects. I know some folks want to stay away completely — where would you expect such a disclosure? Bottom of README ok?

@fasterthanlime
Copy link
Collaborator Author

Added: 2a3bb06

@flying-sheep
Copy link
Contributor

Btw.: registerGrammar seems to be strictly an alternative solution to using the resolveJs and resolveWasm functions I added in #97, so that API was not really necessary I think.

Yes, large parts of arborium were co-developed with LLMs.

I figured, you’re usually less “move fast and break things”. I’m not complaining, since

  1. you don’t owe me anything and are voluntarily building a thing that has value for me, thank you!
  2. even if I paid you (more than the patreon membership), there would be nothing to complain, since lockfiles exist, you’re super responsive, and fix things quickly and add features I wanted quickly

I think the only think I could ask for is tests to avoid regressions like #122, which I think also exist now.

@bakkot
Copy link

bakkot commented Feb 15, 2026

The snippet above doesn't work in Deno, because:

  • Deno doesn't have node_modules
  • you also need to pass a hostUrl specifying the local install as a file:// url, or else it will still try to import() from the CDN, which won't work because you can't import from an https url in Deno (or Node)

Also it still won't work on Node because wasm-bindgen uses fetch internally, which fails because Node (unlike Deno) will not let you fetch from a file:// url.

Here's a version which works in Deno:

import { registerGrammar } from '@arborium/arborium';
import * as pythonGrammar from '@arborium/python';
import { readFile } from 'node:fs/promises';
import { dirname } from 'node:path';
const py = import.meta.resolve('@arborium/python/grammar_bg.wasm');
const hostUrl = dirname(import.meta.resolve('@arborium/arborium'));
const wasm = await readFile(new URL(py));
const grammar = await registerGrammar(pythonGrammar, wasm, { hostUrl });
const html = await grammar.highlight("print('hello')");
console.log({ html });

Making this work in Node would require some additional work, probably most straightforwardly by having resolveJs/resolveWasm also apply to loading the host (kinda weird it doesn't).

@flying-sheep
Copy link
Contributor

flying-sheep commented Feb 15, 2026

As said, resolveJs and resolveWasm will also work in any environment, as you can 100% customize how to load the files.

@bakkot
Copy link

bakkot commented Feb 15, 2026

@flying-sheep As I said, resolveJs and resolveWasm do not govern how to load the host, so no, they are not sufficient to get it working in Node, at least as far as I can tell. Try it yourself.

@flying-sheep
Copy link
Contributor

Oof, sorry! this time I was the one who didn’t read properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deno: Cannot load grammars. Likely due to https import? Cannot use the esm module in node. "window is not defined"

4 participants