@gjsify/cli 0.3.3 → 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.js +61 -8
- package/package.json +10 -10
- package/src/actions/build.ts +65 -8
package/lib/actions/build.js
CHANGED
|
@@ -2,8 +2,10 @@ 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
4
|
import { dirname, extname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { chmod, readFile, writeFile } from "node:fs/promises";
|
|
6
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) {
|
|
@@ -22,26 +24,77 @@ function findPnpRoot(dir) {
|
|
|
22
24
|
* @yarnpkg/esbuild-plugin-pnp plugin so esbuild can resolve
|
|
23
25
|
* modules from zip archives without manual extraction.
|
|
24
26
|
*
|
|
25
|
-
* Custom onResolve:
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* gjsify
|
|
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.
|
|
29
36
|
*/
|
|
30
37
|
async function getPnpPlugin() {
|
|
31
38
|
if (!findPnpRoot(process.cwd()))
|
|
32
39
|
return null;
|
|
33
40
|
try {
|
|
34
41
|
const { pnpPlugin } = await import("@yarnpkg/esbuild-plugin-pnp");
|
|
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
|
+
}
|
|
35
68
|
return pnpPlugin({
|
|
36
|
-
onResolve: async (
|
|
69
|
+
onResolve: async (args, { resolvedPath, error, watchFiles }) => {
|
|
37
70
|
if (resolvedPath !== null) {
|
|
38
71
|
return { namespace: "pnp", path: resolvedPath, watchFiles };
|
|
39
72
|
}
|
|
40
|
-
// UNDECLARED_DEPENDENCY: package exists transitively but isn't
|
|
41
|
-
// in the issuer's direct deps. Fall through so the gjsify alias
|
|
42
|
-
// plugin can resolve it (e.g. bare → @gjsify/* mappings).
|
|
43
73
|
if (error?.pnpCode ===
|
|
44
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.
|
|
45
98
|
return null;
|
|
46
99
|
}
|
|
47
100
|
return {
|
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
|
@@ -8,8 +8,10 @@ import {
|
|
|
8
8
|
detectAutoGlobals,
|
|
9
9
|
} from "@gjsify/esbuild-plugin-gjsify/globals";
|
|
10
10
|
import { dirname, extname, join } from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
11
12
|
import { chmod, readFile, writeFile } from "node:fs/promises";
|
|
12
13
|
import { existsSync } from "node:fs";
|
|
14
|
+
import { createRequire } from "node:module";
|
|
13
15
|
|
|
14
16
|
const GJS_SHEBANG = "#!/usr/bin/env -S gjs -m\n";
|
|
15
17
|
|
|
@@ -29,27 +31,82 @@ function findPnpRoot(dir: string): string | null {
|
|
|
29
31
|
* @yarnpkg/esbuild-plugin-pnp plugin so esbuild can resolve
|
|
30
32
|
* modules from zip archives without manual extraction.
|
|
31
33
|
*
|
|
32
|
-
* Custom onResolve:
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* gjsify
|
|
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.
|
|
36
43
|
*/
|
|
37
44
|
async function getPnpPlugin(): Promise<Plugin | null> {
|
|
38
45
|
if (!findPnpRoot(process.cwd())) return null;
|
|
39
46
|
try {
|
|
40
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
|
+
|
|
41
80
|
return pnpPlugin({
|
|
42
|
-
onResolve: async (
|
|
81
|
+
onResolve: async (args, { resolvedPath, error, watchFiles }) => {
|
|
43
82
|
if (resolvedPath !== null) {
|
|
44
83
|
return { namespace: "pnp", path: resolvedPath, watchFiles };
|
|
45
84
|
}
|
|
46
|
-
// UNDECLARED_DEPENDENCY: package exists transitively but isn't
|
|
47
|
-
// in the issuer's direct deps. Fall through so the gjsify alias
|
|
48
|
-
// plugin can resolve it (e.g. bare → @gjsify/* mappings).
|
|
49
85
|
if (
|
|
50
86
|
(error as { pnpCode?: string } | null)?.pnpCode ===
|
|
51
87
|
"UNDECLARED_DEPENDENCY"
|
|
52
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.
|
|
53
110
|
return null;
|
|
54
111
|
}
|
|
55
112
|
return {
|