Skip to content

Commit 6132b2d

Browse files
romgrkclaude
andcommitted
refactor: use module.registerHooks for the gi: ESM loader
Switch the `gi:` scheme loader from `module.register` (async hooks on a separate loader thread, loaded by URL) to `module.registerHooks` (synchronous, in-thread hooks passed directly as functions). Since registerHooks takes the hook functions rather than a module URL, the whole implementation now lives in register.mjs and the separate hooks.mjs file (plus its `./hooks` package export, which was unused) is removed. The resolve and load hooks are now synchronous, as registerHooks requires; the synthetic `gi.require` module emitted by `load` is unchanged. Bumps the minimum from Node >= 20.6 (module.register) to Node >= 22.15 (module.registerHooks); node-gtk v4 already targets Node 22/24/26. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent d49dc1f commit 6132b2d

4 files changed

Lines changed: 48 additions & 54 deletions

File tree

doc/importing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ package by name:
3838
import gi, { registerClass } from 'node-gtk'
3939
```
4040

41-
The `gi:` hooks require **Node ≥ 20.6** (for `module.register`).
41+
The `gi:` hooks require **Node ≥ 22.15** (for `module.registerHooks`).
4242

4343
### The loop integration starts automatically
4444

lib/esm/hooks.mjs

Lines changed: 0 additions & 49 deletions
This file was deleted.

lib/esm/register.mjs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,58 @@
44
* Usage: node --import node-gtk/register app.mjs
55
*
66
* Then, in app.mjs:
7-
* import Gtk from 'gi:Gtk-4.0'
7+
* import Gtk from 'gi:Gtk-4.0' // `gi:Name-Version`, or `gi:Name` for the latest
88
* const { Box, Label } = Gtk
99
*
10+
* `import Gtk from 'gi:Gtk-4.0'` is equivalent to `gi.require('Gtk', '4.0')`: the
11+
* default export is the namespace object, so read members off it.
12+
*
13+
* The hooks are synchronous and run in-thread (module.registerHooks), so they must
14+
* not return promises. `load` does no native work itself: it emits a tiny synthetic
15+
* ES module whose body calls `gi.require` when that module is evaluated. Requires
16+
* Node >= 22.15 (module.registerHooks).
17+
*
1018
* Note: hooks only affect imports evaluated *after* registration. To use a static
1119
* `import ... from 'gi:...'` in your entry module, register via the `--import`
1220
* flag above (not a programmatic `import 'node-gtk/register'` in that same file).
1321
*/
1422

15-
import { register } from 'node:module'
23+
import { registerHooks } from 'node:module'
24+
25+
const PREFIX = 'gi:'
26+
27+
/* Absolute file:// URL to lib/index.js, embedded into the generated source. The
28+
* synthetic module's parent URL is the schemeless `gi:` URL, which has no
29+
* filesystem base, so a bare `import 'node-gtk'` could not be resolved from it —
30+
* the absolute URL sidesteps resolution entirely. */
31+
const INDEX_URL = new URL('../index.js', import.meta.url).href
32+
33+
function resolve(specifier, context, nextResolve) {
34+
if (specifier.startsWith(PREFIX))
35+
return { url: specifier, shortCircuit: true }
36+
return nextResolve(specifier, context)
37+
}
38+
39+
function load(url, context, nextLoad) {
40+
if (!url.startsWith(PREFIX))
41+
return nextLoad(url, context)
42+
43+
// `gi:Gtk-4.0` -> ('Gtk', '4.0'); `gi:Adw-1` -> ('Adw', '1'); `gi:cairo` -> ('cairo', null).
44+
// Split on the first '-' only: GI namespace names never contain '-', versions may.
45+
const spec = url.slice(PREFIX.length)
46+
const dash = spec.indexOf('-')
47+
const name = dash === -1 ? spec : spec.slice(0, dash)
48+
const version = dash === -1 ? null : spec.slice(dash + 1)
49+
50+
const call = version === null
51+
? `gi.require(${JSON.stringify(name)})`
52+
: `gi.require(${JSON.stringify(name)}, ${JSON.stringify(version)})`
53+
54+
const source =
55+
`import gi from ${JSON.stringify(INDEX_URL)};\n` +
56+
`export default ${call};\n`
57+
58+
return { format: 'module', shortCircuit: true, source }
59+
}
1660

17-
register(new URL('./hooks.mjs', import.meta.url))
61+
registerHooks({ resolve, load })

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
"require": "./lib/index.js"
1010
},
1111
"./register": "./lib/esm/register.mjs",
12-
"./hooks": "./lib/esm/hooks.mjs",
1312
"./styles": {
1413
"types": "./lib/styles.d.ts",
1514
"default": "./lib/styles.js"

0 commit comments

Comments
 (0)