@gjsify/cli 0.23.0 → 0.24.2
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 +9 -5
- package/dist/cli.gjs.mjs +97 -85
- package/lib/actions/build.d.ts +12 -0
- package/lib/actions/build.js +26 -0
- package/lib/bundler-pick.js +54 -13
- package/lib/commands/affected.js +62 -4
- package/lib/commands/dlx.d.ts +15 -0
- package/lib/commands/dlx.js +3 -2
- package/lib/commands/foreach.js +71 -1
- package/lib/commands/install.d.ts +1 -1
- package/lib/commands/install.js +30 -23
- package/lib/commands/showcase.js +62 -18
- package/lib/commands/storybook.js +5 -2
- package/lib/utils/bin-shim.d.ts +49 -0
- package/lib/utils/bin-shim.js +105 -0
- package/lib/utils/detect-native-packages.d.ts +26 -21
- package/lib/utils/detect-native-packages.js +53 -41
- package/lib/utils/gjs-bundle-guard.d.ts +32 -0
- package/lib/utils/gjs-bundle-guard.js +103 -0
- package/lib/utils/install-backend-native.js +0 -1
- package/lib/utils/install-global.d.ts +0 -16
- package/lib/utils/install-global.js +19 -36
- package/lib/utils/normalize-bundler-options.js +0 -2
- package/lib/utils/oxc-resolve.js +7 -2
- package/lib/utils/run-node.d.ts +16 -0
- package/lib/utils/run-node.js +28 -7
- package/lib/utils/runtimes.d.ts +21 -0
- package/lib/utils/runtimes.js +23 -0
- package/package.json +17 -17
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// Build-time guard: a `--app gjs` bundle must not keep bare `node:` imports.
|
|
2
|
+
//
|
|
3
|
+
// Stock GJS has NO `node:` module loader. A single surviving
|
|
4
|
+
// `import … from "node:fs"` makes it abort the ENTIRE module graph before one
|
|
5
|
+
// line executes:
|
|
6
|
+
//
|
|
7
|
+
// Gjs-WARNING **: JS ERROR: ImportError: Unsupported URI scheme for importing: node
|
|
8
|
+
// Gjs-CRITICAL **: Failed to resolve imports for module: '…/dist/cli.gjs.mjs'
|
|
9
|
+
//
|
|
10
|
+
// `--app gjs` maps every Node builtin to its `@gjsify/*` polyfill, so a healthy
|
|
11
|
+
// bundle has ZERO of them. But when an alias TARGET cannot be resolved — the
|
|
12
|
+
// classic case being a workspace checkout whose `@gjsify/*` packages have no
|
|
13
|
+
// built `lib/`, so `exports["."]` points at a file that does not exist — the
|
|
14
|
+
// bundler falls back to treating the import as external and re-emits the
|
|
15
|
+
// ORIGINAL `node:*` specifier. That is a WARNING, not an error: the build
|
|
16
|
+
// "succeeds" and writes a bundle that cannot load anywhere. It cost three red
|
|
17
|
+
// CI jobs to notice, because nothing between `gjsify build` and CI ever
|
|
18
|
+
// executes the emitted GJS bundle (tsc, lint, format and the unit/e2e suites
|
|
19
|
+
// all run the Node entry).
|
|
20
|
+
//
|
|
21
|
+
// The pre-commit hook makes it worse rather than better: it rebuilds and
|
|
22
|
+
// AUTO-STAGES `dist/cli.gjs.mjs`, so a developer whose checkout cannot resolve
|
|
23
|
+
// the polyfills commits a broken artifact without ever seeing it.
|
|
24
|
+
//
|
|
25
|
+
// So the refusal belongs at build time, in `gjsify build --app gjs` itself —
|
|
26
|
+
// not in a git hook and not in one package's `build:gjs-bundle` script. The
|
|
27
|
+
// invariant is a property of the ARTIFACT, and every showcase, every downstream
|
|
28
|
+
// app (buchhaltung, bauplaner, Learn6502) and CI all produce it through this
|
|
29
|
+
// one code path. A hook would protect only commits in this repo; a per-package
|
|
30
|
+
// script would protect one package.
|
|
31
|
+
//
|
|
32
|
+
// ## The oracle is the module graph, NOT the emitted text
|
|
33
|
+
//
|
|
34
|
+
// The first cut of this guard grepped the output for `from "node:…"`. That is
|
|
35
|
+
// wrong, and CI caught it: `@gjsify/process`'s own test bundle names a case
|
|
36
|
+
//
|
|
37
|
+
// await it(`named-import hrtime (from "node:process") preserves .bigint`, …)
|
|
38
|
+
//
|
|
39
|
+
// so the phrase appears verbatim inside a STRING, in a bundle that loads and
|
|
40
|
+
// runs under GJS perfectly well. The same trap sits in `@gjsify/cli`'s own
|
|
41
|
+
// bundle, which embeds `giNodeShimSource()`'s `--app node` codegen template
|
|
42
|
+
// (`import { createRequire } from 'node:module';`). Telling a statement from a
|
|
43
|
+
// quoted lookalike needs a JS lexer — but the bundler already did that work:
|
|
44
|
+
// every chunk carries the list of external specifiers it actually imports. That
|
|
45
|
+
// list is exact, engine-independent (npm `rolldown` returns it directly,
|
|
46
|
+
// `@gjsify/rolldown-native` forwards it through `synthRolldownOutput`), and
|
|
47
|
+
// free.
|
|
48
|
+
//
|
|
49
|
+
// Scope is STATIC imports, which is precisely the failure mode above: they are
|
|
50
|
+
// resolved when GJS links the module, so one bad specifier kills the whole
|
|
51
|
+
// bundle. A dynamic `import('node:x')` throws lazily at its call site instead —
|
|
52
|
+
// a real bug, but not "the artifact cannot load", and not what this gate is
|
|
53
|
+
// for.
|
|
54
|
+
/**
|
|
55
|
+
* Bare `node:` specifiers a `--app gjs` bundle may keep as static imports.
|
|
56
|
+
*
|
|
57
|
+
* Deliberately EMPTY. Every Node builtin has an `@gjsify/*` polyfill that
|
|
58
|
+
* `--app gjs` aliases to, so there is no specifier that both survives into the
|
|
59
|
+
* module graph and loads under GJS. Reading the graph instead of the text is
|
|
60
|
+
* what keeps this list empty — the entries an earlier text-scanning version
|
|
61
|
+
* needed (`node:module`, `node:process`) were quoted lookalikes, never imports.
|
|
62
|
+
*
|
|
63
|
+
* Add an entry ONLY with a comment naming why GJS can resolve it. Each one is a
|
|
64
|
+
* specifier this guard can no longer catch for real.
|
|
65
|
+
*/
|
|
66
|
+
export const GJS_ALLOWED_NODE_IMPORTS = [];
|
|
67
|
+
/**
|
|
68
|
+
* The distinct bare `node:` specifiers `chunks` statically import, minus the
|
|
69
|
+
* allowlist. Sorted, so the error message and any test are stable.
|
|
70
|
+
*/
|
|
71
|
+
export function findDisallowedNodeImports(chunks, allowed = GJS_ALLOWED_NODE_IMPORTS) {
|
|
72
|
+
const found = new Set();
|
|
73
|
+
for (const chunk of chunks) {
|
|
74
|
+
for (const specifier of chunk.imports ?? []) {
|
|
75
|
+
if (!specifier.startsWith('node:'))
|
|
76
|
+
continue;
|
|
77
|
+
if (allowed.includes(specifier))
|
|
78
|
+
continue;
|
|
79
|
+
found.add(specifier);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return [...found].sort();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Throw when a built `--app gjs` bundle statically imports Node builtins.
|
|
86
|
+
*
|
|
87
|
+
* @param chunks the emitted chunks, as reported by the bundler
|
|
88
|
+
* @param outfile path of the bundle, for the error message
|
|
89
|
+
*/
|
|
90
|
+
export function assertGjsBundleLoadable(chunks, outfile) {
|
|
91
|
+
const offenders = findDisallowedNodeImports(chunks);
|
|
92
|
+
if (offenders.length === 0)
|
|
93
|
+
return;
|
|
94
|
+
throw new Error(`gjsify build --app gjs: ${outfile} still imports ${offenders.length} bare \`node:\` module(s), ` +
|
|
95
|
+
'which stock GJS cannot resolve — it would fail at load with ' +
|
|
96
|
+
'"ImportError: Unsupported URI scheme for importing: node".\n' +
|
|
97
|
+
offenders.map((s) => ` - ${s}`).join('\n') +
|
|
98
|
+
'\n\nThese should have been aliased to their `@gjsify/*` polyfills. The usual cause is that the ' +
|
|
99
|
+
'alias TARGET could not be resolved, so the bundler externalised the import instead (look for ' +
|
|
100
|
+
'UNRESOLVED_IMPORT warnings above): e.g. a workspace checkout whose `@gjsify/*` packages have no ' +
|
|
101
|
+
'built `lib/`. Build the workspace first (`gjsify run build:infra`), or fix the resolution, then ' +
|
|
102
|
+
'rebuild.');
|
|
103
|
+
}
|
|
@@ -571,7 +571,6 @@ function findVisible(requesterPath, name, byPath) {
|
|
|
571
571
|
candidates.push(`${requesterPath}/node_modules/${name}`);
|
|
572
572
|
// Walk up: strip the last `/node_modules/<pkg>` segment and try again.
|
|
573
573
|
let p = requesterPath;
|
|
574
|
-
// eslint-disable-next-line no-constant-condition
|
|
575
574
|
while (true) {
|
|
576
575
|
// Find the deepest `/node_modules/<pkg>` in `p`, strip it.
|
|
577
576
|
const idx = p.lastIndexOf('/node_modules/');
|
|
@@ -86,22 +86,6 @@ export interface LinkedBin {
|
|
|
86
86
|
* simplicity and so we don't need to discriminate by runtime here.
|
|
87
87
|
*/
|
|
88
88
|
export declare function linkGlobalBins(packageNames: string[], layout: GlobalLayout): LinkedBin[];
|
|
89
|
-
/**
|
|
90
|
-
* Build the POSIX-sh `export` lines that prepend the given prebuild
|
|
91
|
-
* directories to GI_TYPELIB_PATH and the host's shared-library search path.
|
|
92
|
-
* Any pre-existing value inherited from the user's environment is preserved as
|
|
93
|
-
* a suffix so user-installed typelibs/libraries still resolve.
|
|
94
|
-
*
|
|
95
|
-
* The library variable is host-dependent — `LD_LIBRARY_PATH` on Linux,
|
|
96
|
-
* `DYLD_LIBRARY_PATH` on macOS (dyld never reads the ELF one), so a launcher
|
|
97
|
-
* written on a Mac used to export a variable nothing consults, leaving every
|
|
98
|
-
* `darwin-arm64` prebuild unloadable. `platform` is a parameter so both
|
|
99
|
-
* branches are unit-testable from either host.
|
|
100
|
-
*
|
|
101
|
-
* Returns the empty string when no prebuilds were found — avoids emitting an
|
|
102
|
-
* inert assignment in the launcher.
|
|
103
|
-
*/
|
|
104
|
-
export declare function buildLauncherEnvPreamble(prebuildsDirs: string[], platform?: string): string;
|
|
105
89
|
/** Returns `true` if `binDir` is on the user's PATH. */
|
|
106
90
|
export declare function binDirOnPath(binDir: string): boolean;
|
|
107
91
|
/**
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
import * as fs from 'node:fs';
|
|
24
24
|
import * as os from 'node:os';
|
|
25
25
|
import * as path from 'node:path';
|
|
26
|
-
import { detectNativePackages
|
|
27
|
-
import { buildLauncherShims, parseShebang } from './bin-shim.js';
|
|
26
|
+
import { detectNativePackages } from './detect-native-packages.js';
|
|
27
|
+
import { buildLauncherShims, buildNativeEnvPreamble, parseShebang } from './bin-shim.js';
|
|
28
28
|
/**
|
|
29
29
|
* Compute the canonical global install layout for the current user. Honours
|
|
30
30
|
* `XDG_DATA_HOME` (per the XDG Base Directory Spec) plus
|
|
@@ -143,18 +143,25 @@ export async function installGjsEnginePackages(prefix, version, opts = {}) {
|
|
|
143
143
|
export function linkGlobalBins(packageNames, layout) {
|
|
144
144
|
fs.mkdirSync(layout.binDir, { recursive: true });
|
|
145
145
|
const created = [];
|
|
146
|
-
//
|
|
147
|
-
// + shared libs)
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
//
|
|
146
|
+
// The launcher exports GI_TYPELIB_PATH / <loader path> for the @gjsify/*
|
|
147
|
+
// native prebuilds (Vala/GObject typelibs + shared libs) installed in this
|
|
148
|
+
// prefix, so `imports.gi.X` resolves at CLI startup — required for the
|
|
149
|
+
// bundler engine `@gjsify/rolldown-native` (without which `gjsify build`
|
|
150
|
+
// hard-fails under GJS) and for e.g. `@gjsify/terminal-native`, without
|
|
151
|
+
// which isTTY / columns / colors fall back to conservative defaults.
|
|
152
152
|
//
|
|
153
|
-
// `runGjsBundle()` does the same dance for `gjsify run <bundle>` at
|
|
154
|
-
//
|
|
155
|
-
//
|
|
153
|
+
// `runGjsBundle()` does the same dance for `gjsify run <bundle>` at runtime;
|
|
154
|
+
// here it has to be the launcher, because the typelib lookup happens inside
|
|
155
|
+
// the GJS runtime before the bundle's first line runs.
|
|
156
|
+
//
|
|
157
|
+
// The preamble SCANS the prefix at launch time rather than embedding what
|
|
158
|
+
// was there at install time — see `buildNativeEnvPreamble` for why a
|
|
159
|
+
// snapshot is the wrong shape. `nativePrebuildDirs` is still computed: the
|
|
160
|
+
// Windows `.cmd`/`.ps1` shims take the baked list, and a hit in an
|
|
161
|
+
// ANCESTOR's node_modules (which the walk finds and a single-root scan
|
|
162
|
+
// cannot) is embedded verbatim.
|
|
156
163
|
const nativePrebuildDirs = detectNativePackages(layout.prefix).map((p) => p.prebuildsDir);
|
|
157
|
-
const envPreamble =
|
|
164
|
+
const envPreamble = buildNativeEnvPreamble(layout.prefix, nativePrebuildDirs);
|
|
158
165
|
for (const pkgName of packageNames) {
|
|
159
166
|
const pkgDir = path.join(layout.prefix, 'node_modules', pkgName);
|
|
160
167
|
const pkgJsonPath = path.join(pkgDir, 'package.json');
|
|
@@ -237,30 +244,6 @@ export function linkGlobalBins(packageNames, layout) {
|
|
|
237
244
|
function shQuote(s) {
|
|
238
245
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
239
246
|
}
|
|
240
|
-
/**
|
|
241
|
-
* Build the POSIX-sh `export` lines that prepend the given prebuild
|
|
242
|
-
* directories to GI_TYPELIB_PATH and the host's shared-library search path.
|
|
243
|
-
* Any pre-existing value inherited from the user's environment is preserved as
|
|
244
|
-
* a suffix so user-installed typelibs/libraries still resolve.
|
|
245
|
-
*
|
|
246
|
-
* The library variable is host-dependent — `LD_LIBRARY_PATH` on Linux,
|
|
247
|
-
* `DYLD_LIBRARY_PATH` on macOS (dyld never reads the ELF one), so a launcher
|
|
248
|
-
* written on a Mac used to export a variable nothing consults, leaving every
|
|
249
|
-
* `darwin-arm64` prebuild unloadable. `platform` is a parameter so both
|
|
250
|
-
* branches are unit-testable from either host.
|
|
251
|
-
*
|
|
252
|
-
* Returns the empty string when no prebuilds were found — avoids emitting an
|
|
253
|
-
* inert assignment in the launcher.
|
|
254
|
-
*/
|
|
255
|
-
export function buildLauncherEnvPreamble(prebuildsDirs, platform = process.platform) {
|
|
256
|
-
if (prebuildsDirs.length === 0)
|
|
257
|
-
return '';
|
|
258
|
-
const { name: libVar } = libraryPathVar(platform);
|
|
259
|
-
const joined = shQuote(prebuildsDirs.join(':'));
|
|
260
|
-
return (`GI_TYPELIB_PATH=${joined}\${GI_TYPELIB_PATH:+":$GI_TYPELIB_PATH"}\n` +
|
|
261
|
-
`${libVar}=${joined}\${${libVar}:+":$${libVar}"}\n` +
|
|
262
|
-
`export GI_TYPELIB_PATH ${libVar}\n`);
|
|
263
|
-
}
|
|
264
247
|
/** Parse a bin file's `#!` line; `null` when unreadable or not a shebang. */
|
|
265
248
|
function readShebangOf(file) {
|
|
266
249
|
try {
|
|
@@ -24,7 +24,6 @@ export function normalizeBundlerOptions(configData) {
|
|
|
24
24
|
raw['define'] !== null) {
|
|
25
25
|
if (!warnedDefineOnce) {
|
|
26
26
|
warnedDefineOnce = true;
|
|
27
|
-
// eslint-disable-next-line no-console
|
|
28
27
|
console.warn("[gjsify] WARNING: 'bundler.define' is not a valid Rolldown option and would be " +
|
|
29
28
|
"silently ignored — it has been auto-mapped to 'bundler.transform.define'. " +
|
|
30
29
|
"Move 'define' under 'bundler.transform.define' in your config to suppress " +
|
|
@@ -46,7 +45,6 @@ export function normalizeBundlerOptions(configData) {
|
|
|
46
45
|
return fromBundler;
|
|
47
46
|
if (!warnedOnce) {
|
|
48
47
|
warnedOnce = true;
|
|
49
|
-
// eslint-disable-next-line no-console
|
|
50
48
|
console.warn("[gjsify] DEPRECATION: the 'esbuild' config key is deprecated and will be removed in 0.5.0. " +
|
|
51
49
|
"Rename it to 'bundler' (typed as RolldownOptions). See the migration notes in the gjsify CHANGELOG.");
|
|
52
50
|
}
|
package/lib/utils/oxc-resolve.js
CHANGED
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
// lives in the Node launcher, so a native oxlint bridge could only run the
|
|
47
47
|
// Rust rule subset. Lint stays Node-spawned until that trade-off is decided
|
|
48
48
|
// (tracked in STATUS.md Open TODOs).
|
|
49
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
49
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
50
50
|
import { join, resolve } from 'node:path';
|
|
51
51
|
import { createRequire } from 'node:module';
|
|
52
52
|
import { pathToFileURL } from 'node:url';
|
|
@@ -89,7 +89,12 @@ function oxcBindingSuffix() {
|
|
|
89
89
|
// glibc systems have `/lib/ld-linux-*`, musl has `/lib/ld-musl-*`.
|
|
90
90
|
let libc = 'gnu';
|
|
91
91
|
try {
|
|
92
|
-
|
|
92
|
+
// `readdirSync` is imported STATICALLY at the top of this file. It
|
|
93
|
+
// used to be a lazy `require('node:fs')` inside this try — a bare
|
|
94
|
+
// `require` in an ESM module, so it threw ReferenceError, the catch
|
|
95
|
+
// below swallowed it, and `libc` silently stayed 'gnu': a musl host
|
|
96
|
+
// would be told to install the WRONG binding package. Same defect
|
|
97
|
+
// class as commands/affected.ts, and even quieter.
|
|
93
98
|
const libEntries = readdirSync('/lib');
|
|
94
99
|
if (libEntries.some((e) => e.startsWith('ld-musl-'))) {
|
|
95
100
|
libc = 'musl';
|
package/lib/utils/run-node.d.ts
CHANGED
|
@@ -6,6 +6,22 @@ import { type ExampleRuntime } from './runtimes.js';
|
|
|
6
6
|
* not available under the GJS-bundled CLI.
|
|
7
7
|
*/
|
|
8
8
|
export declare function resolveNodeGi(startDir: string): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Resolve `@gjsify/node-gi` for a bundle we are about to launch: from the
|
|
11
|
+
* BUNDLE's own directory first, then from `cwd`.
|
|
12
|
+
*
|
|
13
|
+
* The bundle's directory is the correct base and cwd is the fallback, for the
|
|
14
|
+
* same reason {@link computeNativeEnvForBundle} walks both: `@gjsify/node-gi` is
|
|
15
|
+
* kept EXTERNAL, so what has to be satisfiable is the RUNTIME's resolution of a
|
|
16
|
+
* bare specifier from inside the bundle — which Node performs relative to the
|
|
17
|
+
* importing file, never relative to cwd. A dlx-cache layout
|
|
18
|
+
* (`~/.cache/gjsify/dlx/<sha>/node_modules/<pkg>/dist/bundle.mjs`) has node-gi
|
|
19
|
+
* sitting right beside the bundle and nothing at all under the user's cwd, so a
|
|
20
|
+
* cwd-only probe rejected a run that would have worked. The cwd probe is kept
|
|
21
|
+
* because a project-local `node_modules` legitimately satisfies a bundle built
|
|
22
|
+
* into a `dist/` outside it (a `--outfile /tmp/…` build from a project root).
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveNodeGiForBundle(bundlePath: string, cwd: string): string | null;
|
|
9
25
|
/** Pick the node executable: the current one when on Node, else PATH `node`. */
|
|
10
26
|
export declare function nodeBinary(): string;
|
|
11
27
|
export interface RunNodeBundleOptions {
|
package/lib/utils/run-node.js
CHANGED
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
// through `@gjsify/node-gi` (the Axis-5 reverse bridge). Two things have to be
|
|
6
6
|
// true at runtime:
|
|
7
7
|
//
|
|
8
|
-
// 1. `@gjsify/node-gi` must resolve
|
|
9
|
-
// the bundler (a native addon), so it has to physically exist in
|
|
10
|
-
//
|
|
11
|
-
//
|
|
8
|
+
// 1. `@gjsify/node-gi` must resolve FROM THE BUNDLE — it is kept EXTERNAL by
|
|
9
|
+
// the bundler (a native addon), so it has to physically exist in a
|
|
10
|
+
// node_modules the bundle's own directory can reach (that is where Node
|
|
11
|
+
// will look), with the CWD as a fallback. We verify this up front and emit
|
|
12
|
+
// a clear hint instead of letting Node throw `ERR_MODULE_NOT_FOUND` deep in
|
|
13
|
+
// the bundle. See `resolveNodeGiForBundle`.
|
|
12
14
|
// 2. `gi://Gtk` / `gi://Adw` etc. must resolve. System typelibs come from the
|
|
13
15
|
// default GI search path, but any `@gjsify/*` Vala bridge a story pulls in
|
|
14
16
|
// ships its typelib in `prebuilds/` — so we reuse the SAME
|
|
@@ -21,7 +23,7 @@
|
|
|
21
23
|
// `gjs`, which cannot run a `--app node` bundle).
|
|
22
24
|
import { spawn } from 'node:child_process';
|
|
23
25
|
import { existsSync, readFileSync } from 'node:fs';
|
|
24
|
-
import { join, resolve } from 'node:path';
|
|
26
|
+
import { dirname, join, resolve } from 'node:path';
|
|
25
27
|
import { isNode } from '@gjsify/rolldown-plugin-gjsify/runtime';
|
|
26
28
|
import { computeNativeEnvForBundle } from './run-gjs.js';
|
|
27
29
|
import { RUNTIMES } from './runtimes.js';
|
|
@@ -43,6 +45,25 @@ export function resolveNodeGi(startDir) {
|
|
|
43
45
|
dir = parent;
|
|
44
46
|
}
|
|
45
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolve `@gjsify/node-gi` for a bundle we are about to launch: from the
|
|
50
|
+
* BUNDLE's own directory first, then from `cwd`.
|
|
51
|
+
*
|
|
52
|
+
* The bundle's directory is the correct base and cwd is the fallback, for the
|
|
53
|
+
* same reason {@link computeNativeEnvForBundle} walks both: `@gjsify/node-gi` is
|
|
54
|
+
* kept EXTERNAL, so what has to be satisfiable is the RUNTIME's resolution of a
|
|
55
|
+
* bare specifier from inside the bundle — which Node performs relative to the
|
|
56
|
+
* importing file, never relative to cwd. A dlx-cache layout
|
|
57
|
+
* (`~/.cache/gjsify/dlx/<sha>/node_modules/<pkg>/dist/bundle.mjs`) has node-gi
|
|
58
|
+
* sitting right beside the bundle and nothing at all under the user's cwd, so a
|
|
59
|
+
* cwd-only probe rejected a run that would have worked. The cwd probe is kept
|
|
60
|
+
* because a project-local `node_modules` legitimately satisfies a bundle built
|
|
61
|
+
* into a `dist/` outside it (a `--outfile /tmp/…` build from a project root).
|
|
62
|
+
*/
|
|
63
|
+
export function resolveNodeGiForBundle(bundlePath, cwd) {
|
|
64
|
+
const resolvedBundle = resolve(bundlePath);
|
|
65
|
+
return resolveNodeGi(dirname(resolvedBundle)) ?? resolveNodeGi(cwd);
|
|
66
|
+
}
|
|
46
67
|
/** Pick the node executable: the current one when on Node, else PATH `node`. */
|
|
47
68
|
export function nodeBinary() {
|
|
48
69
|
return isNode() && process.execPath ? process.execPath : 'node';
|
|
@@ -55,7 +76,7 @@ export function nodeBinary() {
|
|
|
55
76
|
*/
|
|
56
77
|
export async function runNodeBundle(bundlePath, extraArgs = [], options = {}) {
|
|
57
78
|
const cwd = process.cwd();
|
|
58
|
-
if (!
|
|
79
|
+
if (!resolveNodeGiForBundle(bundlePath, cwd)) {
|
|
59
80
|
throw new Error('Cannot run the storybook on Node: `@gjsify/node-gi` is not installed.\n' +
|
|
60
81
|
'Add @gjsify/node-gi as a dependency to run the storybook on Node, e.g.:\n' +
|
|
61
82
|
' "devDependencies": { "@gjsify/node-gi": "^0.13.0" }');
|
|
@@ -113,7 +134,7 @@ export function bundleRequiresNodeGi(bundlePath) {
|
|
|
113
134
|
export async function runRuntimeBundle(runtime, bundlePath, extraArgs = [], options = {}) {
|
|
114
135
|
const cwd = process.cwd();
|
|
115
136
|
const resolvedBundle = resolve(bundlePath);
|
|
116
|
-
if (bundleRequiresNodeGi(resolvedBundle) && !
|
|
137
|
+
if (bundleRequiresNodeGi(resolvedBundle) && !resolveNodeGiForBundle(resolvedBundle, cwd)) {
|
|
117
138
|
throw new Error(`Cannot run this bundle on ${runtime}: it uses gi:// via \`@gjsify/node-gi\`, which is not installed.\n` +
|
|
118
139
|
'Add @gjsify/node-gi as a dependency to run gi:// code off GJS, e.g.:\n' +
|
|
119
140
|
' "dependencies": { "@gjsify/node-gi": "^0.13.0" }');
|
package/lib/utils/runtimes.d.ts
CHANGED
|
@@ -37,6 +37,27 @@ export declare function isRuntimeOnPath(probe: string): boolean;
|
|
|
37
37
|
export declare function isRuntimeAvailable(runtime: ExampleRuntime): boolean;
|
|
38
38
|
/** Which of gjs/node/bun/deno are runnable on this host. */
|
|
39
39
|
export declare function availableRuntimes(): ExampleRuntime[];
|
|
40
|
+
/**
|
|
41
|
+
* The default `--runtime` for running a prebuilt EXAMPLE/SHOWCASE: `gjs`
|
|
42
|
+
* whenever gjs is runnable here, else the host runtime.
|
|
43
|
+
*
|
|
44
|
+
* This is deliberately NOT a plain `hostRuntime()`. A showcase's canonical
|
|
45
|
+
* artifact is its `--app gjs` bundle (`gjsify.main`) — that is what every
|
|
46
|
+
* showcase ships, what the `gjs` path installs via `gjsify dlx`, and what the
|
|
47
|
+
* docs call the default. Following the host instead means `npx @gjsify/cli
|
|
48
|
+
* showcase <name>` (host = node) silently asks for the `--app node` bundle,
|
|
49
|
+
* which most showcases do not ship and which additionally needs
|
|
50
|
+
* `@gjsify/node-gi` in the consumer's project — so the FIRST-RUN experience of
|
|
51
|
+
* the primary documented entry point failed on a missing file.
|
|
52
|
+
*
|
|
53
|
+
* Same rule `gjsify run` already applies in its bare-file path, where a
|
|
54
|
+
* `--app gjs` bundle stays on gjs regardless of host (`isLikelyGjsBundle`);
|
|
55
|
+
* here the "is it a gjs artifact" question is answered by the command instead
|
|
56
|
+
* of by sniffing the file. `--runtime` still overrides explicitly, and a host
|
|
57
|
+
* WITHOUT gjs (a plain Node/bun/deno box) keeps following the host so the
|
|
58
|
+
* node-capable showcases stay runnable there.
|
|
59
|
+
*/
|
|
60
|
+
export declare function defaultExampleRuntime(): ExampleRuntime;
|
|
40
61
|
interface ExampleGjsifyField {
|
|
41
62
|
example?: {
|
|
42
63
|
runtimes?: unknown;
|
package/lib/utils/runtimes.js
CHANGED
|
@@ -64,6 +64,29 @@ export function isRuntimeAvailable(runtime) {
|
|
|
64
64
|
export function availableRuntimes() {
|
|
65
65
|
return EXAMPLE_RUNTIMES.filter((rt) => isRuntimeAvailable(rt));
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* The default `--runtime` for running a prebuilt EXAMPLE/SHOWCASE: `gjs`
|
|
69
|
+
* whenever gjs is runnable here, else the host runtime.
|
|
70
|
+
*
|
|
71
|
+
* This is deliberately NOT a plain `hostRuntime()`. A showcase's canonical
|
|
72
|
+
* artifact is its `--app gjs` bundle (`gjsify.main`) — that is what every
|
|
73
|
+
* showcase ships, what the `gjs` path installs via `gjsify dlx`, and what the
|
|
74
|
+
* docs call the default. Following the host instead means `npx @gjsify/cli
|
|
75
|
+
* showcase <name>` (host = node) silently asks for the `--app node` bundle,
|
|
76
|
+
* which most showcases do not ship and which additionally needs
|
|
77
|
+
* `@gjsify/node-gi` in the consumer's project — so the FIRST-RUN experience of
|
|
78
|
+
* the primary documented entry point failed on a missing file.
|
|
79
|
+
*
|
|
80
|
+
* Same rule `gjsify run` already applies in its bare-file path, where a
|
|
81
|
+
* `--app gjs` bundle stays on gjs regardless of host (`isLikelyGjsBundle`);
|
|
82
|
+
* here the "is it a gjs artifact" question is answered by the command instead
|
|
83
|
+
* of by sniffing the file. `--runtime` still overrides explicitly, and a host
|
|
84
|
+
* WITHOUT gjs (a plain Node/bun/deno box) keeps following the host so the
|
|
85
|
+
* node-capable showcases stay runnable there.
|
|
86
|
+
*/
|
|
87
|
+
export function defaultExampleRuntime() {
|
|
88
|
+
return isRuntimeAvailable('gjs') ? 'gjs' : hostRuntime();
|
|
89
|
+
}
|
|
67
90
|
/**
|
|
68
91
|
* Read a package's declared example runtimes. Returns the (validated) list, or
|
|
69
92
|
* `null` when the package declares none — the "unconstrained / permissive" case.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.2",
|
|
4
4
|
"description": "CLI for Gjsify",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -130,19 +130,19 @@
|
|
|
130
130
|
"cli"
|
|
131
131
|
],
|
|
132
132
|
"dependencies": {
|
|
133
|
-
"@gjsify/buffer": "^0.
|
|
134
|
-
"@gjsify/create-app": "^0.
|
|
135
|
-
"@gjsify/node-globals": "^0.
|
|
136
|
-
"@gjsify/node-polyfills": "^0.
|
|
137
|
-
"@gjsify/npm-registry": "^0.
|
|
138
|
-
"@gjsify/resolve-npm": "^0.
|
|
139
|
-
"@gjsify/rolldown-plugin-gjsify": "^0.
|
|
140
|
-
"@gjsify/rolldown-plugin-pnp": "^0.
|
|
141
|
-
"@gjsify/semver": "^0.
|
|
142
|
-
"@gjsify/tar": "^0.
|
|
143
|
-
"@gjsify/tsc": "^0.
|
|
144
|
-
"@gjsify/web-polyfills": "^0.
|
|
145
|
-
"@gjsify/workspace": "^0.
|
|
133
|
+
"@gjsify/buffer": "^0.24.2",
|
|
134
|
+
"@gjsify/create-app": "^0.24.2",
|
|
135
|
+
"@gjsify/node-globals": "^0.24.2",
|
|
136
|
+
"@gjsify/node-polyfills": "^0.24.2",
|
|
137
|
+
"@gjsify/npm-registry": "^0.24.2",
|
|
138
|
+
"@gjsify/resolve-npm": "^0.24.2",
|
|
139
|
+
"@gjsify/rolldown-plugin-gjsify": "^0.24.2",
|
|
140
|
+
"@gjsify/rolldown-plugin-pnp": "^0.24.2",
|
|
141
|
+
"@gjsify/semver": "^0.24.2",
|
|
142
|
+
"@gjsify/tar": "^0.24.2",
|
|
143
|
+
"@gjsify/tsc": "^0.24.2",
|
|
144
|
+
"@gjsify/web-polyfills": "^0.24.2",
|
|
145
|
+
"@gjsify/workspace": "^0.24.2",
|
|
146
146
|
"cosmiconfig": "^9.0.2",
|
|
147
147
|
"get-tsconfig": "^4.14.0",
|
|
148
148
|
"pkg-types": "^2.3.1",
|
|
@@ -150,13 +150,13 @@
|
|
|
150
150
|
"yargs": "^18.0.0"
|
|
151
151
|
},
|
|
152
152
|
"devDependencies": {
|
|
153
|
-
"@gjsify/unit": "^0.
|
|
153
|
+
"@gjsify/unit": "^0.24.2",
|
|
154
154
|
"@types/yargs": "^17.0.35",
|
|
155
155
|
"typescript": "^6.0.3"
|
|
156
156
|
},
|
|
157
157
|
"peerDependencies": {
|
|
158
|
-
"@gjsify/oxfmt-native": "^0.
|
|
159
|
-
"@gjsify/rolldown-native": "^0.
|
|
158
|
+
"@gjsify/oxfmt-native": "^0.24.2",
|
|
159
|
+
"@gjsify/rolldown-native": "^0.24.2"
|
|
160
160
|
},
|
|
161
161
|
"peerDependenciesMeta": {
|
|
162
162
|
"@gjsify/oxfmt-native": {
|