@gjsify/cli 0.3.1 → 0.3.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/lib/actions/build.d.ts +2 -2
- package/lib/actions/build.js +62 -26
- package/lib/commands/build.js +5 -0
- package/lib/config.js +8 -0
- package/lib/types/cli-build-options.d.ts +7 -0
- package/lib/types/config-data.d.ts +7 -0
- package/package.json +11 -10
- package/src/actions/build.ts +96 -56
- package/src/commands/build.ts +5 -0
- package/src/config.ts +7 -0
- package/src/types/cli-build-options.ts +7 -0
- package/src/types/config-data.ts +7 -0
package/lib/actions/build.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ConfigData } from '../types/index.js';
|
|
2
2
|
import type { App } from '@gjsify/esbuild-plugin-gjsify';
|
|
3
|
-
import { BuildOptions, BuildResult } from 'esbuild';
|
|
3
|
+
import { BuildOptions, BuildResult, Plugin } from 'esbuild';
|
|
4
4
|
export declare class BuildAction {
|
|
5
5
|
readonly configData: ConfigData;
|
|
6
6
|
constructor(configData?: ConfigData);
|
|
@@ -34,7 +34,7 @@ export declare class BuildAction {
|
|
|
34
34
|
/** Application mode */
|
|
35
35
|
buildApp(app?: App): Promise<BuildResult<{
|
|
36
36
|
format: "esm" | "cjs";
|
|
37
|
-
plugins:
|
|
37
|
+
plugins: Plugin[];
|
|
38
38
|
bundle?: boolean;
|
|
39
39
|
splitting?: boolean;
|
|
40
40
|
preserveSymlinks?: boolean;
|
package/lib/actions/build.js
CHANGED
|
@@ -1,9 +1,38 @@
|
|
|
1
1
|
import { build } from 'esbuild';
|
|
2
2
|
import { gjsifyPlugin } from '@gjsify/esbuild-plugin-gjsify';
|
|
3
3
|
import { resolveGlobalsList, writeRegisterInjectFile, detectAutoGlobals } from '@gjsify/esbuild-plugin-gjsify/globals';
|
|
4
|
-
import { dirname, extname } from 'node:path';
|
|
4
|
+
import { dirname, extname, join } from 'node:path';
|
|
5
5
|
import { chmod, readFile, writeFile } from 'node:fs/promises';
|
|
6
|
-
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
const GJS_SHEBANG = "#!/usr/bin/env -S gjs -m\n";
|
|
8
|
+
/** Walk up from dir until .pnp.cjs is found; return its directory or null. */
|
|
9
|
+
function findPnpRoot(dir) {
|
|
10
|
+
let current = dir;
|
|
11
|
+
while (true) {
|
|
12
|
+
if (existsSync(join(current, ".pnp.cjs")))
|
|
13
|
+
return current;
|
|
14
|
+
const parent = dirname(current);
|
|
15
|
+
if (parent === current)
|
|
16
|
+
return null;
|
|
17
|
+
current = parent;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* If the current project uses Yarn PnP, return the official
|
|
22
|
+
* @yarnpkg/esbuild-plugin-pnp plugin so esbuild can resolve
|
|
23
|
+
* modules from zip archives without manual extraction.
|
|
24
|
+
*/
|
|
25
|
+
async function getPnpPlugin() {
|
|
26
|
+
if (!findPnpRoot(process.cwd()))
|
|
27
|
+
return null;
|
|
28
|
+
try {
|
|
29
|
+
const { pnpPlugin } = await import("@yarnpkg/esbuild-plugin-pnp");
|
|
30
|
+
return pnpPlugin();
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
7
36
|
export class BuildAction {
|
|
8
37
|
configData;
|
|
9
38
|
constructor(configData = {}) {
|
|
@@ -23,45 +52,50 @@ export class BuildAction {
|
|
|
23
52
|
typescript ||= {};
|
|
24
53
|
const moduleOutdir = library?.module ? dirname(library.module) : undefined;
|
|
25
54
|
const mainOutdir = library?.main ? dirname(library.main) : undefined;
|
|
26
|
-
const moduleOutExt = library.module ? extname(library.module) :
|
|
27
|
-
const mainOutExt = library.main ? extname(library.main) :
|
|
28
|
-
const multipleBuilds = moduleOutdir && mainOutdir &&
|
|
55
|
+
const moduleOutExt = library.module ? extname(library.module) : ".js";
|
|
56
|
+
const mainOutExt = library.main ? extname(library.main) : ".js";
|
|
57
|
+
const multipleBuilds = moduleOutdir && mainOutdir && moduleOutdir !== mainOutdir;
|
|
58
|
+
const pnpPlugin = await getPnpPlugin();
|
|
59
|
+
const pnpPlugins = pnpPlugin ? [pnpPlugin] : [];
|
|
29
60
|
const results = [];
|
|
30
61
|
if (multipleBuilds) {
|
|
31
|
-
const moduleFormat = moduleOutdir.includes(
|
|
62
|
+
const moduleFormat = moduleOutdir.includes("/cjs") || moduleOutExt === ".cjs" ? "cjs" : "esm";
|
|
32
63
|
results.push(await build({
|
|
33
64
|
...this.getEsBuildDefaults(),
|
|
34
65
|
...esbuild,
|
|
35
66
|
format: moduleFormat,
|
|
36
67
|
outdir: moduleOutdir,
|
|
37
68
|
plugins: [
|
|
69
|
+
...pnpPlugins,
|
|
38
70
|
gjsifyPlugin({ debug: verbose, library: moduleFormat, exclude, reflection: typescript?.reflection, jsExtension: moduleOutExt }),
|
|
39
|
-
]
|
|
71
|
+
],
|
|
40
72
|
}));
|
|
41
|
-
const mainFormat = mainOutdir.includes(
|
|
73
|
+
const mainFormat = mainOutdir.includes("/cjs") || mainOutExt === ".cjs" ? "cjs" : "esm";
|
|
42
74
|
results.push(await build({
|
|
43
75
|
...this.getEsBuildDefaults(),
|
|
44
76
|
...esbuild,
|
|
45
77
|
format: moduleFormat,
|
|
46
78
|
outdir: mainOutdir,
|
|
47
79
|
plugins: [
|
|
48
|
-
|
|
49
|
-
|
|
80
|
+
...pnpPlugins,
|
|
81
|
+
gjsifyPlugin({ debug: verbose, library: mainFormat, exclude, reflection: typescript?.reflection, jsExtension: mainOutdir }),
|
|
82
|
+
],
|
|
50
83
|
}));
|
|
51
84
|
}
|
|
52
85
|
else {
|
|
53
86
|
const outfilePath = esbuild?.outfile || library?.module || library?.main;
|
|
54
|
-
const outExt = outfilePath ? extname(outfilePath) :
|
|
87
|
+
const outExt = outfilePath ? extname(outfilePath) : ".js";
|
|
55
88
|
const outdir = esbuild?.outdir || (outfilePath ? dirname(outfilePath) : undefined);
|
|
56
|
-
const format = esbuild?.format ?? (outdir?.includes(
|
|
89
|
+
const format = esbuild?.format ?? (outdir?.includes("/cjs") || outExt === ".cjs" ? "cjs" : "esm");
|
|
57
90
|
results.push(await build({
|
|
58
91
|
...this.getEsBuildDefaults(),
|
|
59
92
|
...esbuild,
|
|
60
93
|
format,
|
|
61
94
|
outdir,
|
|
62
95
|
plugins: [
|
|
63
|
-
|
|
64
|
-
|
|
96
|
+
...pnpPlugins,
|
|
97
|
+
gjsifyPlugin({ debug: verbose, library: format, exclude, reflection: typescript?.reflection, jsExtension: outExt }),
|
|
98
|
+
],
|
|
65
99
|
}));
|
|
66
100
|
}
|
|
67
101
|
return results;
|
|
@@ -130,12 +164,12 @@ export class BuildAction {
|
|
|
130
164
|
console.debug(`[gjsify] --shebang: wrote shebang + chmod 0o755 to ${outfile}`);
|
|
131
165
|
}
|
|
132
166
|
/** Application mode */
|
|
133
|
-
async buildApp(app =
|
|
134
|
-
const { verbose, esbuild, typescript, exclude, library: pgk, aliases } = this.configData;
|
|
135
|
-
const format = esbuild?.format ?? (esbuild?.outfile?.endsWith(
|
|
167
|
+
async buildApp(app = "gjs") {
|
|
168
|
+
const { verbose, esbuild, typescript, exclude, library: pgk, aliases, excludeGlobals } = this.configData;
|
|
169
|
+
const format = esbuild?.format ?? (esbuild?.outfile?.endsWith(".cjs") ? "cjs" : "esm");
|
|
136
170
|
// Set default outfile if no outdir is set
|
|
137
171
|
if (esbuild && !esbuild?.outfile && !esbuild?.outdir && (pgk?.main || pgk?.module)) {
|
|
138
|
-
esbuild.outfile = esbuild?.format ===
|
|
172
|
+
esbuild.outfile = esbuild?.format === "cjs" ? pgk.main || pgk.module : pgk.module || pgk.main;
|
|
139
173
|
}
|
|
140
174
|
const { consoleShim, globals } = this.configData;
|
|
141
175
|
const pluginOpts = {
|
|
@@ -148,44 +182,46 @@ export class BuildAction {
|
|
|
148
182
|
...(aliases ? { aliases } : {}),
|
|
149
183
|
};
|
|
150
184
|
const { autoMode, extras } = this.parseGlobalsValue(globals);
|
|
185
|
+
const pnpPlugin = await getPnpPlugin();
|
|
186
|
+
const pnpPlugins = pnpPlugin ? [pnpPlugin] : [];
|
|
151
187
|
// --- Auto mode (with optional extras): iterative multi-pass build ---
|
|
152
188
|
// The extras token is used for cases where the detector cannot
|
|
153
189
|
// statically see a global (e.g. Excalibur indirects globalThis via
|
|
154
190
|
// BrowserComponent.nativeComponent). Common pattern: --globals auto,dom
|
|
155
|
-
if (app ===
|
|
156
|
-
const { injectPath } = await detectAutoGlobals({ ...this.getEsBuildDefaults(), ...esbuild, format }, pluginOpts, verbose, { extraGlobalsList: extras });
|
|
191
|
+
if (app === "gjs" && autoMode) {
|
|
192
|
+
const { injectPath } = await detectAutoGlobals({ ...this.getEsBuildDefaults(), ...esbuild, format, plugins: pnpPlugins }, pluginOpts, verbose, { extraGlobalsList: extras, excludeGlobals });
|
|
157
193
|
const result = await build({
|
|
158
194
|
...this.getEsBuildDefaults(),
|
|
159
195
|
...esbuild,
|
|
160
196
|
format,
|
|
161
197
|
plugins: [
|
|
198
|
+
...pnpPlugins,
|
|
162
199
|
gjsifyPlugin({
|
|
163
200
|
...pluginOpts,
|
|
164
201
|
autoGlobalsInject: injectPath,
|
|
165
202
|
}),
|
|
166
203
|
],
|
|
167
204
|
});
|
|
168
|
-
if (app ===
|
|
205
|
+
if (app === "gjs" && this.configData.shebang) {
|
|
169
206
|
await this.applyShebang(esbuild?.outfile, verbose);
|
|
170
207
|
}
|
|
171
208
|
return [result];
|
|
172
209
|
}
|
|
173
210
|
// --- Explicit list (no `auto` token) or none mode ---
|
|
174
|
-
const autoGlobalsInject = extras
|
|
175
|
-
? await this.resolveGlobalsInject(app, extras, verbose)
|
|
176
|
-
: undefined;
|
|
211
|
+
const autoGlobalsInject = extras ? await this.resolveGlobalsInject(app, extras, verbose) : undefined;
|
|
177
212
|
const result = await build({
|
|
178
213
|
...this.getEsBuildDefaults(),
|
|
179
214
|
...esbuild,
|
|
180
215
|
format,
|
|
181
216
|
plugins: [
|
|
217
|
+
...pnpPlugins,
|
|
182
218
|
gjsifyPlugin({
|
|
183
219
|
...pluginOpts,
|
|
184
220
|
autoGlobalsInject,
|
|
185
221
|
}),
|
|
186
|
-
]
|
|
222
|
+
],
|
|
187
223
|
});
|
|
188
|
-
if (app ===
|
|
224
|
+
if (app === "gjs" && this.configData.shebang) {
|
|
189
225
|
await this.applyShebang(esbuild?.outfile, verbose);
|
|
190
226
|
}
|
|
191
227
|
return [result];
|
package/lib/commands/build.js
CHANGED
|
@@ -117,6 +117,11 @@ export const buildCommand = {
|
|
|
117
117
|
type: 'string',
|
|
118
118
|
default: [],
|
|
119
119
|
coerce: (arg) => arg.flatMap((v) => v.split(',').map((s) => s.trim()).filter(Boolean)),
|
|
120
|
+
})
|
|
121
|
+
.option('exclude-globals', {
|
|
122
|
+
description: "Comma-separated global identifiers to remove from auto-detection results. Use for false positives from dead browser-compat code whose polyfills require unavailable native libraries (e.g. --exclude-globals fetch,XMLHttpRequest).",
|
|
123
|
+
type: 'string',
|
|
124
|
+
normalize: true,
|
|
120
125
|
});
|
|
121
126
|
},
|
|
122
127
|
handler: async (args) => {
|
package/lib/config.js
CHANGED
|
@@ -73,6 +73,14 @@ export class Config {
|
|
|
73
73
|
configData.globals = cliArgs.globals;
|
|
74
74
|
if (cliArgs.shebang !== undefined)
|
|
75
75
|
configData.shebang = cliArgs.shebang;
|
|
76
|
+
if (cliArgs.excludeGlobals) {
|
|
77
|
+
const raw = Array.isArray(cliArgs.excludeGlobals)
|
|
78
|
+
? cliArgs.excludeGlobals.join(',')
|
|
79
|
+
: String(cliArgs.excludeGlobals);
|
|
80
|
+
const ids = raw.split(',').map((s) => s.trim()).filter(Boolean);
|
|
81
|
+
if (ids.length)
|
|
82
|
+
configData.excludeGlobals = [...(configData.excludeGlobals ?? []), ...ids];
|
|
83
|
+
}
|
|
76
84
|
merge(configData.library ??= {}, pkg, configData.library);
|
|
77
85
|
merge(configData.typescript ??= {}, tsConfig, configData.typescript);
|
|
78
86
|
// Parse `KEY=VALUE` style flags into Record<string, string>.
|
|
@@ -89,4 +89,11 @@ export interface CliBuildOptions {
|
|
|
89
89
|
* scenario never executes). Layered on top of the built-in alias map.
|
|
90
90
|
*/
|
|
91
91
|
alias?: string[];
|
|
92
|
+
/**
|
|
93
|
+
* Comma-separated global identifiers to remove from the auto-detected set.
|
|
94
|
+
* Useful for false positives from dead browser-compat code in npm deps
|
|
95
|
+
* whose polyfills require unavailable native libraries.
|
|
96
|
+
* Example: `--exclude-globals fetch,XMLHttpRequest`
|
|
97
|
+
*/
|
|
98
|
+
excludeGlobals?: string[];
|
|
92
99
|
}
|
|
@@ -27,4 +27,11 @@ export interface ConfigData {
|
|
|
27
27
|
* Comes from `gjsify build --alias FROM=TO`.
|
|
28
28
|
*/
|
|
29
29
|
aliases?: Record<string, string>;
|
|
30
|
+
/**
|
|
31
|
+
* Global identifiers to remove from the auto-detected set before writing
|
|
32
|
+
* the inject stub. Useful for false positives from dead browser-compat
|
|
33
|
+
* code in npm dependencies whose polyfills require unavailable native libs.
|
|
34
|
+
* Example: `["fetch", "XMLHttpRequest"]` excludes the HTTP polyfill stack.
|
|
35
|
+
*/
|
|
36
|
+
excludeGlobals?: string[];
|
|
30
37
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "CLI for Gjsify",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -23,15 +23,16 @@
|
|
|
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.2",
|
|
27
|
+
"@gjsify/esbuild-plugin-gjsify": "^0.3.2",
|
|
28
|
+
"@gjsify/example-dom-canvas2d-fireworks": "^0.3.2",
|
|
29
|
+
"@gjsify/example-dom-excalibur-jelly-jumper": "^0.3.2",
|
|
30
|
+
"@gjsify/example-dom-three-geometry-teapot": "^0.3.2",
|
|
31
|
+
"@gjsify/example-dom-three-postprocessing-pixel": "^0.3.2",
|
|
32
|
+
"@gjsify/example-node-express-webserver": "^0.3.2",
|
|
33
|
+
"@gjsify/node-polyfills": "^0.3.2",
|
|
34
|
+
"@gjsify/web-polyfills": "^0.3.2",
|
|
35
|
+
"@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.15",
|
|
35
36
|
"cosmiconfig": "^9.0.1",
|
|
36
37
|
"esbuild": "^0.28.0",
|
|
37
38
|
"get-tsconfig": "^4.14.0",
|
package/src/actions/build.ts
CHANGED
|
@@ -1,12 +1,39 @@
|
|
|
1
1
|
import type { ConfigData } from '../types/index.js';
|
|
2
2
|
import type { App } from '@gjsify/esbuild-plugin-gjsify';
|
|
3
|
-
import { build, BuildOptions, BuildResult } from 'esbuild';
|
|
3
|
+
import { build, BuildOptions, BuildResult, Plugin } from 'esbuild';
|
|
4
4
|
import { gjsifyPlugin } from '@gjsify/esbuild-plugin-gjsify';
|
|
5
5
|
import { resolveGlobalsList, writeRegisterInjectFile, detectAutoGlobals } from '@gjsify/esbuild-plugin-gjsify/globals';
|
|
6
|
-
import { dirname, extname } from 'node:path';
|
|
6
|
+
import { dirname, extname, join } from 'node:path';
|
|
7
7
|
import { chmod, readFile, writeFile } from 'node:fs/promises';
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
|
|
10
|
+
const GJS_SHEBANG = "#!/usr/bin/env -S gjs -m\n";
|
|
11
|
+
|
|
12
|
+
/** Walk up from dir until .pnp.cjs is found; return its directory or null. */
|
|
13
|
+
function findPnpRoot(dir: string): string | null {
|
|
14
|
+
let current = dir;
|
|
15
|
+
while (true) {
|
|
16
|
+
if (existsSync(join(current, ".pnp.cjs"))) return current;
|
|
17
|
+
const parent = dirname(current);
|
|
18
|
+
if (parent === current) return null;
|
|
19
|
+
current = parent;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* If the current project uses Yarn PnP, return the official
|
|
25
|
+
* @yarnpkg/esbuild-plugin-pnp plugin so esbuild can resolve
|
|
26
|
+
* modules from zip archives without manual extraction.
|
|
27
|
+
*/
|
|
28
|
+
async function getPnpPlugin(): Promise<Plugin | null> {
|
|
29
|
+
if (!findPnpRoot(process.cwd())) return null;
|
|
30
|
+
try {
|
|
31
|
+
const { pnpPlugin } = await import("@yarnpkg/esbuild-plugin-pnp");
|
|
32
|
+
return pnpPlugin();
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
10
37
|
|
|
11
38
|
export class BuildAction {
|
|
12
39
|
constructor(readonly configData: ConfigData = {}) {
|
|
@@ -30,50 +57,61 @@ export class BuildAction {
|
|
|
30
57
|
const moduleOutdir = library?.module ? dirname(library.module) : undefined;
|
|
31
58
|
const mainOutdir = library?.main ? dirname(library.main) : undefined;
|
|
32
59
|
|
|
33
|
-
const moduleOutExt = library.module ? extname(library.module) :
|
|
34
|
-
const mainOutExt = library.main ? extname(library.main) :
|
|
60
|
+
const moduleOutExt = library.module ? extname(library.module) : ".js";
|
|
61
|
+
const mainOutExt = library.main ? extname(library.main) : ".js";
|
|
35
62
|
|
|
36
|
-
const multipleBuilds = moduleOutdir && mainOutdir &&
|
|
63
|
+
const multipleBuilds = moduleOutdir && mainOutdir && moduleOutdir !== mainOutdir;
|
|
64
|
+
|
|
65
|
+
const pnpPlugin = await getPnpPlugin();
|
|
66
|
+
const pnpPlugins: Plugin[] = pnpPlugin ? [pnpPlugin] : [];
|
|
37
67
|
|
|
38
68
|
const results: BuildResult[] = [];
|
|
39
|
-
|
|
40
|
-
if(multipleBuilds) {
|
|
41
69
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
if (multipleBuilds) {
|
|
71
|
+
const moduleFormat = moduleOutdir.includes("/cjs") || moduleOutExt === ".cjs" ? "cjs" : "esm";
|
|
72
|
+
results.push(
|
|
73
|
+
await build({
|
|
74
|
+
...this.getEsBuildDefaults(),
|
|
75
|
+
...esbuild,
|
|
76
|
+
format: moduleFormat,
|
|
77
|
+
outdir: moduleOutdir,
|
|
78
|
+
plugins: [
|
|
79
|
+
...pnpPlugins,
|
|
80
|
+
gjsifyPlugin({ debug: verbose, library: moduleFormat, exclude, reflection: typescript?.reflection, jsExtension: moduleOutExt }),
|
|
81
|
+
],
|
|
82
|
+
}),
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const mainFormat = mainOutdir.includes("/cjs") || mainOutExt === ".cjs" ? "cjs" : "esm";
|
|
86
|
+
results.push(
|
|
87
|
+
await build({
|
|
88
|
+
...this.getEsBuildDefaults(),
|
|
89
|
+
...esbuild,
|
|
90
|
+
format: moduleFormat,
|
|
91
|
+
outdir: mainOutdir,
|
|
92
|
+
plugins: [
|
|
93
|
+
...pnpPlugins,
|
|
94
|
+
gjsifyPlugin({ debug: verbose, library: mainFormat, exclude, reflection: typescript?.reflection, jsExtension: mainOutdir }),
|
|
95
|
+
],
|
|
96
|
+
}),
|
|
97
|
+
);
|
|
63
98
|
} else {
|
|
64
99
|
const outfilePath = esbuild?.outfile || library?.module || library?.main;
|
|
65
|
-
const outExt = outfilePath ? extname(outfilePath) :
|
|
100
|
+
const outExt = outfilePath ? extname(outfilePath) : ".js";
|
|
66
101
|
const outdir = esbuild?.outdir || (outfilePath ? dirname(outfilePath) : undefined);
|
|
67
|
-
const format:
|
|
68
|
-
results.push(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
102
|
+
const format: "esm" | "cjs" = (esbuild?.format as "esm" | "cjs") ?? (outdir?.includes("/cjs") || outExt === ".cjs" ? "cjs" : "esm");
|
|
103
|
+
results.push(
|
|
104
|
+
await build({
|
|
105
|
+
...this.getEsBuildDefaults(),
|
|
106
|
+
...esbuild,
|
|
107
|
+
format,
|
|
108
|
+
outdir,
|
|
109
|
+
plugins: [
|
|
110
|
+
...pnpPlugins,
|
|
111
|
+
gjsifyPlugin({ debug: verbose, library: format, exclude, reflection: typescript?.reflection, jsExtension: outExt }),
|
|
112
|
+
],
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
77
115
|
}
|
|
78
116
|
return results;
|
|
79
117
|
}
|
|
@@ -147,15 +185,14 @@ export class BuildAction {
|
|
|
147
185
|
}
|
|
148
186
|
|
|
149
187
|
/** Application mode */
|
|
150
|
-
async buildApp(app: App =
|
|
188
|
+
async buildApp(app: App = "gjs") {
|
|
189
|
+
const { verbose, esbuild, typescript, exclude, library: pgk, aliases, excludeGlobals } = this.configData;
|
|
151
190
|
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
const format: 'esm' | 'cjs' = (esbuild?.format as 'esm' | 'cjs') ?? (esbuild?.outfile?.endsWith('.cjs') ? 'cjs' : 'esm');
|
|
191
|
+
const format: "esm" | "cjs" = (esbuild?.format as "esm" | "cjs") ?? (esbuild?.outfile?.endsWith(".cjs") ? "cjs" : "esm");
|
|
155
192
|
|
|
156
193
|
// Set default outfile if no outdir is set
|
|
157
|
-
if(esbuild && !esbuild?.outfile && !esbuild?.outdir && (pgk?.main || pgk?.module)) {
|
|
158
|
-
esbuild.outfile = esbuild?.format ===
|
|
194
|
+
if (esbuild && !esbuild?.outfile && !esbuild?.outdir && (pgk?.main || pgk?.module)) {
|
|
195
|
+
esbuild.outfile = esbuild?.format === "cjs" ? pgk.main || pgk.module : pgk.module || pgk.main;
|
|
159
196
|
}
|
|
160
197
|
|
|
161
198
|
const { consoleShim, globals } = this.configData;
|
|
@@ -172,16 +209,19 @@ export class BuildAction {
|
|
|
172
209
|
|
|
173
210
|
const { autoMode, extras } = this.parseGlobalsValue(globals);
|
|
174
211
|
|
|
212
|
+
const pnpPlugin = await getPnpPlugin();
|
|
213
|
+
const pnpPlugins: Plugin[] = pnpPlugin ? [pnpPlugin] : [];
|
|
214
|
+
|
|
175
215
|
// --- Auto mode (with optional extras): iterative multi-pass build ---
|
|
176
216
|
// The extras token is used for cases where the detector cannot
|
|
177
217
|
// statically see a global (e.g. Excalibur indirects globalThis via
|
|
178
218
|
// BrowserComponent.nativeComponent). Common pattern: --globals auto,dom
|
|
179
|
-
if (app ===
|
|
219
|
+
if (app === "gjs" && autoMode) {
|
|
180
220
|
const { injectPath } = await detectAutoGlobals(
|
|
181
|
-
{ ...this.getEsBuildDefaults(), ...esbuild, format },
|
|
221
|
+
{ ...this.getEsBuildDefaults(), ...esbuild, format, plugins: pnpPlugins },
|
|
182
222
|
pluginOpts,
|
|
183
223
|
verbose,
|
|
184
|
-
{ extraGlobalsList: extras },
|
|
224
|
+
{ extraGlobalsList: extras, excludeGlobals },
|
|
185
225
|
);
|
|
186
226
|
|
|
187
227
|
const result = await build({
|
|
@@ -189,6 +229,7 @@ export class BuildAction {
|
|
|
189
229
|
...esbuild,
|
|
190
230
|
format,
|
|
191
231
|
plugins: [
|
|
232
|
+
...pnpPlugins,
|
|
192
233
|
gjsifyPlugin({
|
|
193
234
|
...pluginOpts,
|
|
194
235
|
autoGlobalsInject: injectPath,
|
|
@@ -196,7 +237,7 @@ export class BuildAction {
|
|
|
196
237
|
],
|
|
197
238
|
});
|
|
198
239
|
|
|
199
|
-
if (app ===
|
|
240
|
+
if (app === "gjs" && this.configData.shebang) {
|
|
200
241
|
await this.applyShebang(esbuild?.outfile, verbose);
|
|
201
242
|
}
|
|
202
243
|
|
|
@@ -204,23 +245,22 @@ export class BuildAction {
|
|
|
204
245
|
}
|
|
205
246
|
|
|
206
247
|
// --- Explicit list (no `auto` token) or none mode ---
|
|
207
|
-
const autoGlobalsInject = extras
|
|
208
|
-
? await this.resolveGlobalsInject(app, extras, verbose)
|
|
209
|
-
: undefined;
|
|
248
|
+
const autoGlobalsInject = extras ? await this.resolveGlobalsInject(app, extras, verbose) : undefined;
|
|
210
249
|
|
|
211
250
|
const result = await build({
|
|
212
251
|
...this.getEsBuildDefaults(),
|
|
213
252
|
...esbuild,
|
|
214
253
|
format,
|
|
215
254
|
plugins: [
|
|
255
|
+
...pnpPlugins,
|
|
216
256
|
gjsifyPlugin({
|
|
217
257
|
...pluginOpts,
|
|
218
258
|
autoGlobalsInject,
|
|
219
259
|
}),
|
|
220
|
-
]
|
|
260
|
+
],
|
|
221
261
|
});
|
|
222
262
|
|
|
223
|
-
if (app ===
|
|
263
|
+
if (app === "gjs" && this.configData.shebang) {
|
|
224
264
|
await this.applyShebang(esbuild?.outfile, verbose);
|
|
225
265
|
}
|
|
226
266
|
|
package/src/commands/build.ts
CHANGED
|
@@ -120,6 +120,11 @@ export const buildCommand: Command<any, CliBuildOptions> = {
|
|
|
120
120
|
default: [] as string[],
|
|
121
121
|
coerce: (arg: string[]) => arg.flatMap((v) => v.split(',').map((s) => s.trim()).filter(Boolean)),
|
|
122
122
|
})
|
|
123
|
+
.option('exclude-globals', {
|
|
124
|
+
description: "Comma-separated global identifiers to remove from auto-detection results. Use for false positives from dead browser-compat code whose polyfills require unavailable native libraries (e.g. --exclude-globals fetch,XMLHttpRequest).",
|
|
125
|
+
type: 'string',
|
|
126
|
+
normalize: true,
|
|
127
|
+
})
|
|
123
128
|
},
|
|
124
129
|
handler: async (args) => {
|
|
125
130
|
const config = new Config();
|
package/src/config.ts
CHANGED
|
@@ -84,6 +84,13 @@ export class Config {
|
|
|
84
84
|
if (cliArgs.consoleShim !== undefined) configData.consoleShim = cliArgs.consoleShim;
|
|
85
85
|
if (cliArgs.globals !== undefined) configData.globals = cliArgs.globals;
|
|
86
86
|
if (cliArgs.shebang !== undefined) configData.shebang = cliArgs.shebang;
|
|
87
|
+
if (cliArgs.excludeGlobals) {
|
|
88
|
+
const raw = Array.isArray(cliArgs.excludeGlobals)
|
|
89
|
+
? cliArgs.excludeGlobals.join(',')
|
|
90
|
+
: String(cliArgs.excludeGlobals);
|
|
91
|
+
const ids = raw.split(',').map((s: string) => s.trim()).filter(Boolean);
|
|
92
|
+
if (ids.length) configData.excludeGlobals = [...(configData.excludeGlobals ?? []), ...ids];
|
|
93
|
+
}
|
|
87
94
|
|
|
88
95
|
merge(configData.library ??= {}, pkg, configData.library);
|
|
89
96
|
merge(configData.typescript ??= {}, tsConfig, configData.typescript);
|
|
@@ -90,4 +90,11 @@ export interface CliBuildOptions {
|
|
|
90
90
|
* scenario never executes). Layered on top of the built-in alias map.
|
|
91
91
|
*/
|
|
92
92
|
alias?: string[];
|
|
93
|
+
/**
|
|
94
|
+
* Comma-separated global identifiers to remove from the auto-detected set.
|
|
95
|
+
* Useful for false positives from dead browser-compat code in npm deps
|
|
96
|
+
* whose polyfills require unavailable native libraries.
|
|
97
|
+
* Example: `--exclude-globals fetch,XMLHttpRequest`
|
|
98
|
+
*/
|
|
99
|
+
excludeGlobals?: string[];
|
|
93
100
|
}
|
package/src/types/config-data.ts
CHANGED
|
@@ -28,4 +28,11 @@ export interface ConfigData {
|
|
|
28
28
|
* Comes from `gjsify build --alias FROM=TO`.
|
|
29
29
|
*/
|
|
30
30
|
aliases?: Record<string, string>;
|
|
31
|
+
/**
|
|
32
|
+
* Global identifiers to remove from the auto-detected set before writing
|
|
33
|
+
* the inject stub. Useful for false positives from dead browser-compat
|
|
34
|
+
* code in npm dependencies whose polyfills require unavailable native libs.
|
|
35
|
+
* Example: `["fetch", "XMLHttpRequest"]` excludes the HTTP polyfill stack.
|
|
36
|
+
*/
|
|
37
|
+
excludeGlobals?: string[];
|
|
31
38
|
}
|