@gjsify/cli 0.3.6 → 0.3.7
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.js +21 -113
- package/package.json +6 -5
- package/src/actions/build.ts +21 -116
package/lib/actions/build.js
CHANGED
|
@@ -1,122 +1,30 @@
|
|
|
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 {
|
|
5
|
-
import {
|
|
4
|
+
import { getBundleDir, rewriteContents } from "@gjsify/esbuild-plugin-gjsify";
|
|
5
|
+
import { getPnpPlugin } from "@gjsify/resolve-npm/pnp-relay";
|
|
6
|
+
import { dirname, extname } from "node:path";
|
|
6
7
|
import { chmod, readFile, writeFile } from "node:fs/promises";
|
|
7
|
-
import { existsSync } from "node:fs";
|
|
8
|
-
import { createRequire } from "node:module";
|
|
9
8
|
const GJS_SHEBANG = "#!/usr/bin/env -S gjs -m\n";
|
|
10
|
-
/** Walk up from dir until .pnp.cjs is found; return its directory or null. */
|
|
11
|
-
function findPnpRoot(dir) {
|
|
12
|
-
let current = dir;
|
|
13
|
-
while (true) {
|
|
14
|
-
if (existsSync(join(current, ".pnp.cjs")))
|
|
15
|
-
return current;
|
|
16
|
-
const parent = dirname(current);
|
|
17
|
-
if (parent === current)
|
|
18
|
-
return null;
|
|
19
|
-
current = parent;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
9
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
10
|
+
* Resolve the gjsify-flavoured PnP plugin. Anchors the relay on this file's
|
|
11
|
+
* URL so transitive `@gjsify/*` polyfills (reached via @gjsify/cli's deps on
|
|
12
|
+
* @gjsify/{node,web}-polyfills) are resolvable for external consumers without
|
|
13
|
+
* each one having to be a direct devDep.
|
|
26
14
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
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.
|
|
15
|
+
* Wires the @gjsify/esbuild-plugin-gjsify rewriter (`__filename`/`__dirname`
|
|
16
|
+
* injection for CJS code in node_modules) into the pnp plugin's onLoad —
|
|
17
|
+
* esbuild stops at the first matching onLoad, so the rewriter MUST run from
|
|
18
|
+
* inside the pnp plugin's onLoad rather than as a separate registration.
|
|
36
19
|
*/
|
|
37
|
-
async function
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Two-hop relay: node-polyfills and web-polyfills have all individual
|
|
46
|
-
// @gjsify/* packages as direct deps. Resolving from their package.json
|
|
47
|
-
// paths allows PnP to use them as issuers — sub-path imports
|
|
48
|
-
// (`@gjsify/foo/register/bar`) then resolve through the polyfill's
|
|
49
|
-
// dep graph. Resolve to package.json (always present, exports-agnostic)
|
|
50
|
-
// rather than main/module (the polyfills meta packages have no main).
|
|
51
|
-
const requireFromGjsify = createRequire(gjsifyIssuer);
|
|
52
|
-
const relayIssuers = [];
|
|
53
|
-
for (const pkg of ["@gjsify/node-polyfills", "@gjsify/web-polyfills"]) {
|
|
54
|
-
try {
|
|
55
|
-
relayIssuers.push(requireFromGjsify.resolve(`${pkg}/package.json`));
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
// polyfills package not in dep tree — relay won't cover it
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
let pnpApi = null;
|
|
62
|
-
try {
|
|
63
|
-
// pnpapi has no npm package — it is a virtual CJS module injected by
|
|
64
|
-
// Yarn PnP. `await import()` of a CJS module yields the ESM namespace
|
|
65
|
-
// `{ default, "module.exports" }`, NOT the exports object — so
|
|
66
|
-
// `mod.resolveRequest` is `undefined`. Unwrap `.default` (the CJS
|
|
67
|
-
// exports) before use, falling back to the namespace itself for ESM
|
|
68
|
-
// builds of pnpapi (none today, but defensive).
|
|
69
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
70
|
-
// @ts-expect-error
|
|
71
|
-
const mod = await import("pnpapi");
|
|
72
|
-
pnpApi = (mod.default ?? mod);
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
// Not in a PnP runtime (shouldn't happen since findPnpRoot passed)
|
|
76
|
-
}
|
|
77
|
-
return pnpPlugin({
|
|
78
|
-
onResolve: async (args, { resolvedPath, error, watchFiles }) => {
|
|
79
|
-
if (resolvedPath !== null) {
|
|
80
|
-
return { namespace: "pnp", path: resolvedPath, watchFiles };
|
|
81
|
-
}
|
|
82
|
-
if (error?.pnpCode ===
|
|
83
|
-
"UNDECLARED_DEPENDENCY") {
|
|
84
|
-
if (pnpApi !== null) {
|
|
85
|
-
// Try @gjsify/cli context first (covers @gjsify/* that are
|
|
86
|
-
// direct deps of cli's own deps — unlikely but fast check).
|
|
87
|
-
try {
|
|
88
|
-
const rp = pnpApi.resolveRequest(args.path, gjsifyIssuer);
|
|
89
|
-
if (rp !== null)
|
|
90
|
-
return { namespace: "pnp", path: rp, watchFiles };
|
|
91
|
-
}
|
|
92
|
-
catch { }
|
|
93
|
-
// Two-hop relay: resolve from node-polyfills / web-polyfills context
|
|
94
|
-
// which have the individual @gjsify/* packages as direct deps.
|
|
95
|
-
for (const relayIssuer of relayIssuers) {
|
|
96
|
-
try {
|
|
97
|
-
const rp = pnpApi.resolveRequest(args.path, relayIssuer);
|
|
98
|
-
if (rp !== null)
|
|
99
|
-
return { namespace: "pnp", path: rp, watchFiles };
|
|
100
|
-
}
|
|
101
|
-
catch { }
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
// Fall through — bare aliases (abort-controller, fetch/register/*)
|
|
105
|
-
// are handled by the gjsify alias plugin after this returns null,
|
|
106
|
-
// then the re-resolved @gjsify/* path goes through this hook again.
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
return {
|
|
110
|
-
external: true,
|
|
111
|
-
errors: error ? [{ text: error.message }] : [],
|
|
112
|
-
watchFiles,
|
|
113
|
-
};
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
20
|
+
async function buildPnpPlugin() {
|
|
21
|
+
return getPnpPlugin({
|
|
22
|
+
issuerUrl: import.meta.url,
|
|
23
|
+
transformContentsFactory: (build) => {
|
|
24
|
+
const bundleDir = getBundleDir(build);
|
|
25
|
+
return (args, contents) => rewriteContents(args, contents, bundleDir);
|
|
26
|
+
},
|
|
27
|
+
});
|
|
120
28
|
}
|
|
121
29
|
export class BuildAction {
|
|
122
30
|
configData;
|
|
@@ -140,7 +48,7 @@ export class BuildAction {
|
|
|
140
48
|
const moduleOutExt = library.module ? extname(library.module) : ".js";
|
|
141
49
|
const mainOutExt = library.main ? extname(library.main) : ".js";
|
|
142
50
|
const multipleBuilds = moduleOutdir && mainOutdir && moduleOutdir !== mainOutdir;
|
|
143
|
-
const pnpPlugin = await
|
|
51
|
+
const pnpPlugin = await buildPnpPlugin();
|
|
144
52
|
const pnpPlugins = pnpPlugin ? [pnpPlugin] : [];
|
|
145
53
|
const results = [];
|
|
146
54
|
if (multipleBuilds) {
|
|
@@ -298,7 +206,7 @@ export class BuildAction {
|
|
|
298
206
|
...(aliases ? { aliases } : {}),
|
|
299
207
|
};
|
|
300
208
|
const { autoMode, extras } = this.parseGlobalsValue(globals);
|
|
301
|
-
const pnpPlugin = await
|
|
209
|
+
const pnpPlugin = await buildPnpPlugin();
|
|
302
210
|
const pnpPlugins = pnpPlugin ? [pnpPlugin] : [];
|
|
303
211
|
// --- Auto mode (with optional extras): iterative multi-pass build ---
|
|
304
212
|
// The extras token is used for cases where the detector cannot
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "CLI for Gjsify",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -23,10 +23,11 @@
|
|
|
23
23
|
"cli"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@gjsify/create-app": "^0.3.
|
|
27
|
-
"@gjsify/esbuild-plugin-gjsify": "^0.3.
|
|
28
|
-
"@gjsify/node-polyfills": "^0.3.
|
|
29
|
-
"@gjsify/
|
|
26
|
+
"@gjsify/create-app": "^0.3.7",
|
|
27
|
+
"@gjsify/esbuild-plugin-gjsify": "^0.3.7",
|
|
28
|
+
"@gjsify/node-polyfills": "^0.3.7",
|
|
29
|
+
"@gjsify/resolve-npm": "^0.3.7",
|
|
30
|
+
"@gjsify/web-polyfills": "^0.3.7",
|
|
30
31
|
"@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.15",
|
|
31
32
|
"cosmiconfig": "^9.0.1",
|
|
32
33
|
"esbuild": "^0.28.0",
|
package/src/actions/build.ts
CHANGED
|
@@ -7,127 +7,32 @@ import {
|
|
|
7
7
|
writeRegisterInjectFile,
|
|
8
8
|
detectAutoGlobals,
|
|
9
9
|
} from "@gjsify/esbuild-plugin-gjsify/globals";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { getBundleDir, rewriteContents } from "@gjsify/esbuild-plugin-gjsify";
|
|
11
|
+
import { getPnpPlugin } from "@gjsify/resolve-npm/pnp-relay";
|
|
12
|
+
import { dirname, extname } from "node:path";
|
|
12
13
|
import { chmod, readFile, writeFile } from "node:fs/promises";
|
|
13
|
-
import { existsSync } from "node:fs";
|
|
14
|
-
import { createRequire } from "node:module";
|
|
15
14
|
|
|
16
15
|
const GJS_SHEBANG = "#!/usr/bin/env -S gjs -m\n";
|
|
17
16
|
|
|
18
|
-
/** Walk up from dir until .pnp.cjs is found; return its directory or null. */
|
|
19
|
-
function findPnpRoot(dir: string): string | null {
|
|
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
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
17
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
18
|
+
* Resolve the gjsify-flavoured PnP plugin. Anchors the relay on this file's
|
|
19
|
+
* URL so transitive `@gjsify/*` polyfills (reached via @gjsify/cli's deps on
|
|
20
|
+
* @gjsify/{node,web}-polyfills) are resolvable for external consumers without
|
|
21
|
+
* each one having to be a direct devDep.
|
|
33
22
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
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.
|
|
23
|
+
* Wires the @gjsify/esbuild-plugin-gjsify rewriter (`__filename`/`__dirname`
|
|
24
|
+
* injection for CJS code in node_modules) into the pnp plugin's onLoad —
|
|
25
|
+
* esbuild stops at the first matching onLoad, so the rewriter MUST run from
|
|
26
|
+
* inside the pnp plugin's onLoad rather than as a separate registration.
|
|
43
27
|
*/
|
|
44
|
-
async function
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// Two-hop relay: node-polyfills and web-polyfills have all individual
|
|
54
|
-
// @gjsify/* packages as direct deps. Resolving from their package.json
|
|
55
|
-
// paths allows PnP to use them as issuers — sub-path imports
|
|
56
|
-
// (`@gjsify/foo/register/bar`) then resolve through the polyfill's
|
|
57
|
-
// dep graph. Resolve to package.json (always present, exports-agnostic)
|
|
58
|
-
// rather than main/module (the polyfills meta packages have no main).
|
|
59
|
-
const requireFromGjsify = createRequire(gjsifyIssuer);
|
|
60
|
-
const relayIssuers: string[] = [];
|
|
61
|
-
for (const pkg of ["@gjsify/node-polyfills", "@gjsify/web-polyfills"]) {
|
|
62
|
-
try {
|
|
63
|
-
relayIssuers.push(requireFromGjsify.resolve(`${pkg}/package.json`));
|
|
64
|
-
} catch {
|
|
65
|
-
// polyfills package not in dep tree — relay won't cover it
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// pnpapi is a virtual module injected by Yarn PnP at runtime.
|
|
70
|
-
type PnpApi = {
|
|
71
|
-
resolveRequest: (req: string, issuer: string) => string | null;
|
|
72
|
-
};
|
|
73
|
-
let pnpApi: PnpApi | null = null;
|
|
74
|
-
try {
|
|
75
|
-
// pnpapi has no npm package — it is a virtual CJS module injected by
|
|
76
|
-
// Yarn PnP. `await import()` of a CJS module yields the ESM namespace
|
|
77
|
-
// `{ default, "module.exports" }`, NOT the exports object — so
|
|
78
|
-
// `mod.resolveRequest` is `undefined`. Unwrap `.default` (the CJS
|
|
79
|
-
// exports) before use, falling back to the namespace itself for ESM
|
|
80
|
-
// builds of pnpapi (none today, but defensive).
|
|
81
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
82
|
-
// @ts-expect-error
|
|
83
|
-
const mod = await import("pnpapi");
|
|
84
|
-
pnpApi = ((mod as { default?: PnpApi }).default ?? mod) as PnpApi;
|
|
85
|
-
} catch {
|
|
86
|
-
// Not in a PnP runtime (shouldn't happen since findPnpRoot passed)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return pnpPlugin({
|
|
90
|
-
onResolve: async (args, { resolvedPath, error, watchFiles }) => {
|
|
91
|
-
if (resolvedPath !== null) {
|
|
92
|
-
return { namespace: "pnp", path: resolvedPath, watchFiles };
|
|
93
|
-
}
|
|
94
|
-
if (
|
|
95
|
-
(error as { pnpCode?: string } | null)?.pnpCode ===
|
|
96
|
-
"UNDECLARED_DEPENDENCY"
|
|
97
|
-
) {
|
|
98
|
-
if (pnpApi !== null) {
|
|
99
|
-
// Try @gjsify/cli context first (covers @gjsify/* that are
|
|
100
|
-
// direct deps of cli's own deps — unlikely but fast check).
|
|
101
|
-
try {
|
|
102
|
-
const rp = pnpApi.resolveRequest(args.path, gjsifyIssuer);
|
|
103
|
-
if (rp !== null)
|
|
104
|
-
return { namespace: "pnp", path: rp, watchFiles };
|
|
105
|
-
} catch {}
|
|
106
|
-
// Two-hop relay: resolve from node-polyfills / web-polyfills context
|
|
107
|
-
// which have the individual @gjsify/* packages as direct deps.
|
|
108
|
-
for (const relayIssuer of relayIssuers) {
|
|
109
|
-
try {
|
|
110
|
-
const rp = pnpApi.resolveRequest(args.path, relayIssuer);
|
|
111
|
-
if (rp !== null)
|
|
112
|
-
return { namespace: "pnp", path: rp, watchFiles };
|
|
113
|
-
} catch {}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
// Fall through — bare aliases (abort-controller, fetch/register/*)
|
|
117
|
-
// are handled by the gjsify alias plugin after this returns null,
|
|
118
|
-
// then the re-resolved @gjsify/* path goes through this hook again.
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
return {
|
|
122
|
-
external: true,
|
|
123
|
-
errors: error ? [{ text: error.message }] : [],
|
|
124
|
-
watchFiles,
|
|
125
|
-
};
|
|
126
|
-
},
|
|
127
|
-
});
|
|
128
|
-
} catch {
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
28
|
+
async function buildPnpPlugin(): Promise<Plugin | null> {
|
|
29
|
+
return getPnpPlugin({
|
|
30
|
+
issuerUrl: import.meta.url,
|
|
31
|
+
transformContentsFactory: (build) => {
|
|
32
|
+
const bundleDir = getBundleDir(build);
|
|
33
|
+
return (args, contents) => rewriteContents(args, contents, bundleDir);
|
|
34
|
+
},
|
|
35
|
+
});
|
|
131
36
|
}
|
|
132
37
|
|
|
133
38
|
export class BuildAction {
|
|
@@ -156,7 +61,7 @@ export class BuildAction {
|
|
|
156
61
|
const multipleBuilds =
|
|
157
62
|
moduleOutdir && mainOutdir && moduleOutdir !== mainOutdir;
|
|
158
63
|
|
|
159
|
-
const pnpPlugin = await
|
|
64
|
+
const pnpPlugin = await buildPnpPlugin();
|
|
160
65
|
const pnpPlugins: Plugin[] = pnpPlugin ? [pnpPlugin] : [];
|
|
161
66
|
|
|
162
67
|
const results: BuildResult[] = [];
|
|
@@ -368,7 +273,7 @@ export class BuildAction {
|
|
|
368
273
|
|
|
369
274
|
const { autoMode, extras } = this.parseGlobalsValue(globals);
|
|
370
275
|
|
|
371
|
-
const pnpPlugin = await
|
|
276
|
+
const pnpPlugin = await buildPnpPlugin();
|
|
372
277
|
const pnpPlugins: Plugin[] = pnpPlugin ? [pnpPlugin] : [];
|
|
373
278
|
|
|
374
279
|
// --- Auto mode (with optional extras): iterative multi-pass build ---
|