@gjsify/rolldown-plugin-gjsify 0.51.1 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/lib/app/browser.js +28 -0
- package/lib/app/gjs.js +14 -2
- package/lib/app/nativescript.js +15 -3
- package/lib/app/node.d.ts +1 -1
- package/lib/app/node.js +26 -10
- package/lib/index.d.ts +4 -2
- package/lib/index.js +4 -2
- package/lib/plugins/console-assign.d.ts +13 -0
- package/lib/plugins/console-assign.js +125 -0
- package/lib/plugins/css-as-string.js +126 -44
- package/lib/plugins/gi-renderer.d.ts +1 -1
- package/lib/plugins/gi-renderer.js +1 -1
- package/lib/plugins/gi-runtime-paths.js +5 -2
- package/lib/plugins/napi-node-addon.d.ts +48 -4
- package/lib/plugins/napi-node-addon.js +261 -85
- package/lib/plugins/node-native-external.d.ts +20 -0
- package/lib/plugins/node-native-external.js +145 -0
- package/lib/plugins/platform-resolve.d.ts +95 -5
- package/lib/plugins/platform-resolve.js +132 -11
- package/lib/plugins/rewrite-node-modules-paths.d.ts +18 -1
- package/lib/plugins/rewrite-node-modules-paths.js +181 -25
- package/lib/plugins/unresolved-workspace-import.js +89 -68
- package/lib/shims/addon-resolve.d.ts +19 -0
- package/lib/shims/addon-resolve.js +193 -0
- package/lib/utils/addon-platform.d.ts +23 -0
- package/lib/utils/addon-platform.js +50 -0
- package/lib/utils/auto-globals.d.ts +6 -0
- package/lib/utils/auto-globals.js +92 -15
- package/lib/utils/declare-build-input.d.ts +13 -0
- package/lib/utils/declare-build-input.js +37 -0
- package/lib/utils/detect-free-globals.d.ts +3 -0
- package/lib/utils/detect-free-globals.js +1 -1
- package/lib/utils/entry-wrapper.js +6 -1
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.js +1 -0
- package/lib/utils/inline-static-reads.d.ts +15 -1
- package/lib/utils/inline-static-reads.js +16 -8
- package/lib/utils/runtime.js +1 -1
- package/lib/utils/scan-globals.d.ts +2 -2
- package/lib/utils/scan-globals.js +20 -14
- package/lib/utils/zip-path.d.ts +9 -0
- package/lib/utils/zip-path.js +12 -0
- package/package.json +13 -9
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// `@import`s are resolved + inlined in JS first (`flattenCssImports`, so bare
|
|
18
18
|
// node_modules specifiers work — the native `bundle()` FileProvider can't walk
|
|
19
19
|
// node_modules), then the flattened CSS goes through the native `transform()`
|
|
20
|
-
// for lowering. Both use the same
|
|
20
|
+
// for lowering. Both use the same resolver. The `--app gjs`
|
|
21
21
|
// orchestrator passes `targets: { firefox: 60 << 16 }` so nesting + modern
|
|
22
22
|
// selectors get flattened to GTK4-CSS-engine-compatible output. Targeting is
|
|
23
23
|
// opt-in — a missing `targets` keeps the source pristine.
|
|
@@ -43,7 +43,10 @@ import { createRequire } from 'node:module';
|
|
|
43
43
|
import { dirname, isAbsolute, resolve as resolvePath } from 'node:path';
|
|
44
44
|
import { pathToFileURL } from 'node:url';
|
|
45
45
|
import { isGjs } from '../utils/runtime.js';
|
|
46
|
+
import { declareBuildInput } from '../utils/declare-build-input.js';
|
|
46
47
|
let _bundlerPromise = null;
|
|
48
|
+
/** Why the native bridge's library would not open, when `tryLoadNativeBundler()` measured it. */
|
|
49
|
+
let _nativeLoadError = null;
|
|
47
50
|
async function pickBundler() {
|
|
48
51
|
const forced = globalThis.process?.env
|
|
49
52
|
?.GJSIFY_CSS_BACKEND;
|
|
@@ -52,11 +55,22 @@ async function pickBundler() {
|
|
|
52
55
|
if (forced === 'native') {
|
|
53
56
|
const native = await tryLoadNativeBundler();
|
|
54
57
|
if (!native)
|
|
55
|
-
throw new Error('GJSIFY_CSS_BACKEND=native but @gjsify/lightningcss-native is not loadable'
|
|
58
|
+
throw new Error('GJSIFY_CSS_BACKEND=native but @gjsify/lightningcss-native is not loadable' +
|
|
59
|
+
(_nativeLoadError ? `\n${_nativeLoadError.message}` : ''));
|
|
56
60
|
return native;
|
|
57
61
|
}
|
|
58
62
|
const native = await tryLoadNativeBundler();
|
|
59
|
-
|
|
63
|
+
if (native)
|
|
64
|
+
return native;
|
|
65
|
+
// The npm fallback is the right answer, and it is silent on purpose — a
|
|
66
|
+
// missing optional backend is not an error. But if we MEASURED why the
|
|
67
|
+
// native one would not load, that measurement is the only place the user
|
|
68
|
+
// ever hears it, so it goes to the same `console.debug` channel
|
|
69
|
+
// `loadOptionalNativeModule` uses rather than into nothing. A backend that
|
|
70
|
+
// cannot load is the reason someone reaches for this flag.
|
|
71
|
+
if (_nativeLoadError)
|
|
72
|
+
console.debug(_nativeLoadError.message);
|
|
73
|
+
return loadNpmBundler();
|
|
60
74
|
}
|
|
61
75
|
async function tryLoadNativeBundler() {
|
|
62
76
|
// The native bridge only exists under GJS — `imports.gi` marker. Skip
|
|
@@ -79,14 +93,42 @@ async function tryLoadNativeBundler() {
|
|
|
79
93
|
const mod = (await import(/* @vite-ignore */ pathToFileURL(resolved).href));
|
|
80
94
|
if (!mod.hasNativeLightningcss())
|
|
81
95
|
return null;
|
|
82
|
-
|
|
96
|
+
// The typelib resolved; its library opens at the first class access. Open
|
|
97
|
+
// it now, beside that typelib: this module cannot leave it to the wrapper,
|
|
98
|
+
// whose `lib/` is imported by file URL where GJS resolves no bare
|
|
99
|
+
// specifier. A library that will not load then names its missing
|
|
100
|
+
// dependency and the npm fallback runs, instead of the nameless
|
|
101
|
+
// "Unsupported type void" inside `transform()`.
|
|
102
|
+
// The same resolve-then-import dance as above, for the probe itself: by
|
|
103
|
+
// the time a CSS transform asks for the native bundler, utils' `lib/esm`
|
|
104
|
+
// is long built, so the lazy edge costs nothing and the static one would
|
|
105
|
+
// have cost a bootable CLI. `./native-library` rather than `./core`:
|
|
106
|
+
// `core` re-exports `main-loop`, whose module-level singleton would then
|
|
107
|
+
// exist twice in a process that already has it inlined in the GJS bundle.
|
|
108
|
+
//
|
|
109
|
+
// Its own `try` because the outer one cannot tell this apart from "there
|
|
110
|
+
// is no native backend" — and reporting nothing is the one outcome this
|
|
111
|
+
// file must not produce: a missing measurement reads as a passing one.
|
|
112
|
+
let openNativeLibrary;
|
|
113
|
+
try {
|
|
114
|
+
const utilsHref = pathToFileURL(createRequire(import.meta.url).resolve('@gjsify/utils/native-library')).href;
|
|
115
|
+
({ openNativeLibrary } = (await import(/* @vite-ignore */ utilsHref)));
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
_nativeLoadError = err instanceof Error ? err : new Error(String(err));
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
_nativeLoadError = openNativeLibrary('GjsifyLightningcss');
|
|
122
|
+
if (_nativeLoadError)
|
|
123
|
+
return null;
|
|
124
|
+
return async (filename, targets, declare) => {
|
|
83
125
|
// The native `@gjsify/lightningcss-native` `bundle()` resolves
|
|
84
126
|
// `@import` chains through lightningcss's filesystem-backed
|
|
85
127
|
// FileProvider, which walks relative + absolute paths but NOT
|
|
86
128
|
// bare node_modules specifiers (`@import "@scope/pkg/x.css"`) —
|
|
87
129
|
// a JS resolver callback can't cross the GI/Rust boundary. So we
|
|
88
130
|
// do `@import` resolution in JS first, using the SAME
|
|
89
|
-
//
|
|
131
|
+
// resolver the npm `bundleAsync` path uses (npm-package
|
|
90
132
|
// + `exports`-map aware), and hand the fully-flattened CSS to the
|
|
91
133
|
// native `transform()` for the GTK4 nesting/modern-syntax lowering
|
|
92
134
|
// (`targets`). The native shim accepts a browserslist string; the
|
|
@@ -94,7 +136,7 @@ async function tryLoadNativeBundler() {
|
|
|
94
136
|
// (`firefox: 60 << 16` etc), so convert per browser key.
|
|
95
137
|
let flattened;
|
|
96
138
|
try {
|
|
97
|
-
flattened = await flattenCssImports(filename);
|
|
139
|
+
flattened = await flattenCssImports(filename, declare);
|
|
98
140
|
}
|
|
99
141
|
catch (err) {
|
|
100
142
|
// The native rolldown engine flattens a thrown plugin error to
|
|
@@ -147,13 +189,16 @@ async function loadNpmBundler() {
|
|
|
147
189
|
// `dependency` of this package, so the runtime resolve finds it.
|
|
148
190
|
const specifier = 'lightningcss';
|
|
149
191
|
const { bundleAsync } = (await import(/* @vite-ignore */ specifier));
|
|
150
|
-
return async (filename, targets) => {
|
|
192
|
+
return async (filename, targets, declare) => {
|
|
151
193
|
const result = await bundleAsync({
|
|
152
194
|
filename,
|
|
153
195
|
targets,
|
|
154
196
|
minify: false,
|
|
155
197
|
errorRecovery: true,
|
|
156
|
-
|
|
198
|
+
// Per call, not a module singleton: the resolver is where every
|
|
199
|
+
// `@import` target is resolved, so it is where the declaration has
|
|
200
|
+
// to happen — and it must carry THIS load's sink.
|
|
201
|
+
resolver: createCssBundleResolver(declare),
|
|
157
202
|
});
|
|
158
203
|
return { code: result.code };
|
|
159
204
|
};
|
|
@@ -185,35 +230,50 @@ const ASSET_REF_RE = /\.(woff2?|ttf|otf|eot|svg|png|jpe?g|gif|webp|avif|ico)(\?|
|
|
|
185
230
|
function isAssetReference(specifier) {
|
|
186
231
|
return /^(data|https?|file):/i.test(specifier) || ASSET_REF_RE.test(specifier);
|
|
187
232
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
// Bare specifier — walk node_modules and honor package.json exports.
|
|
196
|
-
// `createRequire` takes a file URL or path; passing the importer
|
|
197
|
-
// lets it scope its node_modules walk to the right starting point.
|
|
198
|
-
const req = createRequire(pathToFileURL(from).href);
|
|
199
|
-
try {
|
|
200
|
-
return req.resolve(specifier);
|
|
201
|
-
}
|
|
202
|
-
catch (err) {
|
|
203
|
-
// Not an installed module. If it's a `url()`/asset reference,
|
|
204
|
-
// leave it verbatim so lightningcss keeps the `@font-face` /
|
|
205
|
-
// `url()` rule intact (the consumer serves the asset) instead of
|
|
206
|
-
// crashing the build. A genuine unresolvable CSS `@import`
|
|
207
|
-
// re-throws with actionable context so the missing dependency
|
|
208
|
-
// surfaces clearly on both backends (npm and native).
|
|
209
|
-
if (isAssetReference(specifier))
|
|
233
|
+
function createCssBundleResolver(declare) {
|
|
234
|
+
return {
|
|
235
|
+
resolve(specifier, from) {
|
|
236
|
+
// A relative `@import` is resolved here, but lightningcss reads the
|
|
237
|
+
// target itself — so the resolver is the only place its name is known.
|
|
238
|
+
if (isAbsolute(specifier)) {
|
|
239
|
+
declare(stripQuery(specifier));
|
|
210
240
|
return specifier;
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
241
|
+
}
|
|
242
|
+
if (specifier.startsWith('./') || specifier.startsWith('../')) {
|
|
243
|
+
const resolved = resolvePath(dirname(from), specifier);
|
|
244
|
+
declare(resolved);
|
|
245
|
+
return resolved;
|
|
246
|
+
}
|
|
247
|
+
// Bare specifier — walk node_modules and honor package.json exports.
|
|
248
|
+
// `createRequire` takes a file URL or path; passing the importer
|
|
249
|
+
// lets it scope its node_modules walk to the right starting point.
|
|
250
|
+
const req = createRequire(pathToFileURL(from).href);
|
|
251
|
+
try {
|
|
252
|
+
const resolved = req.resolve(specifier);
|
|
253
|
+
declare(resolved);
|
|
254
|
+
return resolved;
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
// Not an installed module. If it's a `url()`/asset reference,
|
|
258
|
+
// leave it verbatim so lightningcss keeps the `@font-face` /
|
|
259
|
+
// `url()` rule intact (the consumer serves the asset) instead of
|
|
260
|
+
// crashing the build. A genuine unresolvable CSS `@import`
|
|
261
|
+
// re-throws with actionable context so the missing dependency
|
|
262
|
+
// surfaces clearly on both backends (npm and native).
|
|
263
|
+
if (isAssetReference(specifier))
|
|
264
|
+
return specifier;
|
|
265
|
+
throw new Error(`cannot resolve @import "${specifier}" from ${from} (${err.message}). ` +
|
|
266
|
+
'If it is a workspace/npm package, ensure it is installed and exposes the CSS ' +
|
|
267
|
+
'file via its package.json "exports".');
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/** `@scope/pkg/x.css?v=2` is a cache-busting convention; the file is the part before it. */
|
|
273
|
+
function stripQuery(specifier) {
|
|
274
|
+
const cut = specifier.search(/[?#]/);
|
|
275
|
+
return cut === -1 ? specifier : specifier.slice(0, cut);
|
|
276
|
+
}
|
|
217
277
|
// Matches a CSS `@import` at-rule and captures the specifier + any trailing
|
|
218
278
|
// condition tokens (media query / `layer()` / `supports()`) before the `;`.
|
|
219
279
|
// Covers `@import "x";`, `@import 'x';`, and `@import url("x")` / `url(x)`.
|
|
@@ -236,7 +296,7 @@ async function replaceAllAsync(source, re, fn) {
|
|
|
236
296
|
}
|
|
237
297
|
/**
|
|
238
298
|
* Recursively resolve + inline every bundleable `@import` in `entry`, using the
|
|
239
|
-
* same
|
|
299
|
+
* same resolver the npm `bundleAsync` path uses. Returns a
|
|
240
300
|
* single flattened CSS string with no bundleable `@import` statements left — the
|
|
241
301
|
* native `transform()` then applies GTK4 nesting/target lowering.
|
|
242
302
|
*
|
|
@@ -249,20 +309,26 @@ async function replaceAllAsync(source, re, fn) {
|
|
|
249
309
|
* URL) are kept verbatim (the resolver leaves them alone), matching the npm
|
|
250
310
|
* path. A cycle inlines each file at most once.
|
|
251
311
|
*/
|
|
252
|
-
async function flattenCssImports(entry) {
|
|
312
|
+
async function flattenCssImports(entry, declare) {
|
|
253
313
|
const seen = new Set();
|
|
314
|
+
const resolver = createCssBundleResolver(declare);
|
|
254
315
|
const inline = async (file, isRoot) => {
|
|
255
|
-
const abs = isAbsolute(file) ? file : resolvePath(file);
|
|
316
|
+
const abs = isAbsolute(file) ? stripQuery(file) : resolvePath(file);
|
|
256
317
|
if (seen.has(abs))
|
|
257
318
|
return ''; // @import cycle — inline once
|
|
258
319
|
seen.add(abs);
|
|
320
|
+
// Declared at the READ, not at the resolution: the root stylesheet, and
|
|
321
|
+
// any import a form the regex does not match, are still inputs of the
|
|
322
|
+
// output — and a resolution declares nothing if lightningcss then
|
|
323
|
+
// decides not to read it.
|
|
324
|
+
declare(abs);
|
|
259
325
|
let source = await readFile(abs, 'utf8');
|
|
260
326
|
// `@charset` is only valid as the very first token of a stylesheet;
|
|
261
327
|
// an inlined sub-file's `@charset` mid-stream would be invalid CSS.
|
|
262
328
|
if (!isRoot)
|
|
263
329
|
source = source.replace(/@charset[^;]*;/gi, '');
|
|
264
330
|
return replaceAllAsync(source, IMPORT_RE, async (match, spec, condition) => {
|
|
265
|
-
const resolved =
|
|
331
|
+
const resolved = resolver.resolve(spec, abs);
|
|
266
332
|
// Asset-reference `@import` (rare): resolver returns it verbatim —
|
|
267
333
|
// keep the at-rule intact.
|
|
268
334
|
if (resolved === spec)
|
|
@@ -310,13 +376,29 @@ export function cssAsStringPlugin(options = {}) {
|
|
|
310
376
|
// flattens nesting, so no further lightningcss lowering is needed).
|
|
311
377
|
filter: { id: /\.(css|s[ac]ss)$/ },
|
|
312
378
|
async handler(id) {
|
|
379
|
+
// Every file the backends read on our behalf, declared through
|
|
380
|
+
// the standard contract — `gjsify test`'s freshness check reads
|
|
381
|
+
// this list, and it is the only account of a stylesheet's
|
|
382
|
+
// `@import`/`@use` chain, which no module graph names. Why the
|
|
383
|
+
// call is feature-detected: `utils/declare-build-input.ts`.
|
|
384
|
+
const declare = (abs) => declareBuildInput(this, abs);
|
|
385
|
+
// The entry itself is read here in every branch, and a Sass
|
|
386
|
+
// file's PARTIALS are not: dart-sass resolves a relative
|
|
387
|
+
// `@use "./x"` through its own filesystem importer before any
|
|
388
|
+
// custom importer is consulted (measured 2026-09-29 with
|
|
389
|
+
// dart-sass 1.101: `importers[].findFileUrl` and
|
|
390
|
+
// `canonicalize` are called zero times for a relative load, and
|
|
391
|
+
// for a bare one only on the way to being declined, so the path
|
|
392
|
+
// is never ours to declare). Tracking that:
|
|
393
|
+
// status/open-todos/bundler.md.
|
|
394
|
+
declare(stripQuery(id));
|
|
313
395
|
let code;
|
|
314
396
|
if (/\.s[ac]ss$/.test(id)) {
|
|
315
397
|
code = await compileSass(id);
|
|
316
398
|
}
|
|
317
399
|
else {
|
|
318
400
|
code = bundle
|
|
319
|
-
? new TextDecoder('utf-8').decode(await loadAndBundleCss(id, targets))
|
|
401
|
+
? new TextDecoder('utf-8').decode(await loadAndBundleCss(id, targets, declare))
|
|
320
402
|
: await readFile(id, 'utf8');
|
|
321
403
|
}
|
|
322
404
|
return {
|
|
@@ -339,7 +421,7 @@ async function compileSass(filename) {
|
|
|
339
421
|
// `import './x.scss'` fails with UNLOADABLE_DEPENDENCY. Resolving it to a file
|
|
340
422
|
// first (`tryLoadNativeBundler`'s trick) does not help: `sass.default.js` then
|
|
341
423
|
// imports a bare `immutable`. Only INLINING dart-sass works, and 3.6 MB minified
|
|
342
|
-
// onto a 6.6 MB CLI bundle is a carrier-package decision — status/open-todos.md
|
|
424
|
+
// onto a 6.6 MB CLI bundle is a carrier-package decision — status/open-todos/README.md
|
|
343
425
|
// (#1053). dart-sass DOES run under GJS: `adwaita-web`'s `build:scss` does.
|
|
344
426
|
_sassPromise = import(/* @vite-ignore */ 'sass');
|
|
345
427
|
}
|
|
@@ -352,10 +434,10 @@ async function compileSass(filename) {
|
|
|
352
434
|
`Is the \`sass\` package installed? (${err.message})`);
|
|
353
435
|
}
|
|
354
436
|
}
|
|
355
|
-
async function loadAndBundleCss(filename, targets) {
|
|
437
|
+
async function loadAndBundleCss(filename, targets, declare) {
|
|
356
438
|
if (!_bundlerPromise)
|
|
357
439
|
_bundlerPromise = pickBundler();
|
|
358
440
|
const bundler = await _bundlerPromise;
|
|
359
|
-
const { code } = await bundler(filename, targets);
|
|
441
|
+
const { code } = await bundler(filename, targets, declare);
|
|
360
442
|
return code;
|
|
361
443
|
}
|
|
@@ -29,7 +29,7 @@ export interface GiRendererOptions {
|
|
|
29
29
|
* passes `--gi-renderer`, so the arm never composes there and this text cannot reach them
|
|
30
30
|
* — measured, nothing under `tests/` names the flag but `gi-renderer-arms` itself. Making
|
|
31
31
|
* that suite's two assertions import-shaped would retire this rule outright; the argument,
|
|
32
|
-
* the other twelve sites and the retirement condition are in `status/open-todos.md`.
|
|
32
|
+
* the other twelve sites and the retirement condition are in `status/open-todos/README.md`.
|
|
33
33
|
*/
|
|
34
34
|
export declare function giRendererShimSource(options: GiRendererOptions, namespace: string, version: string): string;
|
|
35
35
|
export declare function giRendererPlugin(options: GiRendererOptions): Plugin;
|
|
@@ -90,7 +90,7 @@ const GI_RENDERER_VIRTUAL_PREFIX = `${GJSIFY_VIRTUAL_PREFIX}gi-renderer:`;
|
|
|
90
90
|
* passes `--gi-renderer`, so the arm never composes there and this text cannot reach them
|
|
91
91
|
* — measured, nothing under `tests/` names the flag but `gi-renderer-arms` itself. Making
|
|
92
92
|
* that suite's two assertions import-shaped would retire this rule outright; the argument,
|
|
93
|
-
* the other twelve sites and the retirement condition are in `status/open-todos.md`.
|
|
93
|
+
* the other twelve sites and the retirement condition are in `status/open-todos/README.md`.
|
|
94
94
|
*/
|
|
95
95
|
export function giRendererShimSource(options, namespace, version) {
|
|
96
96
|
return (`import { ${namespace} as namespace } from ${JSON.stringify(options.renderer)};\n` +
|
|
@@ -9,8 +9,11 @@
|
|
|
9
9
|
// e2e): a banner is the entry chunk's BODY and ESM evaluates imports first, so a
|
|
10
10
|
// STATIC `import … from 'gi://Ns'` has already loaded its typelib before this runs.
|
|
11
11
|
// What is left is what loads LATER — `await import('gi://Soup')` and the other
|
|
12
|
-
// optional namespaces.
|
|
13
|
-
//
|
|
12
|
+
// optional namespaces. Confirmed on darwin-arm64 in the same shape (macOS 27 / M4 /
|
|
13
|
+
// Homebrew, the bundle loading Gtk through `await import` and failing through a
|
|
14
|
+
// static one). Reaching the static ones changes how a bundle acquires GI namespaces
|
|
15
|
+
// at all: ADR 0085 decides to lower them here, in `renderChunk`, to awaited dynamic
|
|
16
|
+
// imports placed after this prologue — proposed, not implemented.
|
|
14
17
|
//
|
|
15
18
|
// TWO KINDS OF DIRECTORY, split by WHOSE FACT each is. `dirs` describe the SHIPPED
|
|
16
19
|
// TREE, so they are baked, relative to the program. `systemProbes` describe the host
|
|
@@ -12,11 +12,49 @@ export interface NapiNodeAddonPluginOptions {
|
|
|
12
12
|
* `@gjsify/napi` is not resolvable in the consumer graph. Default `true`.
|
|
13
13
|
*/
|
|
14
14
|
warnOnMissingNapi?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Is the output an ESM single-file build, i.e. does it carry the
|
|
17
|
+
* bundle-URL banner the run-time resolver anchors on? Default `true`;
|
|
18
|
+
* `app/gjs.ts` passes the same `format === 'esm'` the node-modules path
|
|
19
|
+
* rewriter gates its own runtime resolution on.
|
|
20
|
+
*
|
|
21
|
+
* `false` DECLINES every rewrite, with one warning naming the reason. It is
|
|
22
|
+
* a decline and not the pre-ADR baked path because there is no correct baked
|
|
23
|
+
* path left: the whole point of ADR 0084 is that a path chosen at build time
|
|
24
|
+
* is what made the artifact unusable off the build machine, so emitting one
|
|
25
|
+
* again would reintroduce the defect for a mode that cannot anchor at run
|
|
26
|
+
* time anyway. A `--library cjs` build is a library for a consumer's own
|
|
27
|
+
* toolchain, which resolves its addons itself.
|
|
28
|
+
*/
|
|
29
|
+
runtimeResolve?: boolean;
|
|
15
30
|
}
|
|
16
31
|
/** A native addon package root has no resolvable compiled `.node`. */
|
|
17
32
|
export declare class AddonNotBuiltError extends Error {
|
|
18
33
|
constructor(pkgRoot: string);
|
|
19
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Enumerate every `.node` an addon package ships, keyed by platform, as a
|
|
37
|
+
* `<package>/<subpath>` spec per entry. ADR 0084: the build ENUMERATES, it
|
|
38
|
+
* does not select — the bundle picks the right entry at RUN time from the
|
|
39
|
+
* host it finds itself on.
|
|
40
|
+
*
|
|
41
|
+
* The table has:
|
|
42
|
+
* - One entry per `prebuilds/<tuple>/` directory, keyed by the tuple's
|
|
43
|
+
* platform and EVERY architecture it declares, and per libc variant. Each
|
|
44
|
+
* entry is chosen by {@link selectPrebuildFile} — node-gyp-build's own
|
|
45
|
+
* algorithm, run for a synthetic host of that tuple — so the entry for the
|
|
46
|
+
* build host is exactly the binary Node would load, and a foreign platform's
|
|
47
|
+
* entry is the best one that host could load rather than the best-looking
|
|
48
|
+
* file in the directory.
|
|
49
|
+
* - One entry per `build/Release` and `build/Debug`, keyed by the BUILD host
|
|
50
|
+
* ({@link buildHostTarget}, deliberately not the `npm_config_*` override
|
|
51
|
+
* those files are not built for), overriding the prebuilds entry for the
|
|
52
|
+
* same key: node-gyp-build's order has build/Release winning.
|
|
53
|
+
*
|
|
54
|
+
* Returns an empty record when no `.node` exists anywhere — the caller then
|
|
55
|
+
* throws {@link AddonNotBuiltError} as a build-time gate.
|
|
56
|
+
*/
|
|
57
|
+
export declare function enumerateAddonTargets(pkgRoot: string, pkg: AddonPackageJson): Record<string, string>;
|
|
20
58
|
/**
|
|
21
59
|
* Locate the compiled `.node` for an addon package root, matching node-gyp-build's
|
|
22
60
|
* probe order: `build/Release` → `build/Debug` →
|
|
@@ -28,14 +66,19 @@ export declare function resolveAddonPath(pkgRoot: string, opts?: {
|
|
|
28
66
|
}): string;
|
|
29
67
|
/** Nearest ancestor directory of `importerFile` holding a `package.json`. */
|
|
30
68
|
export declare function nearestPackageRoot(importerFile: string): string | null;
|
|
69
|
+
/**
|
|
70
|
+
* The addon table as a JSON string — the platform-key → `<pkg>/<subpath>`
|
|
71
|
+
* map the runtime resolver (`__gjsifyAddonResolve`) picks from. ADR 0084.
|
|
72
|
+
*/
|
|
73
|
+
type AddonTable = string;
|
|
31
74
|
/** Direct `.node` import → the addon's exports (ESM default). */
|
|
32
|
-
export declare function directNodeShim(
|
|
75
|
+
export declare function directNodeShim(addonTable: AddonTable): string;
|
|
33
76
|
/** `node-gyp-build` replacement — a callable `load(dir)` carrying `.path()`. */
|
|
34
|
-
export declare function nodeGypBuildShim(
|
|
77
|
+
export declare function nodeGypBuildShim(addonTable: AddonTable): string;
|
|
35
78
|
/** `bindings` replacement — a callable `bindings(name)` returning the addon. */
|
|
36
|
-
export declare function bindingsShim(
|
|
79
|
+
export declare function bindingsShim(addonTable: AddonTable): string;
|
|
37
80
|
/** napi-rs sibling → the raw native exports as the module value. */
|
|
38
|
-
export declare function napiRsShim(
|
|
81
|
+
export declare function napiRsShim(addonTable: AddonTable): string;
|
|
39
82
|
/** Classify a specifier for interception — pure decision logic, no filesystem. */
|
|
40
83
|
export declare function classifySpecifier(source: string): {
|
|
41
84
|
kind: 'node-gyp-build' | 'bindings';
|
|
@@ -122,3 +165,4 @@ export declare function hostNapiRsTriple(): string | null;
|
|
|
122
165
|
* else. Register ONLY for `--app gjs` — the C-ABI runs under `@gjsify/napi`.
|
|
123
166
|
*/
|
|
124
167
|
export declare function napiNodeAddonPlugin(options?: NapiNodeAddonPluginOptions): Plugin;
|
|
168
|
+
export {};
|