Skip to content

Commit 81ae76b

Browse files
committed
fix: make adminforth bundle to use ts proxy - no compilation needed
1 parent ce7e981 commit 81ae76b

File tree

4 files changed

+152
-14
lines changed

4 files changed

+152
-14
lines changed

adminforth/commands/bundle.js

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,50 @@
11
import fs from "fs";
2-
import { getInstance } from "./utils.js";
2+
import { callTsProxy } from "./callTsProxy.js";
3+
import chalk from "chalk";
34

45
async function bundle() {
6+
console.log("Bundling admin SPA...");
57
const currentDirectory = process.cwd();
6-
const files = fs.readdirSync(currentDirectory);
7-
let instanceFound = false;
88

9+
let files = fs.readdirSync(currentDirectory);
10+
let instanceFound = false;
11+
// try index.ts first
12+
if (files.includes("index.ts")) {
13+
files = files.filter((file) => file !== "index.ts");
14+
files.unshift("index.ts");
15+
}
16+
917
for (const file of files) {
10-
if (file.endsWith(".js") || file.endsWith(".ts")) {
18+
if (file.endsWith(".ts")) {
19+
const fileNoTs = file.replace(/\.ts$/, "");
20+
process.env.HEAVY_DEBUG && console.log(`🪲 Trying bundleing ${file}...`);
1121
try {
12-
const instance = await getInstance(file, currentDirectory);
13-
if (instance) {
14-
await instance.bundleNow({ hotReload: false });
15-
instanceFound = true;
16-
break;
17-
}
18-
} catch (error) {
19-
console.error(`Error: Could not bundle '${file}'`, error);
22+
await callTsProxy(`
23+
import { admin } from './${fileNoTs}.js';
24+
25+
export async function exec() {
26+
return await admin.bundleNow({ hotReload: false });
27+
}
28+
`);
29+
instanceFound = true;
30+
break;
31+
32+
} catch (e) {
33+
process.env.HEAVY_DEBUG && console.log(`🪲 File ${file} failed`, e);
2034
}
2135
}
2236
}
2337
if (!instanceFound) {
24-
console.error("Error: No valid instance found to bundle.");
38+
console.error(
39+
chalk.red(
40+
`Error: No valid instance found to bundle.\n` +
41+
`Make sure you have a file in the current directory with a .ts extension, and it exports an ` +
42+
chalk.cyan.bold('admin') +
43+
` instance like:\n\n` +
44+
chalk.yellow('export const admin = new AdminForth({...})') +
45+
`\n\nFor example, adminforth CLI creates an index.ts file which exports the admin instance.`
46+
)
47+
);
2548
return;
2649
}
2750
}

adminforth/commands/callTsProxy.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// callTsProxy.js
2+
import { spawn } from "child_process";
3+
import path from "path";
4+
5+
const currentFilePath = import.meta.url;
6+
const currentFileFolder = path.dirname(currentFilePath).replace("file:", "");
7+
8+
export function callTsProxy(tsCode) {
9+
10+
process.env.HEAVY_DEBUG && console.log("🌐 Calling tsproxy with code:", path.join(currentFileFolder, "proxy.ts"));
11+
return new Promise((resolve, reject) => {
12+
const child = spawn("tsx", [
13+
path.join(currentFileFolder, "proxy.ts")
14+
]);
15+
16+
let stdout = "";
17+
let stderr = "";
18+
19+
child.stdout.on("data", (data) => {
20+
stdout += data;
21+
});
22+
23+
child.stderr.on("data", (data) => {
24+
stderr += data;
25+
});
26+
27+
child.on("close", (code) => {
28+
if (code === 0) {
29+
try {
30+
const parsed = JSON.parse(stdout);
31+
parsed.capturedLogs.forEach((log) => {
32+
console.log(...log);
33+
});
34+
resolve(parsed.result);
35+
} catch (e) {
36+
reject(new Error("Invalid JSON from tsproxy: " + stdout));
37+
}
38+
} else {
39+
try {
40+
const parsedError = JSON.parse(stderr);
41+
process.env.HEAVY_DEBUG && console.error("🪲 Error from tsproxy. Captured logs:", parsedError.capturedLogs);
42+
reject(new Error(parsedError.error));
43+
} catch (e) {
44+
reject(new Error(stderr));
45+
}
46+
}
47+
});
48+
49+
process.env.HEAVY_DEBUG && console.log("🪲 Writing to tsproxy stdin...\n'''", tsCode, "'''");
50+
child.stdin.write(tsCode);
51+
child.stdin.end();
52+
});
53+
}
54+
55+
56+
// Example usage:
57+
// callTsProxy(`
58+
// import admin from './admin';
59+
// function exec() {
60+
// return admin.doX();
61+
// }
62+
// `).then(console.log).catch(console.error);

adminforth/commands/proxy.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// tsproxy.ts
2+
import { writeFile, unlink } from 'fs/promises';
3+
import { randomUUID } from 'crypto';
4+
import { pathToFileURL } from 'url';
5+
import path from 'path';
6+
7+
(async () => {
8+
const chunks: Buffer[] = [];
9+
10+
for await (const chunk of process.stdin) {
11+
chunks.push(chunk);
12+
}
13+
14+
const code = Buffer.concat(chunks).toString();
15+
16+
const tmpFileName = `.tmp-tsproxy-${randomUUID()}.ts`;
17+
18+
const tmpFile = path.join(process.cwd(), tmpFileName);
19+
20+
const origLog = console.log;
21+
let capturedLogs: any[] = [];
22+
console.log = (...args: any[]) => {
23+
capturedLogs.push(args);
24+
}
25+
26+
process.env.HEAVY_DEBUG && console.log(`🪲 TMP proxy file: ${tmpFile}`);
27+
process.env.HEAVY_DEBUG && console.log(`🪲 Current working directory: ${process.cwd()}`);
28+
29+
try {
30+
// Save code to a temp file
31+
await writeFile(tmpFile, code);
32+
33+
// Dynamically import the file
34+
const module = await import(pathToFileURL(tmpFile).href);
35+
36+
if (typeof module.exec !== 'function') {
37+
throw new Error("Module does not export an 'exec' function");
38+
}
39+
40+
const result = await Promise.resolve(module.exec());
41+
42+
// Restore original console.log
43+
console.log = origLog;
44+
console.log(JSON.stringify({ result, capturedLogs }));
45+
} catch (error: any) {
46+
// Restore original console.log
47+
console.log = origLog;
48+
console.error(JSON.stringify({ error: error.message, capturedLogs }));
49+
process.exit(1);
50+
} finally {
51+
await unlink(tmpFile).catch(() => {});
52+
}
53+
})();

adminforth/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ class AdminForth implements IAdminForth {
144144

145145

146146

147-
console.log(`${this.formatAdminForth()} v${ADMINFORTH_VERSION} starting up`)
147+
console.log(`${this.formatAdminForth()} v${ADMINFORTH_VERSION} initializing...`);
148148
}
149149

150150
formatAdminForth() {

0 commit comments

Comments
 (0)