@gjsify/cli 0.3.2 → 0.3.4
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 +3 -3
- package/lib/actions/build.js +144 -30
- package/package.json +10 -10
- package/src/actions/build.ts +421 -264
package/lib/actions/build.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { ConfigData } from
|
|
2
|
-
import type { App } from
|
|
3
|
-
import { BuildOptions, BuildResult, Plugin } from
|
|
1
|
+
import type { ConfigData } from "../types/index.js";
|
|
2
|
+
import type { App } from "@gjsify/esbuild-plugin-gjsify";
|
|
3
|
+
import { BuildOptions, BuildResult, Plugin } from "esbuild";
|
|
4
4
|
export declare class BuildAction {
|
|
5
5
|
readonly configData: ConfigData;
|
|
6
6
|
constructor(configData?: ConfigData);
|
package/lib/actions/build.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { build } from
|
|
2
|
-
import { gjsifyPlugin } from
|
|
3
|
-
import { resolveGlobalsList, writeRegisterInjectFile, detectAutoGlobals } from
|
|
4
|
-
import { dirname, extname, join } from
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { build } from "esbuild";
|
|
2
|
+
import { gjsifyPlugin } from "@gjsify/esbuild-plugin-gjsify";
|
|
3
|
+
import { resolveGlobalsList, writeRegisterInjectFile, detectAutoGlobals, } from "@gjsify/esbuild-plugin-gjsify/globals";
|
|
4
|
+
import { dirname, extname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { chmod, readFile, writeFile } from "node:fs/promises";
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
import { createRequire } from "node:module";
|
|
7
9
|
const GJS_SHEBANG = "#!/usr/bin/env -S gjs -m\n";
|
|
8
10
|
/** Walk up from dir until .pnp.cjs is found; return its directory or null. */
|
|
9
11
|
function findPnpRoot(dir) {
|
|
@@ -21,13 +23,87 @@ function findPnpRoot(dir) {
|
|
|
21
23
|
* If the current project uses Yarn PnP, return the official
|
|
22
24
|
* @yarnpkg/esbuild-plugin-pnp plugin so esbuild can resolve
|
|
23
25
|
* modules from zip archives without manual extraction.
|
|
26
|
+
*
|
|
27
|
+
* Custom onResolve: when the project's PnP context throws
|
|
28
|
+
* UNDECLARED_DEPENDENCY, retry via a two-hop relay:
|
|
29
|
+
* 1. @gjsify/cli context (direct dep of the project using gjsify build)
|
|
30
|
+
* 2. @gjsify/node-polyfills context (direct dep of @gjsify/cli, has all
|
|
31
|
+
* node polyfills as direct deps including @gjsify/node-globals)
|
|
32
|
+
* 3. @gjsify/web-polyfills context (direct dep of @gjsify/cli, has all
|
|
33
|
+
* web polyfills as direct deps including @gjsify/fetch, @gjsify/abort-controller)
|
|
34
|
+
* For bare specifiers that the gjsify alias plugin maps (e.g. `abort-controller`),
|
|
35
|
+
* fall through so that plugin can handle the transformation first.
|
|
24
36
|
*/
|
|
25
37
|
async function getPnpPlugin() {
|
|
26
38
|
if (!findPnpRoot(process.cwd()))
|
|
27
39
|
return null;
|
|
28
40
|
try {
|
|
29
41
|
const { pnpPlugin } = await import("@yarnpkg/esbuild-plugin-pnp");
|
|
30
|
-
|
|
42
|
+
// gjsify's own file path — @gjsify/cli has node-polyfills + web-polyfills
|
|
43
|
+
// as direct deps, so we can resolve them as relay issuers from here.
|
|
44
|
+
const gjsifyIssuer = fileURLToPath(import.meta.url);
|
|
45
|
+
// Two-hop relay: node-polyfills and web-polyfills have all individual
|
|
46
|
+
// @gjsify/* packages as direct deps. Resolving from their paths allows
|
|
47
|
+
// PnP to reach e.g. @gjsify/node-globals (dep of node-polyfills).
|
|
48
|
+
const requireFromGjsify = createRequire(gjsifyIssuer);
|
|
49
|
+
const relayIssuers = [];
|
|
50
|
+
for (const pkg of ["@gjsify/node-polyfills", "@gjsify/web-polyfills"]) {
|
|
51
|
+
try {
|
|
52
|
+
relayIssuers.push(requireFromGjsify.resolve(pkg));
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// polyfills package not in dep tree — relay won't cover it
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
let pnpApi = null;
|
|
59
|
+
try {
|
|
60
|
+
// pnpapi has no npm package — it is a virtual module injected by Yarn PnP
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
62
|
+
// @ts-expect-error
|
|
63
|
+
pnpApi = (await import("pnpapi"));
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Not in a PnP runtime (shouldn't happen since findPnpRoot passed)
|
|
67
|
+
}
|
|
68
|
+
return pnpPlugin({
|
|
69
|
+
onResolve: async (args, { resolvedPath, error, watchFiles }) => {
|
|
70
|
+
if (resolvedPath !== null) {
|
|
71
|
+
return { namespace: "pnp", path: resolvedPath, watchFiles };
|
|
72
|
+
}
|
|
73
|
+
if (error?.pnpCode ===
|
|
74
|
+
"UNDECLARED_DEPENDENCY") {
|
|
75
|
+
if (pnpApi !== null) {
|
|
76
|
+
// Try @gjsify/cli context first (covers @gjsify/* that are
|
|
77
|
+
// direct deps of cli's own deps — unlikely but fast check).
|
|
78
|
+
try {
|
|
79
|
+
const rp = pnpApi.resolveRequest(args.path, gjsifyIssuer);
|
|
80
|
+
if (rp !== null)
|
|
81
|
+
return { namespace: "pnp", path: rp, watchFiles };
|
|
82
|
+
}
|
|
83
|
+
catch { }
|
|
84
|
+
// Two-hop relay: resolve from node-polyfills / web-polyfills context
|
|
85
|
+
// which have the individual @gjsify/* packages as direct deps.
|
|
86
|
+
for (const relayIssuer of relayIssuers) {
|
|
87
|
+
try {
|
|
88
|
+
const rp = pnpApi.resolveRequest(args.path, relayIssuer);
|
|
89
|
+
if (rp !== null)
|
|
90
|
+
return { namespace: "pnp", path: rp, watchFiles };
|
|
91
|
+
}
|
|
92
|
+
catch { }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Fall through — bare aliases (abort-controller, fetch/register/*)
|
|
96
|
+
// are handled by the gjsify alias plugin after this returns null,
|
|
97
|
+
// then the re-resolved @gjsify/* path goes through this hook again.
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
external: true,
|
|
102
|
+
errors: error ? [{ text: error.message }] : [],
|
|
103
|
+
watchFiles,
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
});
|
|
31
107
|
}
|
|
32
108
|
catch {
|
|
33
109
|
return null;
|
|
@@ -40,7 +116,7 @@ export class BuildAction {
|
|
|
40
116
|
}
|
|
41
117
|
getEsBuildDefaults() {
|
|
42
118
|
const defaults = {
|
|
43
|
-
allowOverwrite: true
|
|
119
|
+
allowOverwrite: true,
|
|
44
120
|
};
|
|
45
121
|
return defaults;
|
|
46
122
|
}
|
|
@@ -59,7 +135,9 @@ export class BuildAction {
|
|
|
59
135
|
const pnpPlugins = pnpPlugin ? [pnpPlugin] : [];
|
|
60
136
|
const results = [];
|
|
61
137
|
if (multipleBuilds) {
|
|
62
|
-
const moduleFormat = moduleOutdir.includes("/cjs") || moduleOutExt === ".cjs"
|
|
138
|
+
const moduleFormat = moduleOutdir.includes("/cjs") || moduleOutExt === ".cjs"
|
|
139
|
+
? "cjs"
|
|
140
|
+
: "esm";
|
|
63
141
|
results.push(await build({
|
|
64
142
|
...this.getEsBuildDefaults(),
|
|
65
143
|
...esbuild,
|
|
@@ -67,7 +145,13 @@ export class BuildAction {
|
|
|
67
145
|
outdir: moduleOutdir,
|
|
68
146
|
plugins: [
|
|
69
147
|
...pnpPlugins,
|
|
70
|
-
gjsifyPlugin({
|
|
148
|
+
gjsifyPlugin({
|
|
149
|
+
debug: verbose,
|
|
150
|
+
library: moduleFormat,
|
|
151
|
+
exclude,
|
|
152
|
+
reflection: typescript?.reflection,
|
|
153
|
+
jsExtension: moduleOutExt,
|
|
154
|
+
}),
|
|
71
155
|
],
|
|
72
156
|
}));
|
|
73
157
|
const mainFormat = mainOutdir.includes("/cjs") || mainOutExt === ".cjs" ? "cjs" : "esm";
|
|
@@ -78,7 +162,13 @@ export class BuildAction {
|
|
|
78
162
|
outdir: mainOutdir,
|
|
79
163
|
plugins: [
|
|
80
164
|
...pnpPlugins,
|
|
81
|
-
gjsifyPlugin({
|
|
165
|
+
gjsifyPlugin({
|
|
166
|
+
debug: verbose,
|
|
167
|
+
library: mainFormat,
|
|
168
|
+
exclude,
|
|
169
|
+
reflection: typescript?.reflection,
|
|
170
|
+
jsExtension: mainOutdir,
|
|
171
|
+
}),
|
|
82
172
|
],
|
|
83
173
|
}));
|
|
84
174
|
}
|
|
@@ -86,7 +176,8 @@ export class BuildAction {
|
|
|
86
176
|
const outfilePath = esbuild?.outfile || library?.module || library?.main;
|
|
87
177
|
const outExt = outfilePath ? extname(outfilePath) : ".js";
|
|
88
178
|
const outdir = esbuild?.outdir || (outfilePath ? dirname(outfilePath) : undefined);
|
|
89
|
-
const format = esbuild?.format ??
|
|
179
|
+
const format = esbuild?.format ??
|
|
180
|
+
(outdir?.includes("/cjs") || outExt === ".cjs" ? "cjs" : "esm");
|
|
90
181
|
results.push(await build({
|
|
91
182
|
...this.getEsBuildDefaults(),
|
|
92
183
|
...esbuild,
|
|
@@ -94,7 +185,13 @@ export class BuildAction {
|
|
|
94
185
|
outdir,
|
|
95
186
|
plugins: [
|
|
96
187
|
...pnpPlugins,
|
|
97
|
-
gjsifyPlugin({
|
|
188
|
+
gjsifyPlugin({
|
|
189
|
+
debug: verbose,
|
|
190
|
+
library: format,
|
|
191
|
+
exclude,
|
|
192
|
+
reflection: typescript?.reflection,
|
|
193
|
+
jsExtension: outExt,
|
|
194
|
+
}),
|
|
98
195
|
],
|
|
99
196
|
}));
|
|
100
197
|
}
|
|
@@ -111,12 +208,15 @@ export class BuildAction {
|
|
|
111
208
|
*/
|
|
112
209
|
parseGlobalsValue(value) {
|
|
113
210
|
if (value === undefined)
|
|
114
|
-
return { autoMode: true, extras:
|
|
115
|
-
if (value ===
|
|
116
|
-
return { autoMode: false, extras:
|
|
117
|
-
const tokens = value
|
|
118
|
-
|
|
119
|
-
|
|
211
|
+
return { autoMode: true, extras: "" };
|
|
212
|
+
if (value === "none" || value === "")
|
|
213
|
+
return { autoMode: false, extras: "" };
|
|
214
|
+
const tokens = value
|
|
215
|
+
.split(",")
|
|
216
|
+
.map((t) => t.trim())
|
|
217
|
+
.filter(Boolean);
|
|
218
|
+
const hasAuto = tokens.includes("auto");
|
|
219
|
+
const extras = tokens.filter((t) => t !== "auto").join(",");
|
|
120
220
|
return { autoMode: hasAuto, extras };
|
|
121
221
|
}
|
|
122
222
|
/**
|
|
@@ -128,7 +228,7 @@ export class BuildAction {
|
|
|
128
228
|
* The auto path is handled in `buildApp` via the two-pass build.
|
|
129
229
|
*/
|
|
130
230
|
async resolveGlobalsInject(app, globals, verbose) {
|
|
131
|
-
if (app !==
|
|
231
|
+
if (app !== "gjs")
|
|
132
232
|
return undefined;
|
|
133
233
|
if (!globals)
|
|
134
234
|
return undefined;
|
|
@@ -148,11 +248,11 @@ export class BuildAction {
|
|
|
148
248
|
async applyShebang(outfile, verbose) {
|
|
149
249
|
if (!outfile) {
|
|
150
250
|
if (verbose)
|
|
151
|
-
console.warn(
|
|
251
|
+
console.warn("[gjsify] --shebang skipped: no single outfile (use --outfile for GJS executables)");
|
|
152
252
|
return;
|
|
153
253
|
}
|
|
154
|
-
const content = await readFile(outfile,
|
|
155
|
-
if (content.startsWith(
|
|
254
|
+
const content = await readFile(outfile, "utf-8");
|
|
255
|
+
if (content.startsWith("#!")) {
|
|
156
256
|
if (verbose)
|
|
157
257
|
console.debug(`[gjsify] --shebang skipped: ${outfile} already starts with a shebang`);
|
|
158
258
|
}
|
|
@@ -165,11 +265,18 @@ export class BuildAction {
|
|
|
165
265
|
}
|
|
166
266
|
/** Application mode */
|
|
167
267
|
async buildApp(app = "gjs") {
|
|
168
|
-
const { verbose, esbuild, typescript, exclude, library: pgk, aliases, excludeGlobals } = this.configData;
|
|
169
|
-
const format = esbuild?.format ??
|
|
268
|
+
const { verbose, esbuild, typescript, exclude, library: pgk, aliases, excludeGlobals, } = this.configData;
|
|
269
|
+
const format = esbuild?.format ??
|
|
270
|
+
(esbuild?.outfile?.endsWith(".cjs") ? "cjs" : "esm");
|
|
170
271
|
// Set default outfile if no outdir is set
|
|
171
|
-
if (esbuild &&
|
|
172
|
-
esbuild
|
|
272
|
+
if (esbuild &&
|
|
273
|
+
!esbuild?.outfile &&
|
|
274
|
+
!esbuild?.outdir &&
|
|
275
|
+
(pgk?.main || pgk?.module)) {
|
|
276
|
+
esbuild.outfile =
|
|
277
|
+
esbuild?.format === "cjs"
|
|
278
|
+
? pgk.main || pgk.module
|
|
279
|
+
: pgk.module || pgk.main;
|
|
173
280
|
}
|
|
174
281
|
const { consoleShim, globals } = this.configData;
|
|
175
282
|
const pluginOpts = {
|
|
@@ -189,7 +296,12 @@ export class BuildAction {
|
|
|
189
296
|
// statically see a global (e.g. Excalibur indirects globalThis via
|
|
190
297
|
// BrowserComponent.nativeComponent). Common pattern: --globals auto,dom
|
|
191
298
|
if (app === "gjs" && autoMode) {
|
|
192
|
-
const { injectPath } = await detectAutoGlobals({
|
|
299
|
+
const { injectPath } = await detectAutoGlobals({
|
|
300
|
+
...this.getEsBuildDefaults(),
|
|
301
|
+
...esbuild,
|
|
302
|
+
format,
|
|
303
|
+
plugins: pnpPlugins,
|
|
304
|
+
}, pluginOpts, verbose, { extraGlobalsList: extras, excludeGlobals });
|
|
193
305
|
const result = await build({
|
|
194
306
|
...this.getEsBuildDefaults(),
|
|
195
307
|
...esbuild,
|
|
@@ -208,7 +320,9 @@ export class BuildAction {
|
|
|
208
320
|
return [result];
|
|
209
321
|
}
|
|
210
322
|
// --- Explicit list (no `auto` token) or none mode ---
|
|
211
|
-
const autoGlobalsInject = extras
|
|
323
|
+
const autoGlobalsInject = extras
|
|
324
|
+
? await this.resolveGlobalsInject(app, extras, verbose)
|
|
325
|
+
: undefined;
|
|
212
326
|
const result = await build({
|
|
213
327
|
...this.getEsBuildDefaults(),
|
|
214
328
|
...esbuild,
|
|
@@ -226,7 +340,7 @@ export class BuildAction {
|
|
|
226
340
|
}
|
|
227
341
|
return [result];
|
|
228
342
|
}
|
|
229
|
-
async start(buildType = { app:
|
|
343
|
+
async start(buildType = { app: "gjs" }) {
|
|
230
344
|
const results = [];
|
|
231
345
|
if (buildType.library) {
|
|
232
346
|
results.push(...(await this.buildLibrary()));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "CLI for Gjsify",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -23,15 +23,15 @@
|
|
|
23
23
|
"cli"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@gjsify/create-app": "^0.3.
|
|
27
|
-
"@gjsify/esbuild-plugin-gjsify": "^0.3.
|
|
28
|
-
"@gjsify/example-dom-canvas2d-fireworks": "^0.3.
|
|
29
|
-
"@gjsify/example-dom-excalibur-jelly-jumper": "^0.3.
|
|
30
|
-
"@gjsify/example-dom-three-geometry-teapot": "^0.3.
|
|
31
|
-
"@gjsify/example-dom-three-postprocessing-pixel": "^0.3.
|
|
32
|
-
"@gjsify/example-node-express-webserver": "^0.3.
|
|
33
|
-
"@gjsify/node-polyfills": "^0.3.
|
|
34
|
-
"@gjsify/web-polyfills": "^0.3.
|
|
26
|
+
"@gjsify/create-app": "^0.3.4",
|
|
27
|
+
"@gjsify/esbuild-plugin-gjsify": "^0.3.4",
|
|
28
|
+
"@gjsify/example-dom-canvas2d-fireworks": "^0.3.4",
|
|
29
|
+
"@gjsify/example-dom-excalibur-jelly-jumper": "^0.3.4",
|
|
30
|
+
"@gjsify/example-dom-three-geometry-teapot": "^0.3.4",
|
|
31
|
+
"@gjsify/example-dom-three-postprocessing-pixel": "^0.3.4",
|
|
32
|
+
"@gjsify/example-node-express-webserver": "^0.3.4",
|
|
33
|
+
"@gjsify/node-polyfills": "^0.3.4",
|
|
34
|
+
"@gjsify/web-polyfills": "^0.3.4",
|
|
35
35
|
"@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.15",
|
|
36
36
|
"cosmiconfig": "^9.0.1",
|
|
37
37
|
"esbuild": "^0.28.0",
|
package/src/actions/build.ts
CHANGED
|
@@ -1,280 +1,437 @@
|
|
|
1
|
-
import type { ConfigData } from
|
|
2
|
-
import type { App } from
|
|
3
|
-
import { build, BuildOptions, BuildResult, Plugin } from
|
|
4
|
-
import { gjsifyPlugin } from
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import type { ConfigData } from "../types/index.js";
|
|
2
|
+
import type { App } from "@gjsify/esbuild-plugin-gjsify";
|
|
3
|
+
import { build, BuildOptions, BuildResult, Plugin } from "esbuild";
|
|
4
|
+
import { gjsifyPlugin } from "@gjsify/esbuild-plugin-gjsify";
|
|
5
|
+
import {
|
|
6
|
+
resolveGlobalsList,
|
|
7
|
+
writeRegisterInjectFile,
|
|
8
|
+
detectAutoGlobals,
|
|
9
|
+
} from "@gjsify/esbuild-plugin-gjsify/globals";
|
|
10
|
+
import { dirname, extname, join } from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
import { chmod, readFile, writeFile } from "node:fs/promises";
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { createRequire } from "node:module";
|
|
9
15
|
|
|
10
16
|
const GJS_SHEBANG = "#!/usr/bin/env -S gjs -m\n";
|
|
11
17
|
|
|
12
18
|
/** Walk up from dir until .pnp.cjs is found; return its directory or null. */
|
|
13
19
|
function findPnpRoot(dir: string): string | null {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
let current = dir;
|
|
21
|
+
while (true) {
|
|
22
|
+
if (existsSync(join(current, ".pnp.cjs"))) return current;
|
|
23
|
+
const parent = dirname(current);
|
|
24
|
+
if (parent === current) return null;
|
|
25
|
+
current = parent;
|
|
26
|
+
}
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
/**
|
|
24
30
|
* If the current project uses Yarn PnP, return the official
|
|
25
31
|
* @yarnpkg/esbuild-plugin-pnp plugin so esbuild can resolve
|
|
26
32
|
* modules from zip archives without manual extraction.
|
|
33
|
+
*
|
|
34
|
+
* Custom onResolve: when the project's PnP context throws
|
|
35
|
+
* UNDECLARED_DEPENDENCY, retry via a two-hop relay:
|
|
36
|
+
* 1. @gjsify/cli context (direct dep of the project using gjsify build)
|
|
37
|
+
* 2. @gjsify/node-polyfills context (direct dep of @gjsify/cli, has all
|
|
38
|
+
* node polyfills as direct deps including @gjsify/node-globals)
|
|
39
|
+
* 3. @gjsify/web-polyfills context (direct dep of @gjsify/cli, has all
|
|
40
|
+
* web polyfills as direct deps including @gjsify/fetch, @gjsify/abort-controller)
|
|
41
|
+
* For bare specifiers that the gjsify alias plugin maps (e.g. `abort-controller`),
|
|
42
|
+
* fall through so that plugin can handle the transformation first.
|
|
27
43
|
*/
|
|
28
44
|
async function getPnpPlugin(): Promise<Plugin | null> {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
if (!findPnpRoot(process.cwd())) return null;
|
|
46
|
+
try {
|
|
47
|
+
const { pnpPlugin } = await import("@yarnpkg/esbuild-plugin-pnp");
|
|
48
|
+
|
|
49
|
+
// gjsify's own file path — @gjsify/cli has node-polyfills + web-polyfills
|
|
50
|
+
// as direct deps, so we can resolve them as relay issuers from here.
|
|
51
|
+
const gjsifyIssuer = fileURLToPath(import.meta.url);
|
|
52
|
+
|
|
53
|
+
// Two-hop relay: node-polyfills and web-polyfills have all individual
|
|
54
|
+
// @gjsify/* packages as direct deps. Resolving from their paths allows
|
|
55
|
+
// PnP to reach e.g. @gjsify/node-globals (dep of node-polyfills).
|
|
56
|
+
const requireFromGjsify = createRequire(gjsifyIssuer);
|
|
57
|
+
const relayIssuers: string[] = [];
|
|
58
|
+
for (const pkg of ["@gjsify/node-polyfills", "@gjsify/web-polyfills"]) {
|
|
59
|
+
try {
|
|
60
|
+
relayIssuers.push(requireFromGjsify.resolve(pkg));
|
|
61
|
+
} catch {
|
|
62
|
+
// polyfills package not in dep tree — relay won't cover it
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// pnpapi is a virtual module injected by Yarn PnP at runtime.
|
|
67
|
+
type PnpApi = {
|
|
68
|
+
resolveRequest: (req: string, issuer: string) => string | null;
|
|
69
|
+
};
|
|
70
|
+
let pnpApi: PnpApi | null = null;
|
|
71
|
+
try {
|
|
72
|
+
// pnpapi has no npm package — it is a virtual module injected by Yarn PnP
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
74
|
+
// @ts-expect-error
|
|
75
|
+
pnpApi = (await import("pnpapi")) as PnpApi;
|
|
76
|
+
} catch {
|
|
77
|
+
// Not in a PnP runtime (shouldn't happen since findPnpRoot passed)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return pnpPlugin({
|
|
81
|
+
onResolve: async (args, { resolvedPath, error, watchFiles }) => {
|
|
82
|
+
if (resolvedPath !== null) {
|
|
83
|
+
return { namespace: "pnp", path: resolvedPath, watchFiles };
|
|
84
|
+
}
|
|
85
|
+
if (
|
|
86
|
+
(error as { pnpCode?: string } | null)?.pnpCode ===
|
|
87
|
+
"UNDECLARED_DEPENDENCY"
|
|
88
|
+
) {
|
|
89
|
+
if (pnpApi !== null) {
|
|
90
|
+
// Try @gjsify/cli context first (covers @gjsify/* that are
|
|
91
|
+
// direct deps of cli's own deps — unlikely but fast check).
|
|
92
|
+
try {
|
|
93
|
+
const rp = pnpApi.resolveRequest(args.path, gjsifyIssuer);
|
|
94
|
+
if (rp !== null)
|
|
95
|
+
return { namespace: "pnp", path: rp, watchFiles };
|
|
96
|
+
} catch {}
|
|
97
|
+
// Two-hop relay: resolve from node-polyfills / web-polyfills context
|
|
98
|
+
// which have the individual @gjsify/* packages as direct deps.
|
|
99
|
+
for (const relayIssuer of relayIssuers) {
|
|
100
|
+
try {
|
|
101
|
+
const rp = pnpApi.resolveRequest(args.path, relayIssuer);
|
|
102
|
+
if (rp !== null)
|
|
103
|
+
return { namespace: "pnp", path: rp, watchFiles };
|
|
104
|
+
} catch {}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Fall through — bare aliases (abort-controller, fetch/register/*)
|
|
108
|
+
// are handled by the gjsify alias plugin after this returns null,
|
|
109
|
+
// then the re-resolved @gjsify/* path goes through this hook again.
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
external: true,
|
|
114
|
+
errors: error ? [{ text: error.message }] : [],
|
|
115
|
+
watchFiles,
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
} catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
36
122
|
}
|
|
37
123
|
|
|
38
124
|
export class BuildAction {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
125
|
+
constructor(readonly configData: ConfigData = {}) {}
|
|
126
|
+
|
|
127
|
+
getEsBuildDefaults() {
|
|
128
|
+
const defaults: BuildOptions = {
|
|
129
|
+
allowOverwrite: true,
|
|
130
|
+
};
|
|
131
|
+
return defaults;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Library mode */
|
|
135
|
+
async buildLibrary() {
|
|
136
|
+
let { verbose, library, esbuild, typescript, exclude } = this.configData;
|
|
137
|
+
library ||= {};
|
|
138
|
+
esbuild ||= {};
|
|
139
|
+
typescript ||= {};
|
|
140
|
+
|
|
141
|
+
const moduleOutdir = library?.module ? dirname(library.module) : undefined;
|
|
142
|
+
const mainOutdir = library?.main ? dirname(library.main) : undefined;
|
|
143
|
+
|
|
144
|
+
const moduleOutExt = library.module ? extname(library.module) : ".js";
|
|
145
|
+
const mainOutExt = library.main ? extname(library.main) : ".js";
|
|
146
|
+
|
|
147
|
+
const multipleBuilds =
|
|
148
|
+
moduleOutdir && mainOutdir && moduleOutdir !== mainOutdir;
|
|
149
|
+
|
|
150
|
+
const pnpPlugin = await getPnpPlugin();
|
|
151
|
+
const pnpPlugins: Plugin[] = pnpPlugin ? [pnpPlugin] : [];
|
|
152
|
+
|
|
153
|
+
const results: BuildResult[] = [];
|
|
154
|
+
|
|
155
|
+
if (multipleBuilds) {
|
|
156
|
+
const moduleFormat =
|
|
157
|
+
moduleOutdir.includes("/cjs") || moduleOutExt === ".cjs"
|
|
158
|
+
? "cjs"
|
|
159
|
+
: "esm";
|
|
160
|
+
results.push(
|
|
161
|
+
await build({
|
|
162
|
+
...this.getEsBuildDefaults(),
|
|
163
|
+
...esbuild,
|
|
164
|
+
format: moduleFormat,
|
|
165
|
+
outdir: moduleOutdir,
|
|
166
|
+
plugins: [
|
|
167
|
+
...pnpPlugins,
|
|
168
|
+
gjsifyPlugin({
|
|
169
|
+
debug: verbose,
|
|
170
|
+
library: moduleFormat,
|
|
171
|
+
exclude,
|
|
172
|
+
reflection: typescript?.reflection,
|
|
173
|
+
jsExtension: moduleOutExt,
|
|
174
|
+
}),
|
|
175
|
+
],
|
|
176
|
+
}),
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
const mainFormat =
|
|
180
|
+
mainOutdir.includes("/cjs") || mainOutExt === ".cjs" ? "cjs" : "esm";
|
|
181
|
+
results.push(
|
|
182
|
+
await build({
|
|
183
|
+
...this.getEsBuildDefaults(),
|
|
184
|
+
...esbuild,
|
|
185
|
+
format: moduleFormat,
|
|
186
|
+
outdir: mainOutdir,
|
|
187
|
+
plugins: [
|
|
188
|
+
...pnpPlugins,
|
|
189
|
+
gjsifyPlugin({
|
|
190
|
+
debug: verbose,
|
|
191
|
+
library: mainFormat,
|
|
192
|
+
exclude,
|
|
193
|
+
reflection: typescript?.reflection,
|
|
194
|
+
jsExtension: mainOutdir,
|
|
195
|
+
}),
|
|
196
|
+
],
|
|
197
|
+
}),
|
|
198
|
+
);
|
|
199
|
+
} else {
|
|
200
|
+
const outfilePath = esbuild?.outfile || library?.module || library?.main;
|
|
201
|
+
const outExt = outfilePath ? extname(outfilePath) : ".js";
|
|
202
|
+
const outdir =
|
|
203
|
+
esbuild?.outdir || (outfilePath ? dirname(outfilePath) : undefined);
|
|
204
|
+
const format: "esm" | "cjs" =
|
|
205
|
+
(esbuild?.format as "esm" | "cjs") ??
|
|
206
|
+
(outdir?.includes("/cjs") || outExt === ".cjs" ? "cjs" : "esm");
|
|
207
|
+
results.push(
|
|
208
|
+
await build({
|
|
209
|
+
...this.getEsBuildDefaults(),
|
|
210
|
+
...esbuild,
|
|
211
|
+
format,
|
|
212
|
+
outdir,
|
|
213
|
+
plugins: [
|
|
214
|
+
...pnpPlugins,
|
|
215
|
+
gjsifyPlugin({
|
|
216
|
+
debug: verbose,
|
|
217
|
+
library: format,
|
|
218
|
+
exclude,
|
|
219
|
+
reflection: typescript?.reflection,
|
|
220
|
+
jsExtension: outExt,
|
|
221
|
+
}),
|
|
222
|
+
],
|
|
223
|
+
}),
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
return results;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Parse the `--globals` value into { autoMode, extras }.
|
|
231
|
+
* - `auto` → { autoMode: true, extras: '' }
|
|
232
|
+
* - `auto,dom` → { autoMode: true, extras: 'dom' }
|
|
233
|
+
* - `auto,dom,fetch` → { autoMode: true, extras: 'dom,fetch' }
|
|
234
|
+
* - `dom,fetch` → { autoMode: false, extras: 'dom,fetch' }
|
|
235
|
+
* - `none` / `` → { autoMode: false, extras: '' }
|
|
236
|
+
* - `undefined` → { autoMode: true, extras: '' } (default)
|
|
237
|
+
*/
|
|
238
|
+
private parseGlobalsValue(value: string | undefined): {
|
|
239
|
+
autoMode: boolean;
|
|
240
|
+
extras: string;
|
|
241
|
+
} {
|
|
242
|
+
if (value === undefined) return { autoMode: true, extras: "" };
|
|
243
|
+
if (value === "none" || value === "")
|
|
244
|
+
return { autoMode: false, extras: "" };
|
|
245
|
+
|
|
246
|
+
const tokens = value
|
|
247
|
+
.split(",")
|
|
248
|
+
.map((t) => t.trim())
|
|
249
|
+
.filter(Boolean);
|
|
250
|
+
const hasAuto = tokens.includes("auto");
|
|
251
|
+
const extras = tokens.filter((t) => t !== "auto").join(",");
|
|
252
|
+
|
|
253
|
+
return { autoMode: hasAuto, extras };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Resolve the `--globals` CLI list into a pre-computed inject stub path
|
|
258
|
+
* that the esbuild plugin will append to its `inject` list. Only runs
|
|
259
|
+
* for `--app gjs` — Node and browser builds rely on native globals.
|
|
260
|
+
*
|
|
261
|
+
* Used only for the explicit-only path (no `auto` token in the value).
|
|
262
|
+
* The auto path is handled in `buildApp` via the two-pass build.
|
|
263
|
+
*/
|
|
264
|
+
private async resolveGlobalsInject(
|
|
265
|
+
app: App,
|
|
266
|
+
globals: string,
|
|
267
|
+
verbose: boolean | undefined,
|
|
268
|
+
): Promise<string | undefined> {
|
|
269
|
+
if (app !== "gjs") return undefined;
|
|
270
|
+
if (!globals) return undefined;
|
|
271
|
+
|
|
272
|
+
const registerPaths = resolveGlobalsList(globals);
|
|
273
|
+
if (registerPaths.size === 0) return undefined;
|
|
274
|
+
|
|
275
|
+
const injectPath = await writeRegisterInjectFile(
|
|
276
|
+
registerPaths,
|
|
277
|
+
process.cwd(),
|
|
278
|
+
);
|
|
279
|
+
if (verbose && injectPath) {
|
|
280
|
+
console.debug(
|
|
281
|
+
`[gjsify] globals: injected ${registerPaths.size} register module(s) from --globals ${globals}`,
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
return injectPath ?? undefined;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Post-processing: prepend GJS shebang and mark the output file executable.
|
|
289
|
+
* Only runs for GJS app builds with a resolvable single outfile.
|
|
290
|
+
*/
|
|
291
|
+
private async applyShebang(
|
|
292
|
+
outfile: string | undefined,
|
|
293
|
+
verbose: boolean | undefined,
|
|
294
|
+
): Promise<void> {
|
|
295
|
+
if (!outfile) {
|
|
296
|
+
if (verbose)
|
|
297
|
+
console.warn(
|
|
298
|
+
"[gjsify] --shebang skipped: no single outfile (use --outfile for GJS executables)",
|
|
299
|
+
);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const content = await readFile(outfile, "utf-8");
|
|
304
|
+
if (content.startsWith("#!")) {
|
|
305
|
+
if (verbose)
|
|
306
|
+
console.debug(
|
|
307
|
+
`[gjsify] --shebang skipped: ${outfile} already starts with a shebang`,
|
|
308
|
+
);
|
|
309
|
+
} else {
|
|
310
|
+
await writeFile(outfile, GJS_SHEBANG + content);
|
|
311
|
+
}
|
|
312
|
+
await chmod(outfile, 0o755);
|
|
313
|
+
if (verbose)
|
|
314
|
+
console.debug(
|
|
315
|
+
`[gjsify] --shebang: wrote shebang + chmod 0o755 to ${outfile}`,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** Application mode */
|
|
320
|
+
async buildApp(app: App = "gjs") {
|
|
321
|
+
const {
|
|
322
|
+
verbose,
|
|
323
|
+
esbuild,
|
|
324
|
+
typescript,
|
|
325
|
+
exclude,
|
|
326
|
+
library: pgk,
|
|
327
|
+
aliases,
|
|
328
|
+
excludeGlobals,
|
|
329
|
+
} = this.configData;
|
|
330
|
+
|
|
331
|
+
const format: "esm" | "cjs" =
|
|
332
|
+
(esbuild?.format as "esm" | "cjs") ??
|
|
333
|
+
(esbuild?.outfile?.endsWith(".cjs") ? "cjs" : "esm");
|
|
334
|
+
|
|
335
|
+
// Set default outfile if no outdir is set
|
|
336
|
+
if (
|
|
337
|
+
esbuild &&
|
|
338
|
+
!esbuild?.outfile &&
|
|
339
|
+
!esbuild?.outdir &&
|
|
340
|
+
(pgk?.main || pgk?.module)
|
|
341
|
+
) {
|
|
342
|
+
esbuild.outfile =
|
|
343
|
+
esbuild?.format === "cjs"
|
|
344
|
+
? pgk.main || pgk.module
|
|
345
|
+
: pgk.module || pgk.main;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const { consoleShim, globals } = this.configData;
|
|
349
|
+
|
|
350
|
+
const pluginOpts = {
|
|
351
|
+
debug: verbose,
|
|
352
|
+
app,
|
|
353
|
+
format,
|
|
354
|
+
exclude,
|
|
355
|
+
reflection: typescript?.reflection,
|
|
356
|
+
consoleShim,
|
|
357
|
+
...(aliases ? { aliases } : {}),
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const { autoMode, extras } = this.parseGlobalsValue(globals);
|
|
361
|
+
|
|
362
|
+
const pnpPlugin = await getPnpPlugin();
|
|
363
|
+
const pnpPlugins: Plugin[] = pnpPlugin ? [pnpPlugin] : [];
|
|
364
|
+
|
|
365
|
+
// --- Auto mode (with optional extras): iterative multi-pass build ---
|
|
366
|
+
// The extras token is used for cases where the detector cannot
|
|
367
|
+
// statically see a global (e.g. Excalibur indirects globalThis via
|
|
368
|
+
// BrowserComponent.nativeComponent). Common pattern: --globals auto,dom
|
|
369
|
+
if (app === "gjs" && autoMode) {
|
|
370
|
+
const { injectPath } = await detectAutoGlobals(
|
|
371
|
+
{
|
|
372
|
+
...this.getEsBuildDefaults(),
|
|
373
|
+
...esbuild,
|
|
374
|
+
format,
|
|
375
|
+
plugins: pnpPlugins,
|
|
376
|
+
},
|
|
377
|
+
pluginOpts,
|
|
378
|
+
verbose,
|
|
379
|
+
{ extraGlobalsList: extras, excludeGlobals },
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
const result = await build({
|
|
383
|
+
...this.getEsBuildDefaults(),
|
|
384
|
+
...esbuild,
|
|
385
|
+
format,
|
|
386
|
+
plugins: [
|
|
387
|
+
...pnpPlugins,
|
|
388
|
+
gjsifyPlugin({
|
|
389
|
+
...pluginOpts,
|
|
390
|
+
autoGlobalsInject: injectPath,
|
|
391
|
+
}),
|
|
392
|
+
],
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
if (app === "gjs" && this.configData.shebang) {
|
|
396
|
+
await this.applyShebang(esbuild?.outfile, verbose);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return [result];
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// --- Explicit list (no `auto` token) or none mode ---
|
|
403
|
+
const autoGlobalsInject = extras
|
|
404
|
+
? await this.resolveGlobalsInject(app, extras, verbose)
|
|
405
|
+
: undefined;
|
|
406
|
+
|
|
407
|
+
const result = await build({
|
|
408
|
+
...this.getEsBuildDefaults(),
|
|
409
|
+
...esbuild,
|
|
410
|
+
format,
|
|
411
|
+
plugins: [
|
|
412
|
+
...pnpPlugins,
|
|
413
|
+
gjsifyPlugin({
|
|
414
|
+
...pluginOpts,
|
|
415
|
+
autoGlobalsInject,
|
|
416
|
+
}),
|
|
417
|
+
],
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
if (app === "gjs" && this.configData.shebang) {
|
|
421
|
+
await this.applyShebang(esbuild?.outfile, verbose);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return [result];
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async start(buildType: { library?: boolean; app?: App } = { app: "gjs" }) {
|
|
428
|
+
const results: BuildResult[] = [];
|
|
429
|
+
if (buildType.library) {
|
|
430
|
+
results.push(...(await this.buildLibrary()));
|
|
431
|
+
} else {
|
|
432
|
+
results.push(...(await this.buildApp(buildType.app)));
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return results;
|
|
436
|
+
}
|
|
437
|
+
}
|