@gjsify/cli 0.1.7 → 0.1.8
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/lib/actions/build.d.ts +6 -0
- package/lib/actions/build.js +30 -3
- package/lib/commands/build.js +6 -0
- package/lib/commands/create.d.ts +6 -0
- package/lib/commands/create.js +15 -0
- package/lib/commands/index.d.ts +1 -0
- package/lib/commands/index.js +1 -0
- package/lib/commands/showcase.js +29 -29
- package/lib/config.js +2 -0
- package/lib/index.js +2 -1
- package/lib/types/cli-build-options.d.ts +7 -0
- package/lib/types/config-data.d.ts +5 -0
- package/lib/utils/discover-showcases.d.ts +19 -0
- package/lib/utils/{discover-examples.js → discover-showcases.js} +14 -15
- package/lib/utils/run-gjs.js +9 -0
- package/package.json +9 -50
- package/src/actions/build.ts +38 -4
- package/src/commands/build.ts +6 -0
- package/src/commands/create.ts +21 -0
- package/src/commands/index.ts +2 -1
- package/src/commands/showcase.ts +30 -30
- package/src/config.ts +1 -0
- package/src/index.ts +2 -1
- package/src/types/cli-build-options.ts +8 -1
- package/src/types/config-data.ts +6 -1
- package/src/utils/{discover-examples.ts → discover-showcases.ts} +18 -19
- package/src/utils/run-gjs.ts +11 -0
- package/lib/utils/discover-examples.d.ts +0 -19
package/lib/actions/build.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ export declare class BuildAction {
|
|
|
7
7
|
getEsBuildDefaults(): BuildOptions;
|
|
8
8
|
/** Library mode */
|
|
9
9
|
buildLibrary(): Promise<BuildResult<BuildOptions>[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Resolve the `--globals` CLI list into a pre-computed inject stub path
|
|
12
|
+
* that the esbuild plugin will append to its `inject` list. Only runs
|
|
13
|
+
* for `--app gjs` — Node and browser builds rely on native globals.
|
|
14
|
+
*/
|
|
15
|
+
private resolveGlobalsInject;
|
|
10
16
|
/** Application mode */
|
|
11
17
|
buildApp(app?: App): Promise<BuildResult<{
|
|
12
18
|
format: "esm" | "cjs";
|
package/lib/actions/build.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { build } from 'esbuild';
|
|
2
2
|
import { gjsifyPlugin } from '@gjsify/esbuild-plugin-gjsify';
|
|
3
|
+
import { resolveGlobalsList, writeRegisterInjectFile } from '@gjsify/esbuild-plugin-gjsify/globals';
|
|
3
4
|
import { dirname, extname } from 'path';
|
|
4
5
|
export class BuildAction {
|
|
5
6
|
configData;
|
|
@@ -63,6 +64,23 @@ export class BuildAction {
|
|
|
63
64
|
}
|
|
64
65
|
return results;
|
|
65
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolve the `--globals` CLI list into a pre-computed inject stub path
|
|
69
|
+
* that the esbuild plugin will append to its `inject` list. Only runs
|
|
70
|
+
* for `--app gjs` — Node and browser builds rely on native globals.
|
|
71
|
+
*/
|
|
72
|
+
async resolveGlobalsInject(app, globals, verbose) {
|
|
73
|
+
if (app !== 'gjs' || !globals)
|
|
74
|
+
return undefined;
|
|
75
|
+
const registerPaths = resolveGlobalsList(globals);
|
|
76
|
+
if (registerPaths.size === 0)
|
|
77
|
+
return undefined;
|
|
78
|
+
const injectPath = await writeRegisterInjectFile(registerPaths, process.cwd());
|
|
79
|
+
if (verbose && injectPath) {
|
|
80
|
+
console.debug(`[gjsify] globals: injected ${registerPaths.size} register module(s) from --globals ${globals}`);
|
|
81
|
+
}
|
|
82
|
+
return injectPath ?? undefined;
|
|
83
|
+
}
|
|
66
84
|
/** Application mode */
|
|
67
85
|
async buildApp(app = 'gjs') {
|
|
68
86
|
const { verbose, esbuild, typescript, exclude, library: pgk } = this.configData;
|
|
@@ -71,17 +89,26 @@ export class BuildAction {
|
|
|
71
89
|
if (esbuild && !esbuild?.outfile && !esbuild?.outdir && (pgk?.main || pgk?.module)) {
|
|
72
90
|
esbuild.outfile = esbuild?.format === 'cjs' ? pgk.main || pgk.module : pgk.module || pgk.main;
|
|
73
91
|
}
|
|
74
|
-
const { consoleShim } = this.configData;
|
|
92
|
+
const { consoleShim, globals } = this.configData;
|
|
93
|
+
const autoGlobalsInject = await this.resolveGlobalsInject(app, globals, verbose);
|
|
75
94
|
const result = await build({
|
|
76
95
|
...this.getEsBuildDefaults(),
|
|
77
96
|
...esbuild,
|
|
78
97
|
format,
|
|
79
98
|
plugins: [
|
|
80
|
-
gjsifyPlugin({
|
|
99
|
+
gjsifyPlugin({
|
|
100
|
+
debug: verbose,
|
|
101
|
+
app,
|
|
102
|
+
format,
|
|
103
|
+
exclude,
|
|
104
|
+
reflection: typescript?.reflection,
|
|
105
|
+
consoleShim,
|
|
106
|
+
autoGlobalsInject,
|
|
107
|
+
}),
|
|
81
108
|
]
|
|
82
109
|
});
|
|
83
110
|
// See https://esbuild.github.io/api/#metafile
|
|
84
|
-
// TODO add cli options for this
|
|
111
|
+
// TODO add cli options for this
|
|
85
112
|
// if(result.metafile) {
|
|
86
113
|
// const outFile = esbuild?.outfile ? esbuild.outfile + '.meta.json' : 'meta.json';
|
|
87
114
|
// await writeFile(outFile, JSON.stringify(result.metafile));
|
package/lib/commands/build.js
CHANGED
|
@@ -85,6 +85,12 @@ export const buildCommand = {
|
|
|
85
85
|
type: 'boolean',
|
|
86
86
|
normalize: true,
|
|
87
87
|
default: true
|
|
88
|
+
})
|
|
89
|
+
.option('globals', {
|
|
90
|
+
description: "Comma-separated list of global identifiers your code needs (e.g. 'fetch,Buffer,process,URL,crypto'). Each identifier is mapped to the corresponding `@gjsify/<pkg>/register` module and injected into the bundle. See the CLI Reference docs for the full list of known identifiers. Only applies to GJS app builds.",
|
|
91
|
+
type: 'string',
|
|
92
|
+
normalize: true,
|
|
93
|
+
default: ''
|
|
88
94
|
});
|
|
89
95
|
},
|
|
90
96
|
handler: async (args) => {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createProject } from '@gjsify/create-app';
|
|
2
|
+
export const createCommand = {
|
|
3
|
+
command: 'create [project-name]',
|
|
4
|
+
description: 'Scaffold a new Gjsify project in a new directory.',
|
|
5
|
+
builder: (yargs) => {
|
|
6
|
+
return yargs.positional('project-name', {
|
|
7
|
+
describe: 'Name of the project directory to create',
|
|
8
|
+
type: 'string',
|
|
9
|
+
default: 'my-gjs-app',
|
|
10
|
+
});
|
|
11
|
+
},
|
|
12
|
+
handler: async (args) => {
|
|
13
|
+
await createProject(args['project-name']);
|
|
14
|
+
},
|
|
15
|
+
};
|
package/lib/commands/index.d.ts
CHANGED
package/lib/commands/index.js
CHANGED
package/lib/commands/showcase.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { discoverShowcases, findShowcase } from '../utils/discover-showcases.js';
|
|
2
2
|
import { runMinimalChecks, checkGwebgl, detectPackageManager, buildInstallCommand } from '../utils/check-system-deps.js';
|
|
3
3
|
import { runGjsBundle } from '../utils/run-gjs.js';
|
|
4
4
|
export const showcaseCommand = {
|
|
5
5
|
command: 'showcase [name]',
|
|
6
|
-
description: 'List or run built-in gjsify
|
|
6
|
+
description: 'List or run built-in gjsify showcase applications.',
|
|
7
7
|
builder: (yargs) => {
|
|
8
8
|
return yargs
|
|
9
9
|
.positional('name', {
|
|
10
|
-
description: '
|
|
10
|
+
description: 'Showcase name to run (omit to list all)',
|
|
11
11
|
type: 'string',
|
|
12
12
|
})
|
|
13
13
|
.option('json', {
|
|
@@ -16,7 +16,7 @@ export const showcaseCommand = {
|
|
|
16
16
|
default: false,
|
|
17
17
|
})
|
|
18
18
|
.option('list', {
|
|
19
|
-
description: 'List available
|
|
19
|
+
description: 'List available showcases',
|
|
20
20
|
type: 'boolean',
|
|
21
21
|
default: false,
|
|
22
22
|
});
|
|
@@ -24,47 +24,47 @@ export const showcaseCommand = {
|
|
|
24
24
|
handler: async (args) => {
|
|
25
25
|
// List mode: no name given, or --list flag
|
|
26
26
|
if (!args.name || args.list) {
|
|
27
|
-
const
|
|
27
|
+
const showcases = discoverShowcases();
|
|
28
28
|
if (args.json) {
|
|
29
|
-
console.log(JSON.stringify(
|
|
29
|
+
console.log(JSON.stringify(showcases, null, 2));
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
|
-
if (
|
|
33
|
-
console.log('No
|
|
32
|
+
if (showcases.length === 0) {
|
|
33
|
+
console.log('No showcases found. Showcase packages may not be installed.');
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
36
|
// Group by category
|
|
37
37
|
const grouped = new Map();
|
|
38
|
-
for (const
|
|
39
|
-
const list = grouped.get(
|
|
40
|
-
list.push(
|
|
41
|
-
grouped.set(
|
|
38
|
+
for (const sc of showcases) {
|
|
39
|
+
const list = grouped.get(sc.category) ?? [];
|
|
40
|
+
list.push(sc);
|
|
41
|
+
grouped.set(sc.category, list);
|
|
42
42
|
}
|
|
43
|
-
console.log('Available gjsify
|
|
43
|
+
console.log('Available gjsify showcases:\n');
|
|
44
44
|
for (const [category, list] of grouped) {
|
|
45
45
|
console.log(` ${category.toUpperCase()}:`);
|
|
46
46
|
const maxNameLen = Math.max(...list.map(e => e.name.length));
|
|
47
|
-
for (const
|
|
48
|
-
const pad = ' '.repeat(maxNameLen -
|
|
49
|
-
const desc =
|
|
50
|
-
console.log(` ${
|
|
47
|
+
for (const sc of list) {
|
|
48
|
+
const pad = ' '.repeat(maxNameLen - sc.name.length + 2);
|
|
49
|
+
const desc = sc.description ? `${pad}${sc.description}` : '';
|
|
50
|
+
console.log(` ${sc.name}${desc}`);
|
|
51
51
|
}
|
|
52
52
|
console.log('');
|
|
53
53
|
}
|
|
54
|
-
console.log('Run
|
|
54
|
+
console.log('Run a showcase: gjsify showcase <name>');
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
|
-
// Run mode: find the
|
|
58
|
-
const
|
|
59
|
-
if (!
|
|
60
|
-
console.error(`Unknown
|
|
61
|
-
console.error('Run "gjsify showcase" to list available
|
|
57
|
+
// Run mode: find the showcase
|
|
58
|
+
const showcase = findShowcase(args.name);
|
|
59
|
+
if (!showcase) {
|
|
60
|
+
console.error(`Unknown showcase: "${args.name}"`);
|
|
61
|
+
console.error('Run "gjsify showcase" to list available showcases.');
|
|
62
62
|
process.exit(1);
|
|
63
63
|
}
|
|
64
|
-
// System dependency check before running — only check what this
|
|
65
|
-
// All
|
|
64
|
+
// System dependency check before running — only check what this showcase needs.
|
|
65
|
+
// All showcases need GJS; WebGL showcases additionally need gwebgl prebuilds.
|
|
66
66
|
const results = runMinimalChecks();
|
|
67
|
-
const needsWebgl =
|
|
67
|
+
const needsWebgl = showcase.packageName.includes('webgl') || showcase.packageName.includes('three');
|
|
68
68
|
if (needsWebgl) {
|
|
69
69
|
results.push(checkGwebgl(process.cwd()));
|
|
70
70
|
}
|
|
@@ -81,8 +81,8 @@ export const showcaseCommand = {
|
|
|
81
81
|
}
|
|
82
82
|
process.exit(1);
|
|
83
83
|
}
|
|
84
|
-
// Run the
|
|
85
|
-
console.log(`Running
|
|
86
|
-
await runGjsBundle(
|
|
84
|
+
// Run the showcase via shared GJS runner
|
|
85
|
+
console.log(`Running showcase: ${showcase.name}\n`);
|
|
86
|
+
await runGjsBundle(showcase.bundlePath);
|
|
87
87
|
},
|
|
88
88
|
};
|
package/lib/config.js
CHANGED
|
@@ -69,6 +69,8 @@ export class Config {
|
|
|
69
69
|
configData.exclude = cliArgs.exclude || [];
|
|
70
70
|
if (cliArgs.consoleShim !== undefined)
|
|
71
71
|
configData.consoleShim = cliArgs.consoleShim;
|
|
72
|
+
if (cliArgs.globals !== undefined)
|
|
73
|
+
configData.globals = cliArgs.globals;
|
|
72
74
|
merge(configData.library ??= {}, pkg, configData.library);
|
|
73
75
|
merge(configData.typescript ??= {}, tsConfig, configData.typescript);
|
|
74
76
|
merge(configData.esbuild ??= {}, {
|
package/lib/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import yargs from 'yargs';
|
|
3
3
|
import { hideBin } from 'yargs/helpers';
|
|
4
|
-
import { buildCommand as build, runCommand as run, infoCommand as info, checkCommand as check, showcaseCommand as showcase } from './commands/index.js';
|
|
4
|
+
import { buildCommand as build, runCommand as run, infoCommand as info, checkCommand as check, showcaseCommand as showcase, createCommand as create } from './commands/index.js';
|
|
5
5
|
import { APP_NAME } from './constants.js';
|
|
6
6
|
void yargs(hideBin(process.argv))
|
|
7
7
|
.scriptName(APP_NAME)
|
|
8
8
|
.strict()
|
|
9
9
|
// .usage(Config.usage)
|
|
10
|
+
.command(create.command, create.description, create.builder, create.handler)
|
|
10
11
|
.command(build.command, build.description, build.builder, build.handler)
|
|
11
12
|
.command(run.command, run.description, run.builder, run.handler)
|
|
12
13
|
.command(info.command, info.description, info.builder, info.handler)
|
|
@@ -47,4 +47,11 @@ export interface CliBuildOptions {
|
|
|
47
47
|
* Use --no-console-shim to disable. Only applies to GJS app builds. Default: true.
|
|
48
48
|
*/
|
|
49
49
|
consoleShim?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Comma-separated list of global identifiers your code needs (e.g.
|
|
52
|
+
* `"fetch,Buffer,process,URL,crypto"`). Each identifier is mapped to the
|
|
53
|
+
* corresponding `@gjsify/<pkg>/register` module and injected into the
|
|
54
|
+
* bundle. Only applies to GJS app builds.
|
|
55
|
+
*/
|
|
56
|
+
globals?: string;
|
|
50
57
|
}
|
|
@@ -13,4 +13,9 @@ export interface ConfigData {
|
|
|
13
13
|
* Only applies to GJS app builds. Default: true.
|
|
14
14
|
*/
|
|
15
15
|
consoleShim?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Comma-separated list of global identifiers to register in the bundle.
|
|
18
|
+
* See CliBuildOptions for format.
|
|
19
|
+
*/
|
|
20
|
+
globals?: string;
|
|
16
21
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface ShowcaseInfo {
|
|
2
|
+
/** Short name, e.g. "three-postprocessing-pixel" */
|
|
3
|
+
name: string;
|
|
4
|
+
/** Full npm package name, e.g. "@gjsify/example-dom-three-postprocessing-pixel" */
|
|
5
|
+
packageName: string;
|
|
6
|
+
/** Category: "dom" or "node" */
|
|
7
|
+
category: string;
|
|
8
|
+
/** Description from showcase's package.json */
|
|
9
|
+
description: string;
|
|
10
|
+
/** Absolute path to the GJS bundle (resolved from "main" field) */
|
|
11
|
+
bundlePath: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Discover all installed showcase packages by scanning the CLI's own dependencies.
|
|
15
|
+
* Returns showcases sorted by category then name.
|
|
16
|
+
*/
|
|
17
|
+
export declare function discoverShowcases(): ShowcaseInfo[];
|
|
18
|
+
/** Find a single showcase by short name. */
|
|
19
|
+
export declare function findShowcase(name: string): ShowcaseInfo | undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Dynamic discovery of installed @gjsify/example-*
|
|
1
|
+
// Dynamic discovery of installed showcase packages (@gjsify/example-*).
|
|
2
2
|
// Scans the CLI's own package.json dependencies at runtime.
|
|
3
3
|
import { readFileSync } from 'node:fs';
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
@@ -6,9 +6,8 @@ import { createRequire } from 'node:module';
|
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
const EXAMPLE_PREFIX = '@gjsify/example-';
|
|
8
8
|
/** Extract short name and category from package name. */
|
|
9
|
-
function
|
|
10
|
-
// @gjsify/example-dom-three-
|
|
11
|
-
// @gjsify/example-node-cli-node-path → category=node, name=cli-node-path
|
|
9
|
+
function parseShowcaseName(packageName) {
|
|
10
|
+
// @gjsify/example-dom-three-postprocessing-pixel → category=dom, name=three-postprocessing-pixel
|
|
12
11
|
const suffix = packageName.slice(EXAMPLE_PREFIX.length);
|
|
13
12
|
const dashIdx = suffix.indexOf('-');
|
|
14
13
|
if (dashIdx === -1)
|
|
@@ -19,10 +18,10 @@ function parseExampleName(packageName) {
|
|
|
19
18
|
};
|
|
20
19
|
}
|
|
21
20
|
/**
|
|
22
|
-
* Discover all installed
|
|
23
|
-
* Returns
|
|
21
|
+
* Discover all installed showcase packages by scanning the CLI's own dependencies.
|
|
22
|
+
* Returns showcases sorted by category then name.
|
|
24
23
|
*/
|
|
25
|
-
export function
|
|
24
|
+
export function discoverShowcases() {
|
|
26
25
|
const require = createRequire(import.meta.url);
|
|
27
26
|
const cliPkgPath = join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'package.json');
|
|
28
27
|
let cliPkg;
|
|
@@ -35,11 +34,11 @@ export function discoverExamples() {
|
|
|
35
34
|
const deps = cliPkg['dependencies'];
|
|
36
35
|
if (!deps)
|
|
37
36
|
return [];
|
|
38
|
-
const
|
|
37
|
+
const showcases = [];
|
|
39
38
|
for (const packageName of Object.keys(deps)) {
|
|
40
39
|
if (!packageName.startsWith(EXAMPLE_PREFIX))
|
|
41
40
|
continue;
|
|
42
|
-
const parsed =
|
|
41
|
+
const parsed = parseShowcaseName(packageName);
|
|
43
42
|
if (!parsed)
|
|
44
43
|
continue;
|
|
45
44
|
try {
|
|
@@ -48,7 +47,7 @@ export function discoverExamples() {
|
|
|
48
47
|
const main = pkg['main'];
|
|
49
48
|
if (!main)
|
|
50
49
|
continue;
|
|
51
|
-
|
|
50
|
+
showcases.push({
|
|
52
51
|
name: parsed.name,
|
|
53
52
|
packageName,
|
|
54
53
|
category: parsed.category,
|
|
@@ -60,10 +59,10 @@ export function discoverExamples() {
|
|
|
60
59
|
// Package listed as dep but not resolvable — skip silently
|
|
61
60
|
}
|
|
62
61
|
}
|
|
63
|
-
|
|
64
|
-
return
|
|
62
|
+
showcases.sort((a, b) => a.category.localeCompare(b.category) || a.name.localeCompare(b.name));
|
|
63
|
+
return showcases;
|
|
65
64
|
}
|
|
66
|
-
/** Find a single
|
|
67
|
-
export function
|
|
68
|
-
return
|
|
65
|
+
/** Find a single showcase by short name. */
|
|
66
|
+
export function findShowcase(name) {
|
|
67
|
+
return discoverShowcases().find(e => e.name === name);
|
|
69
68
|
}
|
package/lib/utils/run-gjs.js
CHANGED
|
@@ -29,6 +29,15 @@ export async function runGjsBundle(bundlePath, extraArgs = []) {
|
|
|
29
29
|
...nativeEnv,
|
|
30
30
|
};
|
|
31
31
|
const gjsArgs = ['-m', bundlePath, ...extraArgs];
|
|
32
|
+
// Print the exact command being executed so users can copy-paste it to
|
|
33
|
+
// run gjs directly without the wrapper. Env vars are only shown if we
|
|
34
|
+
// actually set any (i.e. native gjsify packages were detected).
|
|
35
|
+
const envPrefix = Object.entries(nativeEnv)
|
|
36
|
+
.filter(([, value]) => value !== undefined && value !== '')
|
|
37
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
38
|
+
.join(' ');
|
|
39
|
+
const gjsCommand = ['gjs', ...gjsArgs.map(a => a.includes(' ') ? `"${a}"` : a)].join(' ');
|
|
40
|
+
console.log(`$ ${envPrefix ? `${envPrefix} ` : ''}${gjsCommand}`);
|
|
32
41
|
const child = spawn('gjs', gjsArgs, { env, stdio: 'inherit' });
|
|
33
42
|
await new Promise((resolvePromise, reject) => {
|
|
34
43
|
child.on('close', (code) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "CLI for Gjsify",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -23,55 +23,14 @@
|
|
|
23
23
|
"cli"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@gjsify/
|
|
27
|
-
"@gjsify/
|
|
28
|
-
"@gjsify/example-dom-canvas2d-fireworks": "^0.1.
|
|
29
|
-
"@gjsify/example-dom-
|
|
30
|
-
"@gjsify/example-dom-
|
|
31
|
-
"@gjsify/example-
|
|
32
|
-
"@gjsify/
|
|
33
|
-
"@gjsify/
|
|
34
|
-
"@gjsify/example-dom-three-geometry-teapot": "^0.1.7",
|
|
35
|
-
"@gjsify/example-dom-three-loader-ldraw": "^0.1.7",
|
|
36
|
-
"@gjsify/example-dom-three-morphtargets": "^0.1.7",
|
|
37
|
-
"@gjsify/example-dom-three-multiple-rendertargets": "^0.1.7",
|
|
38
|
-
"@gjsify/example-dom-three-postprocessing-pixel": "^0.1.7",
|
|
39
|
-
"@gjsify/example-dom-webgl-demo-fade": "^0.1.7",
|
|
40
|
-
"@gjsify/example-dom-webgl-tutorial-01": "^0.1.7",
|
|
41
|
-
"@gjsify/example-dom-webgl-tutorial-02": "^0.1.7",
|
|
42
|
-
"@gjsify/example-dom-webgl-tutorial-03": "^0.1.7",
|
|
43
|
-
"@gjsify/example-dom-webgl-tutorial-04": "^0.1.7",
|
|
44
|
-
"@gjsify/example-dom-webgl-tutorial-05": "^0.1.7",
|
|
45
|
-
"@gjsify/example-dom-webgl-tutorial-06": "^0.1.7",
|
|
46
|
-
"@gjsify/example-dom-webgl-tutorial-07": "^0.1.7",
|
|
47
|
-
"@gjsify/example-node-cli-deepkit-di": "^0.1.7",
|
|
48
|
-
"@gjsify/example-node-cli-deepkit-events": "^0.1.7",
|
|
49
|
-
"@gjsify/example-node-cli-deepkit-types": "^0.1.7",
|
|
50
|
-
"@gjsify/example-node-cli-deepkit-validation": "^0.1.7",
|
|
51
|
-
"@gjsify/example-node-cli-deepkit-workflow": "^0.1.7",
|
|
52
|
-
"@gjsify/example-node-cli-dns-lookup": "^0.1.7",
|
|
53
|
-
"@gjsify/example-node-cli-esbuild-plugin-deepkit": "^0.1.7",
|
|
54
|
-
"@gjsify/example-node-cli-esbuild-plugin-transform-ext": "^0.1.7",
|
|
55
|
-
"@gjsify/example-node-cli-file-search": "^0.1.7",
|
|
56
|
-
"@gjsify/example-node-cli-gio-cat": "^0.1.7",
|
|
57
|
-
"@gjsify/example-node-cli-json-store": "^0.1.7",
|
|
58
|
-
"@gjsify/example-node-cli-node-buffer": "^0.1.7",
|
|
59
|
-
"@gjsify/example-node-cli-node-events": "^0.1.7",
|
|
60
|
-
"@gjsify/example-node-cli-node-fs": "^0.1.7",
|
|
61
|
-
"@gjsify/example-node-cli-node-os": "^0.1.7",
|
|
62
|
-
"@gjsify/example-node-cli-node-path": "^0.1.7",
|
|
63
|
-
"@gjsify/example-node-cli-node-url": "^0.1.7",
|
|
64
|
-
"@gjsify/example-node-cli-worker-pool": "^0.1.7",
|
|
65
|
-
"@gjsify/example-node-cli-yargs-demo": "^0.1.7",
|
|
66
|
-
"@gjsify/example-node-gtk-http-dashboard": "^0.1.7",
|
|
67
|
-
"@gjsify/example-node-net-express-hello": "^0.1.7",
|
|
68
|
-
"@gjsify/example-node-net-hono-rest": "^0.1.7",
|
|
69
|
-
"@gjsify/example-node-net-koa-blog": "^0.1.7",
|
|
70
|
-
"@gjsify/example-node-net-sse-chat": "^0.1.7",
|
|
71
|
-
"@gjsify/example-node-net-static-file-server": "^0.1.7",
|
|
72
|
-
"@gjsify/example-node-net-ws-chat": "^0.1.7",
|
|
73
|
-
"@gjsify/node-polyfills": "^0.1.7",
|
|
74
|
-
"@gjsify/web-polyfills": "^0.1.7",
|
|
26
|
+
"@gjsify/create-app": "^0.1.8",
|
|
27
|
+
"@gjsify/esbuild-plugin-gjsify": "^0.1.8",
|
|
28
|
+
"@gjsify/example-dom-canvas2d-fireworks": "^0.1.8",
|
|
29
|
+
"@gjsify/example-dom-three-geometry-teapot": "^0.1.8",
|
|
30
|
+
"@gjsify/example-dom-three-postprocessing-pixel": "^0.1.8",
|
|
31
|
+
"@gjsify/example-node-express-webserver": "^0.1.8",
|
|
32
|
+
"@gjsify/node-polyfills": "^0.1.8",
|
|
33
|
+
"@gjsify/web-polyfills": "^0.1.8",
|
|
75
34
|
"cosmiconfig": "^9.0.1",
|
|
76
35
|
"esbuild": "^0.28.0",
|
|
77
36
|
"get-tsconfig": "^4.13.7",
|
package/src/actions/build.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { ConfigData } from '../types/index.js';
|
|
|
2
2
|
import type { App } from '@gjsify/esbuild-plugin-gjsify';
|
|
3
3
|
import { build, BuildOptions, BuildResult } from 'esbuild';
|
|
4
4
|
import { gjsifyPlugin } from '@gjsify/esbuild-plugin-gjsify';
|
|
5
|
+
import { resolveGlobalsList, writeRegisterInjectFile } from '@gjsify/esbuild-plugin-gjsify/globals';
|
|
5
6
|
import { dirname, extname } from 'path';
|
|
6
7
|
|
|
7
8
|
export class BuildAction {
|
|
@@ -74,6 +75,30 @@ export class BuildAction {
|
|
|
74
75
|
return results;
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Resolve the `--globals` CLI list into a pre-computed inject stub path
|
|
80
|
+
* that the esbuild plugin will append to its `inject` list. Only runs
|
|
81
|
+
* for `--app gjs` — Node and browser builds rely on native globals.
|
|
82
|
+
*/
|
|
83
|
+
private async resolveGlobalsInject(
|
|
84
|
+
app: App,
|
|
85
|
+
globals: string | undefined,
|
|
86
|
+
verbose: boolean | undefined,
|
|
87
|
+
): Promise<string | undefined> {
|
|
88
|
+
if (app !== 'gjs' || !globals) return undefined;
|
|
89
|
+
|
|
90
|
+
const registerPaths = resolveGlobalsList(globals);
|
|
91
|
+
if (registerPaths.size === 0) return undefined;
|
|
92
|
+
|
|
93
|
+
const injectPath = await writeRegisterInjectFile(registerPaths, process.cwd());
|
|
94
|
+
if (verbose && injectPath) {
|
|
95
|
+
console.debug(
|
|
96
|
+
`[gjsify] globals: injected ${registerPaths.size} register module(s) from --globals ${globals}`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return injectPath ?? undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
77
102
|
/** Application mode */
|
|
78
103
|
async buildApp(app: App = 'gjs') {
|
|
79
104
|
|
|
@@ -86,22 +111,31 @@ export class BuildAction {
|
|
|
86
111
|
esbuild.outfile = esbuild?.format === 'cjs' ? pgk.main || pgk.module : pgk.module || pgk.main;
|
|
87
112
|
}
|
|
88
113
|
|
|
89
|
-
const { consoleShim } = this.configData;
|
|
114
|
+
const { consoleShim, globals } = this.configData;
|
|
115
|
+
const autoGlobalsInject = await this.resolveGlobalsInject(app, globals, verbose);
|
|
116
|
+
|
|
90
117
|
const result = await build({
|
|
91
118
|
...this.getEsBuildDefaults(),
|
|
92
119
|
...esbuild,
|
|
93
120
|
format,
|
|
94
121
|
plugins: [
|
|
95
|
-
gjsifyPlugin({
|
|
122
|
+
gjsifyPlugin({
|
|
123
|
+
debug: verbose,
|
|
124
|
+
app,
|
|
125
|
+
format,
|
|
126
|
+
exclude,
|
|
127
|
+
reflection: typescript?.reflection,
|
|
128
|
+
consoleShim,
|
|
129
|
+
autoGlobalsInject,
|
|
130
|
+
}),
|
|
96
131
|
]
|
|
97
132
|
});
|
|
98
133
|
|
|
99
134
|
// See https://esbuild.github.io/api/#metafile
|
|
100
|
-
// TODO add cli options for this
|
|
135
|
+
// TODO add cli options for this
|
|
101
136
|
// if(result.metafile) {
|
|
102
137
|
// const outFile = esbuild?.outfile ? esbuild.outfile + '.meta.json' : 'meta.json';
|
|
103
138
|
// await writeFile(outFile, JSON.stringify(result.metafile));
|
|
104
|
-
|
|
105
139
|
// let text = await analyzeMetafile(result.metafile)
|
|
106
140
|
// console.log(text)
|
|
107
141
|
// }
|
package/src/commands/build.ts
CHANGED
|
@@ -88,6 +88,12 @@ export const buildCommand: Command<any, CliBuildOptions> = {
|
|
|
88
88
|
normalize: true,
|
|
89
89
|
default: true
|
|
90
90
|
})
|
|
91
|
+
.option('globals', {
|
|
92
|
+
description: "Comma-separated list of global identifiers your code needs (e.g. 'fetch,Buffer,process,URL,crypto'). Each identifier is mapped to the corresponding `@gjsify/<pkg>/register` module and injected into the bundle. See the CLI Reference docs for the full list of known identifiers. Only applies to GJS app builds.",
|
|
93
|
+
type: 'string',
|
|
94
|
+
normalize: true,
|
|
95
|
+
default: ''
|
|
96
|
+
})
|
|
91
97
|
},
|
|
92
98
|
handler: async (args) => {
|
|
93
99
|
const config = new Config();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createProject } from '@gjsify/create-app';
|
|
2
|
+
import type { Command } from '../types/index.js';
|
|
3
|
+
|
|
4
|
+
interface CreateOptions {
|
|
5
|
+
'project-name': string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const createCommand: Command<any, CreateOptions> = {
|
|
9
|
+
command: 'create [project-name]',
|
|
10
|
+
description: 'Scaffold a new Gjsify project in a new directory.',
|
|
11
|
+
builder: (yargs) => {
|
|
12
|
+
return yargs.positional('project-name', {
|
|
13
|
+
describe: 'Name of the project directory to create',
|
|
14
|
+
type: 'string',
|
|
15
|
+
default: 'my-gjs-app',
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
handler: async (args) => {
|
|
19
|
+
await createProject(args['project-name']);
|
|
20
|
+
},
|
|
21
|
+
};
|
package/src/commands/index.ts
CHANGED
package/src/commands/showcase.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Command } from '../types/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { discoverShowcases, findShowcase } from '../utils/discover-showcases.js';
|
|
3
3
|
import { runMinimalChecks, checkGwebgl, detectPackageManager, buildInstallCommand } from '../utils/check-system-deps.js';
|
|
4
4
|
import { runGjsBundle } from '../utils/run-gjs.js';
|
|
5
5
|
|
|
@@ -11,11 +11,11 @@ interface ShowcaseOptions {
|
|
|
11
11
|
|
|
12
12
|
export const showcaseCommand: Command<any, ShowcaseOptions> = {
|
|
13
13
|
command: 'showcase [name]',
|
|
14
|
-
description: 'List or run built-in gjsify
|
|
14
|
+
description: 'List or run built-in gjsify showcase applications.',
|
|
15
15
|
builder: (yargs) => {
|
|
16
16
|
return yargs
|
|
17
17
|
.positional('name', {
|
|
18
|
-
description: '
|
|
18
|
+
description: 'Showcase name to run (omit to list all)',
|
|
19
19
|
type: 'string',
|
|
20
20
|
})
|
|
21
21
|
.option('json', {
|
|
@@ -24,7 +24,7 @@ export const showcaseCommand: Command<any, ShowcaseOptions> = {
|
|
|
24
24
|
default: false,
|
|
25
25
|
})
|
|
26
26
|
.option('list', {
|
|
27
|
-
description: 'List available
|
|
27
|
+
description: 'List available showcases',
|
|
28
28
|
type: 'boolean',
|
|
29
29
|
default: false,
|
|
30
30
|
});
|
|
@@ -32,54 +32,54 @@ export const showcaseCommand: Command<any, ShowcaseOptions> = {
|
|
|
32
32
|
handler: async (args) => {
|
|
33
33
|
// List mode: no name given, or --list flag
|
|
34
34
|
if (!args.name || args.list) {
|
|
35
|
-
const
|
|
35
|
+
const showcases = discoverShowcases();
|
|
36
36
|
|
|
37
37
|
if (args.json) {
|
|
38
|
-
console.log(JSON.stringify(
|
|
38
|
+
console.log(JSON.stringify(showcases, null, 2));
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
if (
|
|
43
|
-
console.log('No
|
|
42
|
+
if (showcases.length === 0) {
|
|
43
|
+
console.log('No showcases found. Showcase packages may not be installed.');
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// Group by category
|
|
48
|
-
const grouped = new Map<string, typeof
|
|
49
|
-
for (const
|
|
50
|
-
const list = grouped.get(
|
|
51
|
-
list.push(
|
|
52
|
-
grouped.set(
|
|
48
|
+
const grouped = new Map<string, typeof showcases>();
|
|
49
|
+
for (const sc of showcases) {
|
|
50
|
+
const list = grouped.get(sc.category) ?? [];
|
|
51
|
+
list.push(sc);
|
|
52
|
+
grouped.set(sc.category, list);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
console.log('Available gjsify
|
|
55
|
+
console.log('Available gjsify showcases:\n');
|
|
56
56
|
for (const [category, list] of grouped) {
|
|
57
57
|
console.log(` ${category.toUpperCase()}:`);
|
|
58
58
|
const maxNameLen = Math.max(...list.map(e => e.name.length));
|
|
59
|
-
for (const
|
|
60
|
-
const pad = ' '.repeat(maxNameLen -
|
|
61
|
-
const desc =
|
|
62
|
-
console.log(` ${
|
|
59
|
+
for (const sc of list) {
|
|
60
|
+
const pad = ' '.repeat(maxNameLen - sc.name.length + 2);
|
|
61
|
+
const desc = sc.description ? `${pad}${sc.description}` : '';
|
|
62
|
+
console.log(` ${sc.name}${desc}`);
|
|
63
63
|
}
|
|
64
64
|
console.log('');
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
console.log('Run
|
|
67
|
+
console.log('Run a showcase: gjsify showcase <name>');
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
// Run mode: find the
|
|
72
|
-
const
|
|
73
|
-
if (!
|
|
74
|
-
console.error(`Unknown
|
|
75
|
-
console.error('Run "gjsify showcase" to list available
|
|
71
|
+
// Run mode: find the showcase
|
|
72
|
+
const showcase = findShowcase(args.name);
|
|
73
|
+
if (!showcase) {
|
|
74
|
+
console.error(`Unknown showcase: "${args.name}"`);
|
|
75
|
+
console.error('Run "gjsify showcase" to list available showcases.');
|
|
76
76
|
process.exit(1);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
// System dependency check before running — only check what this
|
|
80
|
-
// All
|
|
79
|
+
// System dependency check before running — only check what this showcase needs.
|
|
80
|
+
// All showcases need GJS; WebGL showcases additionally need gwebgl prebuilds.
|
|
81
81
|
const results = runMinimalChecks();
|
|
82
|
-
const needsWebgl =
|
|
82
|
+
const needsWebgl = showcase.packageName.includes('webgl') || showcase.packageName.includes('three');
|
|
83
83
|
if (needsWebgl) {
|
|
84
84
|
results.push(checkGwebgl(process.cwd()));
|
|
85
85
|
}
|
|
@@ -97,8 +97,8 @@ export const showcaseCommand: Command<any, ShowcaseOptions> = {
|
|
|
97
97
|
process.exit(1);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
// Run the
|
|
101
|
-
console.log(`Running
|
|
102
|
-
await runGjsBundle(
|
|
100
|
+
// Run the showcase via shared GJS runner
|
|
101
|
+
console.log(`Running showcase: ${showcase.name}\n`);
|
|
102
|
+
await runGjsBundle(showcase.bundlePath);
|
|
103
103
|
},
|
|
104
104
|
};
|
package/src/config.ts
CHANGED
|
@@ -82,6 +82,7 @@ export class Config {
|
|
|
82
82
|
configData.verbose = cliArgs.verbose || false;
|
|
83
83
|
configData.exclude = cliArgs.exclude || [];
|
|
84
84
|
if (cliArgs.consoleShim !== undefined) configData.consoleShim = cliArgs.consoleShim;
|
|
85
|
+
if (cliArgs.globals !== undefined) configData.globals = cliArgs.globals;
|
|
85
86
|
|
|
86
87
|
merge(configData.library ??= {}, pkg, configData.library);
|
|
87
88
|
merge(configData.typescript ??= {}, tsConfig, configData.typescript);
|
package/src/index.ts
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
import yargs from 'yargs'
|
|
3
3
|
import { hideBin } from 'yargs/helpers'
|
|
4
4
|
|
|
5
|
-
import { buildCommand as build, runCommand as run, infoCommand as info, checkCommand as check, showcaseCommand as showcase } from './commands/index.js'
|
|
5
|
+
import { buildCommand as build, runCommand as run, infoCommand as info, checkCommand as check, showcaseCommand as showcase, createCommand as create } from './commands/index.js'
|
|
6
6
|
import { APP_NAME } from './constants.js'
|
|
7
7
|
|
|
8
8
|
void yargs(hideBin(process.argv))
|
|
9
9
|
.scriptName(APP_NAME)
|
|
10
10
|
.strict()
|
|
11
11
|
// .usage(Config.usage)
|
|
12
|
+
.command(create.command, create.description, create.builder, create.handler)
|
|
12
13
|
.command(build.command, build.description, build.builder, build.handler)
|
|
13
14
|
.command(run.command, run.description, run.builder, run.handler)
|
|
14
15
|
.command(info.command, info.description, info.builder, info.handler)
|
|
@@ -48,4 +48,11 @@ export interface CliBuildOptions {
|
|
|
48
48
|
* Use --no-console-shim to disable. Only applies to GJS app builds. Default: true.
|
|
49
49
|
*/
|
|
50
50
|
consoleShim?: boolean;
|
|
51
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Comma-separated list of global identifiers your code needs (e.g.
|
|
53
|
+
* `"fetch,Buffer,process,URL,crypto"`). Each identifier is mapped to the
|
|
54
|
+
* corresponding `@gjsify/<pkg>/register` module and injected into the
|
|
55
|
+
* bundle. Only applies to GJS app builds.
|
|
56
|
+
*/
|
|
57
|
+
globals?: string;
|
|
58
|
+
}
|
package/src/types/config-data.ts
CHANGED
|
@@ -14,4 +14,9 @@ export interface ConfigData {
|
|
|
14
14
|
* Only applies to GJS app builds. Default: true.
|
|
15
15
|
*/
|
|
16
16
|
consoleShim?: boolean;
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Comma-separated list of global identifiers to register in the bundle.
|
|
19
|
+
* See CliBuildOptions for format.
|
|
20
|
+
*/
|
|
21
|
+
globals?: string;
|
|
22
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Dynamic discovery of installed @gjsify/example-*
|
|
1
|
+
// Dynamic discovery of installed showcase packages (@gjsify/example-*).
|
|
2
2
|
// Scans the CLI's own package.json dependencies at runtime.
|
|
3
3
|
|
|
4
4
|
import { readFileSync } from 'node:fs';
|
|
@@ -6,14 +6,14 @@ import { dirname, join } from 'node:path';
|
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
8
|
|
|
9
|
-
export interface
|
|
10
|
-
/** Short name, e.g. "three-
|
|
9
|
+
export interface ShowcaseInfo {
|
|
10
|
+
/** Short name, e.g. "three-postprocessing-pixel" */
|
|
11
11
|
name: string;
|
|
12
|
-
/** Full npm package name, e.g. "@gjsify/example-dom-three-
|
|
12
|
+
/** Full npm package name, e.g. "@gjsify/example-dom-three-postprocessing-pixel" */
|
|
13
13
|
packageName: string;
|
|
14
14
|
/** Category: "dom" or "node" */
|
|
15
15
|
category: string;
|
|
16
|
-
/** Description from
|
|
16
|
+
/** Description from showcase's package.json */
|
|
17
17
|
description: string;
|
|
18
18
|
/** Absolute path to the GJS bundle (resolved from "main" field) */
|
|
19
19
|
bundlePath: string;
|
|
@@ -22,9 +22,8 @@ export interface ExampleInfo {
|
|
|
22
22
|
const EXAMPLE_PREFIX = '@gjsify/example-';
|
|
23
23
|
|
|
24
24
|
/** Extract short name and category from package name. */
|
|
25
|
-
function
|
|
26
|
-
// @gjsify/example-dom-three-
|
|
27
|
-
// @gjsify/example-node-cli-node-path → category=node, name=cli-node-path
|
|
25
|
+
function parseShowcaseName(packageName: string): { name: string; category: string } | null {
|
|
26
|
+
// @gjsify/example-dom-three-postprocessing-pixel → category=dom, name=three-postprocessing-pixel
|
|
28
27
|
const suffix = packageName.slice(EXAMPLE_PREFIX.length);
|
|
29
28
|
const dashIdx = suffix.indexOf('-');
|
|
30
29
|
if (dashIdx === -1) return null;
|
|
@@ -35,10 +34,10 @@ function parseExampleName(packageName: string): { name: string; category: string
|
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
/**
|
|
38
|
-
* Discover all installed
|
|
39
|
-
* Returns
|
|
37
|
+
* Discover all installed showcase packages by scanning the CLI's own dependencies.
|
|
38
|
+
* Returns showcases sorted by category then name.
|
|
40
39
|
*/
|
|
41
|
-
export function
|
|
40
|
+
export function discoverShowcases(): ShowcaseInfo[] {
|
|
42
41
|
const require = createRequire(import.meta.url);
|
|
43
42
|
const cliPkgPath = join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'package.json');
|
|
44
43
|
let cliPkg: Record<string, unknown>;
|
|
@@ -51,12 +50,12 @@ export function discoverExamples(): ExampleInfo[] {
|
|
|
51
50
|
const deps = cliPkg['dependencies'] as Record<string, string> | undefined;
|
|
52
51
|
if (!deps) return [];
|
|
53
52
|
|
|
54
|
-
const
|
|
53
|
+
const showcases: ShowcaseInfo[] = [];
|
|
55
54
|
|
|
56
55
|
for (const packageName of Object.keys(deps)) {
|
|
57
56
|
if (!packageName.startsWith(EXAMPLE_PREFIX)) continue;
|
|
58
57
|
|
|
59
|
-
const parsed =
|
|
58
|
+
const parsed = parseShowcaseName(packageName);
|
|
60
59
|
if (!parsed) continue;
|
|
61
60
|
|
|
62
61
|
try {
|
|
@@ -65,7 +64,7 @@ export function discoverExamples(): ExampleInfo[] {
|
|
|
65
64
|
const main = pkg['main'] as string | undefined;
|
|
66
65
|
if (!main) continue;
|
|
67
66
|
|
|
68
|
-
|
|
67
|
+
showcases.push({
|
|
69
68
|
name: parsed.name,
|
|
70
69
|
packageName,
|
|
71
70
|
category: parsed.category,
|
|
@@ -77,11 +76,11 @@ export function discoverExamples(): ExampleInfo[] {
|
|
|
77
76
|
}
|
|
78
77
|
}
|
|
79
78
|
|
|
80
|
-
|
|
81
|
-
return
|
|
79
|
+
showcases.sort((a, b) => a.category.localeCompare(b.category) || a.name.localeCompare(b.name));
|
|
80
|
+
return showcases;
|
|
82
81
|
}
|
|
83
82
|
|
|
84
|
-
/** Find a single
|
|
85
|
-
export function
|
|
86
|
-
return
|
|
83
|
+
/** Find a single showcase by short name. */
|
|
84
|
+
export function findShowcase(name: string): ShowcaseInfo | undefined {
|
|
85
|
+
return discoverShowcases().find(e => e.name === name);
|
|
87
86
|
}
|
package/src/utils/run-gjs.ts
CHANGED
|
@@ -36,6 +36,17 @@ export async function runGjsBundle(bundlePath: string, extraArgs: string[] = [])
|
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
const gjsArgs = ['-m', bundlePath, ...extraArgs];
|
|
39
|
+
|
|
40
|
+
// Print the exact command being executed so users can copy-paste it to
|
|
41
|
+
// run gjs directly without the wrapper. Env vars are only shown if we
|
|
42
|
+
// actually set any (i.e. native gjsify packages were detected).
|
|
43
|
+
const envPrefix = Object.entries(nativeEnv)
|
|
44
|
+
.filter(([, value]) => value !== undefined && value !== '')
|
|
45
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
46
|
+
.join(' ');
|
|
47
|
+
const gjsCommand = ['gjs', ...gjsArgs.map(a => a.includes(' ') ? `"${a}"` : a)].join(' ');
|
|
48
|
+
console.log(`$ ${envPrefix ? `${envPrefix} ` : ''}${gjsCommand}`);
|
|
49
|
+
|
|
39
50
|
const child = spawn('gjs', gjsArgs, { env, stdio: 'inherit' });
|
|
40
51
|
|
|
41
52
|
await new Promise<void>((resolvePromise, reject) => {
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export interface ExampleInfo {
|
|
2
|
-
/** Short name, e.g. "three-geometry-shapes" */
|
|
3
|
-
name: string;
|
|
4
|
-
/** Full npm package name, e.g. "@gjsify/example-dom-three-geometry-shapes" */
|
|
5
|
-
packageName: string;
|
|
6
|
-
/** Category: "dom" or "node" */
|
|
7
|
-
category: string;
|
|
8
|
-
/** Description from example's package.json */
|
|
9
|
-
description: string;
|
|
10
|
-
/** Absolute path to the GJS bundle (resolved from "main" field) */
|
|
11
|
-
bundlePath: string;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Discover all installed example packages by scanning the CLI's own dependencies.
|
|
15
|
-
* Returns examples sorted by category then name.
|
|
16
|
-
*/
|
|
17
|
-
export declare function discoverExamples(): ExampleInfo[];
|
|
18
|
-
/** Find a single example by short name. */
|
|
19
|
-
export declare function findExample(name: string): ExampleInfo | undefined;
|