mono-jsx-dom 0.1.4 → 0.1.5
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/bin/build.mjs +12 -9
- package/bin/cli +1 -1
- package/bin/dev.mjs +47 -11
- package/bin/init.mjs +66 -44
- package/package.json +1 -1
- package/server/node-fetch-server.mjs +8 -4
package/bin/build.mjs
CHANGED
|
@@ -60,11 +60,11 @@ async function run() {
|
|
|
60
60
|
const flags = parseFlags();
|
|
61
61
|
const start = performance.now();
|
|
62
62
|
const runtime = flags.node ?? "fetch-server";
|
|
63
|
-
await build({ runtime });
|
|
63
|
+
await build({ serverType: runtime });
|
|
64
64
|
console.log("\x1B[32m\u2728 Build completed.\x1B[0m", "\x1B[90m(%d ms)\x1B[0m", performance.now() - start);
|
|
65
65
|
}
|
|
66
66
|
async function build(options) {
|
|
67
|
-
const workDir = join(cwd(), options?.
|
|
67
|
+
const workDir = join(cwd(), options?.appName ?? ".");
|
|
68
68
|
const outdir = join(workDir, options?.outdir ?? "dist");
|
|
69
69
|
if (!await exists(join(workDir, "index.html"))) {
|
|
70
70
|
console.error("index.html not found");
|
|
@@ -159,7 +159,9 @@ async function build(options) {
|
|
|
159
159
|
for (const file of outputFiles) {
|
|
160
160
|
const contentType = file.path.endsWith(".js") ? "application/javascript" : "text/css";
|
|
161
161
|
const filename = relative(outdir, file.path);
|
|
162
|
-
|
|
162
|
+
if (filename !== tw?.entryCSS) {
|
|
163
|
+
vfs[filename] = await createVFile(indexHTML, filename, file.text, contentType);
|
|
164
|
+
}
|
|
163
165
|
}
|
|
164
166
|
if (tw) {
|
|
165
167
|
const css = await tw.build();
|
|
@@ -173,10 +175,10 @@ async function build(options) {
|
|
|
173
175
|
'import buildJSON$ from "./build.json" with { type: "json" };',
|
|
174
176
|
"server$.setVFS(new Map(Object.entries(buildJSON$)));"
|
|
175
177
|
].join("");
|
|
176
|
-
await buildServerJS(workDir, outdir, options?.
|
|
178
|
+
await buildServerJS(workDir, outdir, options?.serverType, extraJS);
|
|
177
179
|
await dispose();
|
|
178
180
|
}
|
|
179
|
-
async function buildServerJS(workDir, outdir,
|
|
181
|
+
async function buildServerJS(workDir, outdir, serverType = "fetch-server", extraJS, watch) {
|
|
180
182
|
const stdin2 = {
|
|
181
183
|
sourcefile: join(workDir, "server.js"),
|
|
182
184
|
contents: 'import server from "mono-jsx-dom/server;export default server;',
|
|
@@ -185,7 +187,7 @@ async function buildServerJS(workDir, outdir, runtime = "fetch-server", extraJS,
|
|
|
185
187
|
for (const loader of ["ts", "tsx", "js", "jsx"]) {
|
|
186
188
|
const sourcefile = join(workDir, "server." + loader);
|
|
187
189
|
if (await exists(sourcefile)) {
|
|
188
|
-
if (
|
|
190
|
+
if (serverType === "node") {
|
|
189
191
|
stdin2.sourcefile = join(workDir, "server-node.mjs");
|
|
190
192
|
stdin2.resolveDir = workDir;
|
|
191
193
|
stdin2.contents = [
|
|
@@ -235,6 +237,7 @@ async function buildServerJS(workDir, outdir, runtime = "fetch-server", extraJS,
|
|
|
235
237
|
} else {
|
|
236
238
|
await ctx.rebuild();
|
|
237
239
|
await ctx.dispose();
|
|
240
|
+
await esbuild.stop();
|
|
238
241
|
}
|
|
239
242
|
}
|
|
240
243
|
function initTailwindBuilder(workDir, entryCSS) {
|
|
@@ -297,7 +300,7 @@ async function paseIndexHtml(workDir) {
|
|
|
297
300
|
}
|
|
298
301
|
const relativePath = relative(workDir, join(workDir, href));
|
|
299
302
|
entryPoints[relativePath] = relativePath;
|
|
300
|
-
return `<link${attrs}
|
|
303
|
+
return `<link${attrs}href="/${relativePath}">`;
|
|
301
304
|
});
|
|
302
305
|
content = content.replace(/<script(\s[^>]*?)src="([^"]+\.(ts|tsx|js|jsx|mjs))"\s*>/g, (tag, attrs, src) => {
|
|
303
306
|
if (isUrl(src)) {
|
|
@@ -306,7 +309,7 @@ async function paseIndexHtml(workDir) {
|
|
|
306
309
|
const relativePath = relative(workDir, join(workDir, src));
|
|
307
310
|
const resolvedPath = relativePath.slice(0, relativePath.lastIndexOf(".")) + ".js";
|
|
308
311
|
entryPoints[relativePath] = resolvedPath;
|
|
309
|
-
return `<script${attrs}
|
|
312
|
+
return `<script${attrs}src="/${resolvedPath}">`;
|
|
310
313
|
});
|
|
311
314
|
return { content, entryPoints };
|
|
312
315
|
}
|
|
@@ -318,7 +321,7 @@ async function createVFile(indexHTML, filename, content, contentType) {
|
|
|
318
321
|
if (ext !== ".css" && ext !== ".js") {
|
|
319
322
|
filename = filename.slice(0, -ext.length) + ".js";
|
|
320
323
|
}
|
|
321
|
-
indexHTML.content = indexHTML.content.replace('"/' + filename + '"', '"/' + filename + "?hash=" +
|
|
324
|
+
indexHTML.content = indexHTML.content.replace('"/' + filename + '"', '"/' + filename + "?hash=" + contentHash.slice(0, 8) + '"');
|
|
322
325
|
}
|
|
323
326
|
return {
|
|
324
327
|
content,
|
package/bin/cli
CHANGED
package/bin/dev.mjs
CHANGED
|
@@ -50,9 +50,9 @@ async function exists(filename) {
|
|
|
50
50
|
// bin/dev.ts
|
|
51
51
|
import { build } from "./build.mjs";
|
|
52
52
|
async function dev(options) {
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const workDir = join(cwd(), options?.
|
|
53
|
+
const runtime = "Deno" in globalThis ? "deno" : "Bun" in globalThis ? "bun" : "node";
|
|
54
|
+
const ac = options?.ac ?? new AbortController();
|
|
55
|
+
const workDir = join(cwd(), options?.appName ?? ".");
|
|
56
56
|
const outdir = join(workDir, options?.outdir ?? "dist");
|
|
57
57
|
const port = options?.port ?? 3e3;
|
|
58
58
|
const devServerPort = 8798;
|
|
@@ -77,8 +77,11 @@ async function dev(options) {
|
|
|
77
77
|
});
|
|
78
78
|
await serve({
|
|
79
79
|
port: devServerPort,
|
|
80
|
+
hostname: "localhost",
|
|
80
81
|
idleTimeout: 32,
|
|
81
82
|
// 32 seconds
|
|
83
|
+
onListen: (_localAddress) => {
|
|
84
|
+
},
|
|
82
85
|
fetch: async (req) => {
|
|
83
86
|
const { pathname } = new URL(req.url);
|
|
84
87
|
if (pathname === "/__dev_vfs.json") {
|
|
@@ -162,30 +165,49 @@ async function dev(options) {
|
|
|
162
165
|
}
|
|
163
166
|
});
|
|
164
167
|
const serverScript = await resolveModule(join(workDir, "server"), [".ts", ".mjs", ".js"]) ?? join(workDir, "node_modules/mono-jsx-dom/server/index.mjs");
|
|
168
|
+
const args = ["--watch", serverScript];
|
|
169
|
+
if (runtime === "node") {
|
|
170
|
+
args.push("--port", port.toString());
|
|
171
|
+
} else {
|
|
172
|
+
args.unshift("--port", port.toString());
|
|
173
|
+
}
|
|
174
|
+
if (runtime === "deno") {
|
|
175
|
+
args.unshift("serve", "-A");
|
|
176
|
+
}
|
|
165
177
|
const serverProcess = spawn(
|
|
166
|
-
|
|
167
|
-
|
|
178
|
+
runtime,
|
|
179
|
+
args,
|
|
168
180
|
{
|
|
169
181
|
cwd: workDir,
|
|
170
182
|
env: { ...env, DEV_SERVER: devServerUrl },
|
|
171
183
|
stdio: "inherit"
|
|
172
184
|
}
|
|
173
185
|
);
|
|
174
|
-
|
|
186
|
+
const onClose = () => ac.abort();
|
|
187
|
+
serverProcess.on("close", onClose);
|
|
188
|
+
ac.signal.addEventListener("abort", () => {
|
|
189
|
+
serverProcess.off("close", onClose);
|
|
190
|
+
serverProcess.kill();
|
|
191
|
+
});
|
|
175
192
|
};
|
|
176
193
|
const onError = (error) => {
|
|
177
194
|
console.error(error);
|
|
178
195
|
ac.abort();
|
|
179
196
|
};
|
|
180
|
-
if (
|
|
197
|
+
if (runtime === "node") {
|
|
181
198
|
const [major, minor] = versions.node.split(".").map(Number);
|
|
182
199
|
if (major < 22 || major === 22 && minor < 18) {
|
|
183
200
|
console.error("Node.js version 22.18.0 or higher is required to use the dev command.");
|
|
184
201
|
exit2(1);
|
|
185
202
|
}
|
|
186
203
|
}
|
|
204
|
+
process.on("SIGINT", () => {
|
|
205
|
+
console.log("\x1B[90mShutting down dev server...\x1B[0m");
|
|
206
|
+
ac.abort();
|
|
207
|
+
exit2(0);
|
|
208
|
+
});
|
|
187
209
|
await build({
|
|
188
|
-
|
|
210
|
+
appName: options?.appName,
|
|
189
211
|
outdir: options?.outdir,
|
|
190
212
|
dev: {
|
|
191
213
|
signal: ac.signal,
|
|
@@ -194,9 +216,23 @@ async function dev(options) {
|
|
|
194
216
|
}).catch(onError);
|
|
195
217
|
}
|
|
196
218
|
async function serve(options) {
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
219
|
+
const denoServe = globalThis.Deno?.serve;
|
|
220
|
+
const bunServe = globalThis.Bun?.serve;
|
|
221
|
+
if (denoServe) {
|
|
222
|
+
const { fetch, port, signal, hostname, onListen } = options;
|
|
223
|
+
denoServe(
|
|
224
|
+
{
|
|
225
|
+
port,
|
|
226
|
+
signal,
|
|
227
|
+
hostname,
|
|
228
|
+
onListen: onListen ?? ((localAddress) => {
|
|
229
|
+
console.log(`Server is running on http://${hostname ?? "localhost"}:${localAddress.port}`);
|
|
230
|
+
})
|
|
231
|
+
},
|
|
232
|
+
fetch
|
|
233
|
+
);
|
|
234
|
+
} else if (bunServe) {
|
|
235
|
+
const server = bunServe(options);
|
|
200
236
|
options.signal?.addEventListener("abort", () => server.stop());
|
|
201
237
|
} else {
|
|
202
238
|
await import("../server/node-fetch-server.mjs").then((m) => m.serve(options));
|
package/bin/init.mjs
CHANGED
|
@@ -69,6 +69,7 @@ async function input(prompt, placeholder = "") {
|
|
|
69
69
|
return text;
|
|
70
70
|
} finally {
|
|
71
71
|
stdin.setRawMode(wasRaw ?? false);
|
|
72
|
+
stdin.pause();
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
@@ -89,6 +90,7 @@ async function confirm(prompt) {
|
|
|
89
90
|
stdout.write(hint);
|
|
90
91
|
const wasRaw = stdin.isRaw;
|
|
91
92
|
stdin.setRawMode(true);
|
|
93
|
+
stdin.resume();
|
|
92
94
|
try {
|
|
93
95
|
const yes = await new Promise((resolve) => {
|
|
94
96
|
stdin.once("data", (buf) => {
|
|
@@ -117,6 +119,7 @@ async function confirm(prompt) {
|
|
|
117
119
|
return yes;
|
|
118
120
|
} finally {
|
|
119
121
|
stdin.setRawMode(wasRaw ?? false);
|
|
122
|
+
stdin.pause();
|
|
120
123
|
}
|
|
121
124
|
}
|
|
122
125
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
@@ -164,8 +167,8 @@ var template = {
|
|
|
164
167
|
version: "0.0.0",
|
|
165
168
|
private: true,
|
|
166
169
|
scripts: {
|
|
167
|
-
dev: (bun ? "bun --bun" : "") + "
|
|
168
|
-
build: (bun ? "bun --bun" : "") + "
|
|
170
|
+
dev: (bun ? "bun --bun " : "") + "mono-jsx-dom dev",
|
|
171
|
+
build: (bun ? "bun --bun " : "") + "mono-jsx-dom build",
|
|
169
172
|
start: bun ? "bun --bun mono-jsx-dom build && bun dist/server.mjs" : "mono-jsx-dom build --node && node dist/server.mjs"
|
|
170
173
|
}
|
|
171
174
|
},
|
|
@@ -222,17 +225,40 @@ export default {
|
|
|
222
225
|
};
|
|
223
226
|
async function run() {
|
|
224
227
|
const appName = argv2[3] ?? await input("Enter the name of the app", "mono-app");
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
async function init(appName) {
|
|
228
|
-
const appDir = join(cwd(), appName);
|
|
229
|
-
if (await exists(appDir) && !await confirm(`Directory ${appName} already exists. Overwrite?`)) {
|
|
228
|
+
const dir = join(cwd(), appName);
|
|
229
|
+
if (await exists(dir) && !await confirm(`Directory ${appName} already exists. Overwrite?`)) {
|
|
230
230
|
return;
|
|
231
231
|
}
|
|
232
|
+
const tailwindCSS = await confirm("Use TailwindCSS for styling?");
|
|
233
|
+
const wrangler = await confirm("Add Cloudflare Workers integration?");
|
|
234
|
+
const npmCmd = bun ? "bun" : "npm";
|
|
235
|
+
await init({
|
|
236
|
+
dir,
|
|
237
|
+
appName,
|
|
238
|
+
tailwindCSS,
|
|
239
|
+
wrangler,
|
|
240
|
+
onInstall: () => {
|
|
241
|
+
console.log("\x1B[90mInstalling dependencies...\x1B[0m");
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
console.log("");
|
|
245
|
+
console.log("\u2728 \x1B[32mSetup completed.\x1B[0m");
|
|
246
|
+
console.log("You can now start or build the app with the following commands:");
|
|
247
|
+
console.log("");
|
|
248
|
+
console.log(`cd ${appName}`);
|
|
249
|
+
console.log(`${npmCmd} dev${bun ? " " : ""} \x1B[90m# start the app in development mode.\x1B[0m`);
|
|
250
|
+
if (wrangler) {
|
|
251
|
+
console.log(`${npmCmd}${bun ? " run" : ""} deploy \x1B[90m# deploy the app to Cloudflare Workers.\x1B[0m`);
|
|
252
|
+
} else {
|
|
253
|
+
console.log(`${npmCmd}${bun ? " run" : ""} build \x1B[90m# build the app for production.\x1B[0m`);
|
|
254
|
+
console.log(`${npmCmd} start${bun ? " " : ""} \x1B[90m# build and start the app in production mode.\x1B[0m`);
|
|
255
|
+
}
|
|
256
|
+
console.log("");
|
|
257
|
+
}
|
|
258
|
+
async function init(options) {
|
|
259
|
+
const { dir, appName, tailwindCSS, wrangler } = options;
|
|
232
260
|
const scaffold = { ...template };
|
|
233
|
-
|
|
234
|
-
const withWrangler = await confirm("Add Cloudflare Workers integration?");
|
|
235
|
-
if (withWrangler) {
|
|
261
|
+
if (wrangler) {
|
|
236
262
|
scaffold["wrangler.jsonc"] = JSON.stringify(
|
|
237
263
|
{
|
|
238
264
|
$schema: "./node_modules/wrangler/config-schema.json",
|
|
@@ -251,17 +277,17 @@ async function init(appName) {
|
|
|
251
277
|
2
|
|
252
278
|
);
|
|
253
279
|
}
|
|
254
|
-
if (!
|
|
280
|
+
if (!tailwindCSS) {
|
|
255
281
|
scaffold["app/style.css"] = "/* app styles */\n";
|
|
256
282
|
}
|
|
257
|
-
await ensureDir(
|
|
283
|
+
await ensureDir(dir);
|
|
258
284
|
await Promise.all(
|
|
259
285
|
Object.entries(scaffold).map(async ([filename, content]) => {
|
|
260
|
-
const filepath = join(
|
|
286
|
+
const filepath = join(dir, filename);
|
|
261
287
|
if (filename === "package.json") {
|
|
262
288
|
const pkg = JSON.parse(content);
|
|
263
289
|
pkg.name = appName;
|
|
264
|
-
if (
|
|
290
|
+
if (wrangler) {
|
|
265
291
|
pkg.scripts.dev = "wrangler dev";
|
|
266
292
|
pkg.scripts.deploy = "wrangler deploy";
|
|
267
293
|
delete pkg.scripts.build;
|
|
@@ -277,7 +303,7 @@ async function init(appName) {
|
|
|
277
303
|
);
|
|
278
304
|
let tsConfig = /* @__PURE__ */ Object.create(null);
|
|
279
305
|
try {
|
|
280
|
-
const data = await readFile(join(
|
|
306
|
+
const data = await readFile(join(dir, "tsconfig.json"), "utf8");
|
|
281
307
|
tsConfig = JSON.parse(data);
|
|
282
308
|
} catch {
|
|
283
309
|
}
|
|
@@ -289,44 +315,40 @@ async function init(appName) {
|
|
|
289
315
|
compilerOptions.noEmit ??= true;
|
|
290
316
|
compilerOptions.jsx = "react-jsx";
|
|
291
317
|
compilerOptions.jsxImportSource = "mono-jsx-dom";
|
|
292
|
-
await writeFile(join(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
console.log("");
|
|
297
|
-
console.log("\u2728 \x1B[32mSetup completed.\x1B[0m");
|
|
298
|
-
console.log("You can now start or build the app with the following commands:");
|
|
299
|
-
console.log("");
|
|
300
|
-
console.log(`cd ${appName}`);
|
|
301
|
-
console.log(`${cmd} dev${isBun ? " " : ""} \x1B[90m# start the app in development mode.\x1B[0m`);
|
|
302
|
-
if (withWrangler) {
|
|
303
|
-
console.log(`${cmd}${isBun ? " run" : ""} deploy \x1B[90m# deploy the app to Cloudflare Workers.\x1B[0m`);
|
|
304
|
-
} else {
|
|
305
|
-
console.log(`${cmd}${isBun ? " run" : ""} build \x1B[90m# build the app for production.\x1B[0m`);
|
|
306
|
-
console.log(`${cmd} start${isBun ? " " : ""} \x1B[90m# build and start the app in production mode.\x1B[0m`);
|
|
307
|
-
}
|
|
308
|
-
console.log("");
|
|
318
|
+
await writeFile(join(dir, "tsconfig.json"), JSON.stringify(tsConfig, null, 2));
|
|
319
|
+
const depsOptions = { tailwindCSS, wrangler };
|
|
320
|
+
options.onInstall?.(depsOptions);
|
|
321
|
+
installDependencies(dir, depsOptions);
|
|
309
322
|
}
|
|
310
|
-
function
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
315
|
-
spawnSync(cmd, ["add", "mono-jsx-dom"], { cwd: cwd2 });
|
|
323
|
+
function installDependencies(cwd2, options) {
|
|
324
|
+
const { tailwindCSS, wrangler, extraDependencies, extraDevDependencies } = options;
|
|
325
|
+
const npmCmd = bun ? "bun" : "npm";
|
|
326
|
+
const deps = ["mono-jsx-dom"];
|
|
316
327
|
const devDeps = ["esbuild"];
|
|
317
|
-
if (
|
|
328
|
+
if (tailwindCSS) {
|
|
318
329
|
devDeps.push("tailwindcss", "oxide-wasm");
|
|
319
330
|
}
|
|
320
|
-
if (
|
|
331
|
+
if (wrangler) {
|
|
321
332
|
devDeps.push("wrangler");
|
|
322
333
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
334
|
+
if (extraDependencies) {
|
|
335
|
+
deps.push(...extraDependencies);
|
|
336
|
+
}
|
|
337
|
+
if (extraDevDependencies) {
|
|
338
|
+
devDeps.push(...extraDevDependencies);
|
|
339
|
+
}
|
|
340
|
+
spawnSync(npmCmd, ["add", ...deps], { cwd: cwd2 });
|
|
341
|
+
spawnSync(npmCmd, ["add", "-D", ...devDeps], { cwd: cwd2 });
|
|
342
|
+
if (wrangler) {
|
|
343
|
+
if (npmCmd === "bun") {
|
|
344
|
+
spawnSync(npmCmd, ["--bun", "wrangler", "types"], { cwd: cwd2 });
|
|
345
|
+
} else {
|
|
346
|
+
spawnSync(npmCmd, ["wrangler", "types"], { cwd: cwd2 });
|
|
347
|
+
}
|
|
326
348
|
}
|
|
327
|
-
return cmd;
|
|
328
349
|
}
|
|
329
350
|
export {
|
|
330
351
|
init,
|
|
352
|
+
installDependencies,
|
|
331
353
|
run
|
|
332
354
|
};
|
package/package.json
CHANGED
|
@@ -115,12 +115,16 @@ async function sendResponse(res, response) {
|
|
|
115
115
|
res.end();
|
|
116
116
|
}
|
|
117
117
|
function serve(options) {
|
|
118
|
-
const port =
|
|
119
|
-
const server = createServer(createRequestListener(
|
|
118
|
+
const { port = getDefaultPort(), hostname, signal, fetch, onListen } = options;
|
|
119
|
+
const server = createServer(createRequestListener(fetch, options));
|
|
120
120
|
server.listen(port, options?.hostname, () => {
|
|
121
|
-
|
|
121
|
+
if (onListen) {
|
|
122
|
+
onListen({ port });
|
|
123
|
+
} else {
|
|
124
|
+
console.log(`Server is running on http://${hostname ?? "localhost"}:${port}`);
|
|
125
|
+
}
|
|
122
126
|
});
|
|
123
|
-
|
|
127
|
+
signal?.addEventListener("abort", () => {
|
|
124
128
|
server.close();
|
|
125
129
|
});
|
|
126
130
|
return new Promise((resolve, reject) => {
|