hadars 1.0.1 → 1.0.3
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/README.md +13 -13
- package/dist/{chunk-U2JQR4HV.js → chunk-PQ5N5GOY.js} +33 -12
- package/dist/{chunk-HIKMDNRB.js → chunk-QOTDCUE5.js} +28 -35
- package/dist/cli.js +370 -207
- package/dist/cloudflare.cjs +52 -40
- package/dist/cloudflare.js +2 -3
- package/dist/index.js +0 -2
- package/dist/lambda.cjs +52 -40
- package/dist/lambda.js +2 -3
- package/dist/slim-react/index.cjs +29 -32
- package/dist/slim-react/index.d.cts +3 -1
- package/dist/slim-react/index.d.ts +3 -1
- package/dist/slim-react/index.js +3 -2
- package/dist/slim-react/jsx-runtime.js +0 -1
- package/dist/ssr-render-worker.js +22 -28
- package/package.json +1 -1
- package/dist/chunk-3RG5ZIWI.js +0 -10
package/dist/cli.js
CHANGED
|
@@ -148,7 +148,6 @@ var REACT19_ELEMENT = Symbol.for("react.transitional.element");
|
|
|
148
148
|
var FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
149
149
|
var SUSPENSE_TYPE = Symbol.for("react.suspense");
|
|
150
150
|
// src/slim-react/renderContext.ts
|
|
151
|
-
import { createRequire as _nodeCreateRequire } from "node:module";
|
|
152
151
|
var MAP_KEY = "__slimReactContextMap";
|
|
153
152
|
var _g = globalThis;
|
|
154
153
|
if (!("__slimReactContextMap" in _g))
|
|
@@ -285,27 +284,8 @@ function getTreeId() {
|
|
|
285
284
|
const stripped = (id & ~(1 << 31 - Math.clz32(id))).toString(32);
|
|
286
285
|
return stripped + overflow;
|
|
287
286
|
}
|
|
288
|
-
var
|
|
289
|
-
|
|
290
|
-
const major = parseInt(String(__HADARS_REACT_MAJOR__), 10);
|
|
291
|
-
return {
|
|
292
|
-
major,
|
|
293
|
-
version: major < 19 ? "18.3.1" : "19.1.1"
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
const parse = (ver) => ({ major: parseInt(ver.split(".")[0], 10), version: ver });
|
|
297
|
-
try {
|
|
298
|
-
return parse(__require("react").version);
|
|
299
|
-
} catch {}
|
|
300
|
-
try {
|
|
301
|
-
const req = _nodeCreateRequire(process.cwd() + "/__hadars__.js");
|
|
302
|
-
return parse(req("react").version);
|
|
303
|
-
} catch {}
|
|
304
|
-
return { major: 19, version: "19.1.1" };
|
|
305
|
-
};
|
|
306
|
-
var _react = _detectReact();
|
|
307
|
-
var REACT_MAJOR = _react.major;
|
|
308
|
-
var REACT_VERSION = _react.version;
|
|
287
|
+
var REACT_MAJOR = typeof __HADARS_REACT_MAJOR__ !== "undefined" ? parseInt(String(__HADARS_REACT_MAJOR__), 10) : 19;
|
|
288
|
+
var REACT_VERSION = REACT_MAJOR < 19 ? "18.3.1" : "19.1.1";
|
|
309
289
|
function makeId() {
|
|
310
290
|
const st = s();
|
|
311
291
|
const treeId = getTreeId();
|
|
@@ -385,9 +365,24 @@ function use(usable) {
|
|
|
385
365
|
}
|
|
386
366
|
// src/slim-react/dispatcher.ts
|
|
387
367
|
import * as ReactNS from "react";
|
|
388
|
-
var _r19
|
|
389
|
-
var
|
|
390
|
-
var
|
|
368
|
+
var _r19;
|
|
369
|
+
var _r18;
|
|
370
|
+
var _detected = false;
|
|
371
|
+
var _k19 = "__CLIENT_INTERNALS_DO_NOT_USE" + "_OR_WARN_USERS_THEY_CANNOT_UPGRADE";
|
|
372
|
+
var _k18 = "__SECRET_INTERNALS_DO_NOT_USE" + "_OR_YOU_WILL_BE_FIRED";
|
|
373
|
+
function _detect() {
|
|
374
|
+
if (_detected)
|
|
375
|
+
return;
|
|
376
|
+
_detected = true;
|
|
377
|
+
const r19 = ReactNS[_k19];
|
|
378
|
+
if (r19) {
|
|
379
|
+
_r19 = r19;
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const raw = ReactNS[_k18];
|
|
383
|
+
if (raw?.ReactCurrentDispatcher)
|
|
384
|
+
_r18 = raw;
|
|
385
|
+
}
|
|
391
386
|
var slimDispatcher = {
|
|
392
387
|
useId: makeId,
|
|
393
388
|
readContext: (ctx) => getContextValue(ctx),
|
|
@@ -413,6 +408,7 @@ var slimDispatcher = {
|
|
|
413
408
|
useHostTransitionStatus: () => false
|
|
414
409
|
};
|
|
415
410
|
function installDispatcher() {
|
|
411
|
+
_detect();
|
|
416
412
|
if (_r19) {
|
|
417
413
|
const prev = _r19.H;
|
|
418
414
|
_r19.H = slimDispatcher;
|
|
@@ -426,6 +422,7 @@ function installDispatcher() {
|
|
|
426
422
|
return null;
|
|
427
423
|
}
|
|
428
424
|
function restoreDispatcher(prev) {
|
|
425
|
+
_detect();
|
|
429
426
|
if (_r19)
|
|
430
427
|
_r19.H = prev;
|
|
431
428
|
else if (_r18)
|
|
@@ -1223,14 +1220,28 @@ var getReactResponse = async (req, opts) => {
|
|
|
1223
1220
|
globalThis.__hadarsUnsuspend = unsuspend;
|
|
1224
1221
|
globalThis.__hadarsContext = context;
|
|
1225
1222
|
const element = createElement(App, props);
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
globalThis.
|
|
1230
|
-
|
|
1223
|
+
let bodyHtml = null;
|
|
1224
|
+
if (opts.singlePass) {
|
|
1225
|
+
globalThis.__hadarsUnsuspend = unsuspend;
|
|
1226
|
+
globalThis.__hadarsContext = context;
|
|
1227
|
+
try {
|
|
1228
|
+
bodyHtml = await renderToString(element);
|
|
1229
|
+
} finally {
|
|
1230
|
+
globalThis.__hadarsUnsuspend = null;
|
|
1231
|
+
globalThis.__hadarsContext = null;
|
|
1232
|
+
}
|
|
1233
|
+
} else {
|
|
1234
|
+
try {
|
|
1235
|
+
await renderPreflight(element);
|
|
1236
|
+
} finally {
|
|
1237
|
+
globalThis.__hadarsUnsuspend = null;
|
|
1238
|
+
globalThis.__hadarsContext = null;
|
|
1239
|
+
}
|
|
1231
1240
|
}
|
|
1232
1241
|
const status = context.head.status;
|
|
1233
1242
|
const getAppBody = async () => {
|
|
1243
|
+
if (bodyHtml !== null)
|
|
1244
|
+
return bodyHtml;
|
|
1234
1245
|
globalThis.__hadarsUnsuspend = unsuspend;
|
|
1235
1246
|
globalThis.__hadarsContext = context;
|
|
1236
1247
|
try {
|
|
@@ -1826,15 +1837,23 @@ async function transformStream(data, stream) {
|
|
|
1826
1837
|
}
|
|
1827
1838
|
return out;
|
|
1828
1839
|
}
|
|
1840
|
+
var _zlibGzip = null;
|
|
1841
|
+
var _zlibGunzip = null;
|
|
1829
1842
|
async function zlibGzip(d) {
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1843
|
+
if (!_zlibGzip) {
|
|
1844
|
+
const zlib = await import("node:zlib");
|
|
1845
|
+
const { promisify } = await import("node:util");
|
|
1846
|
+
_zlibGzip = promisify(zlib.gzip);
|
|
1847
|
+
}
|
|
1848
|
+
return _zlibGzip(d);
|
|
1833
1849
|
}
|
|
1834
1850
|
async function zlibGunzip(d) {
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1851
|
+
if (!_zlibGunzip) {
|
|
1852
|
+
const zlib = await import("node:zlib");
|
|
1853
|
+
const { promisify } = await import("node:util");
|
|
1854
|
+
_zlibGunzip = promisify(zlib.gunzip);
|
|
1855
|
+
}
|
|
1856
|
+
return _zlibGunzip(d);
|
|
1838
1857
|
}
|
|
1839
1858
|
var gzipCompress = (d) => globalThis.CompressionStream ? transformStream(d, new globalThis.CompressionStream("gzip")) : zlibGzip(d);
|
|
1840
1859
|
var gzipDecompress = (d) => globalThis.DecompressionStream ? transformStream(d, new globalThis.DecompressionStream("gzip")) : zlibGunzip(d);
|
|
@@ -2568,6 +2587,8 @@ var dev = async (options) => {
|
|
|
2568
2587
|
const tmpFilePath = pathMod2.join(HADARS_TMP_DIR, `client-${Date.now()}.tsx`);
|
|
2569
2588
|
await fs.writeFile(tmpFilePath, clientScript);
|
|
2570
2589
|
let ssrBuildId = crypto.randomBytes(4).toString("hex");
|
|
2590
|
+
let cachedSsrModule = null;
|
|
2591
|
+
let cachedSsrBuildId = "";
|
|
2571
2592
|
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod2.resolve(__dirname3, options.htmlTemplate)) : undefined;
|
|
2572
2593
|
const clientCompiler = createClientCompiler(tmpFilePath, {
|
|
2573
2594
|
target: "web",
|
|
@@ -2742,13 +2763,17 @@ var dev = async (options) => {
|
|
|
2742
2763
|
if (projectRes)
|
|
2743
2764
|
return projectRes;
|
|
2744
2765
|
const ssrComponentPath = pathMod2.join(__dirname3, HadarsFolder, SSR_FILENAME);
|
|
2745
|
-
const importPath = pathToFileURL(ssrComponentPath).href + `?t=${ssrBuildId}`;
|
|
2746
2766
|
try {
|
|
2767
|
+
if (ssrBuildId !== cachedSsrBuildId) {
|
|
2768
|
+
const importPath = pathToFileURL(ssrComponentPath).href + `?t=${ssrBuildId}`;
|
|
2769
|
+
cachedSsrModule = await import(importPath);
|
|
2770
|
+
cachedSsrBuildId = ssrBuildId;
|
|
2771
|
+
}
|
|
2747
2772
|
const {
|
|
2748
2773
|
default: Component,
|
|
2749
2774
|
getInitProps,
|
|
2750
2775
|
getFinalProps
|
|
2751
|
-
} =
|
|
2776
|
+
} = cachedSsrModule;
|
|
2752
2777
|
globalThis.__hadarsGraphQL = devStaticCtx?.graphql;
|
|
2753
2778
|
const { head, status, getAppBody, finalize } = await getReactResponse(request, {
|
|
2754
2779
|
document: {
|
|
@@ -2757,7 +2782,8 @@ var dev = async (options) => {
|
|
|
2757
2782
|
getInitProps,
|
|
2758
2783
|
getFinalProps
|
|
2759
2784
|
},
|
|
2760
|
-
staticCtx: devStaticCtx
|
|
2785
|
+
staticCtx: devStaticCtx,
|
|
2786
|
+
singlePass: true
|
|
2761
2787
|
});
|
|
2762
2788
|
if (request.headers.get("Accept") === "application/json") {
|
|
2763
2789
|
const { clientProps } = await finalize();
|
|
@@ -2916,7 +2942,8 @@ var run = async (options) => {
|
|
|
2916
2942
|
lang: "en",
|
|
2917
2943
|
getInitProps,
|
|
2918
2944
|
getFinalProps
|
|
2919
|
-
}
|
|
2945
|
+
},
|
|
2946
|
+
singlePass: true
|
|
2920
2947
|
});
|
|
2921
2948
|
if (request.headers.get("Accept") === "application/json") {
|
|
2922
2949
|
const { clientProps } = await finalize();
|
|
@@ -3232,8 +3259,166 @@ Deploy instructions:`);
|
|
|
3232
3259
|
await unlink(shimPath).catch(() => {});
|
|
3233
3260
|
}
|
|
3234
3261
|
}
|
|
3235
|
-
var
|
|
3236
|
-
|
|
3262
|
+
var _R = "\x1B[0m";
|
|
3263
|
+
var _B = "\x1B[1m";
|
|
3264
|
+
var _D = "\x1B[2m";
|
|
3265
|
+
var _C = "\x1B[36m";
|
|
3266
|
+
var _G = "\x1B[32m";
|
|
3267
|
+
var _UP_KEY = "\x1B[A";
|
|
3268
|
+
var _DOWN_KEY = "\x1B[B";
|
|
3269
|
+
var _HIDE = "\x1B[?25l";
|
|
3270
|
+
var _SHOW = "\x1B[?25h";
|
|
3271
|
+
var _cl = () => "\r\x1B[2K";
|
|
3272
|
+
var _up = (n) => n > 0 ? `\x1B[${n}A` : "";
|
|
3273
|
+
function _readKeys(handler) {
|
|
3274
|
+
return new Promise((resolve2) => {
|
|
3275
|
+
const { stdin } = process;
|
|
3276
|
+
const wasRaw = stdin.isTTY && stdin.isRaw;
|
|
3277
|
+
if (stdin.isTTY)
|
|
3278
|
+
stdin.setRawMode(true);
|
|
3279
|
+
stdin.resume();
|
|
3280
|
+
stdin.setEncoding("utf-8");
|
|
3281
|
+
const onData = (key) => {
|
|
3282
|
+
if (key === "\x03") {
|
|
3283
|
+
cleanup();
|
|
3284
|
+
process.stdout.write(_SHOW);
|
|
3285
|
+
process.exit(130);
|
|
3286
|
+
}
|
|
3287
|
+
if (handler(key))
|
|
3288
|
+
cleanup();
|
|
3289
|
+
};
|
|
3290
|
+
const cleanup = () => {
|
|
3291
|
+
stdin.removeListener("data", onData);
|
|
3292
|
+
if (stdin.isTTY && !wasRaw)
|
|
3293
|
+
stdin.setRawMode(false);
|
|
3294
|
+
stdin.pause();
|
|
3295
|
+
resolve2();
|
|
3296
|
+
};
|
|
3297
|
+
stdin.on("data", onData);
|
|
3298
|
+
});
|
|
3299
|
+
}
|
|
3300
|
+
async function promptRadio(question, options) {
|
|
3301
|
+
const out = process.stdout;
|
|
3302
|
+
let cursor = 0;
|
|
3303
|
+
const total = 1 + options.length;
|
|
3304
|
+
const render = (redraw) => {
|
|
3305
|
+
if (redraw)
|
|
3306
|
+
out.write(_up(total));
|
|
3307
|
+
out.write(`${_cl()} ${_B}${question}${_R}
|
|
3308
|
+
`);
|
|
3309
|
+
for (let i = 0;i < options.length; i++) {
|
|
3310
|
+
const arrow = i === cursor ? `${_C}❯${_R}` : " ";
|
|
3311
|
+
const text = i === cursor ? `${_B}${options[i]}${_R}` : `${_D}${options[i]}${_R}`;
|
|
3312
|
+
out.write(`${_cl()} ${arrow} ${text}
|
|
3313
|
+
`);
|
|
3314
|
+
}
|
|
3315
|
+
};
|
|
3316
|
+
out.write(_HIDE);
|
|
3317
|
+
render(false);
|
|
3318
|
+
await _readKeys((key) => {
|
|
3319
|
+
if (key === _UP_KEY && cursor > 0) {
|
|
3320
|
+
cursor--;
|
|
3321
|
+
render(true);
|
|
3322
|
+
} else if (key === _DOWN_KEY && cursor < options.length - 1) {
|
|
3323
|
+
cursor++;
|
|
3324
|
+
render(true);
|
|
3325
|
+
} else if (key === "\r") {
|
|
3326
|
+
return true;
|
|
3327
|
+
}
|
|
3328
|
+
return false;
|
|
3329
|
+
});
|
|
3330
|
+
out.write(_up(total));
|
|
3331
|
+
out.write(`${_cl()} ${question} ${_C}${_B}${options[cursor]}${_R}
|
|
3332
|
+
`);
|
|
3333
|
+
for (let i = 0;i < options.length; i++)
|
|
3334
|
+
out.write(`${_cl()}
|
|
3335
|
+
`);
|
|
3336
|
+
out.write(_up(options.length));
|
|
3337
|
+
out.write(_SHOW);
|
|
3338
|
+
return cursor;
|
|
3339
|
+
}
|
|
3340
|
+
async function promptMultiSelect(question, options) {
|
|
3341
|
+
const out = process.stdout;
|
|
3342
|
+
let cursor = 0;
|
|
3343
|
+
const selected = new Set;
|
|
3344
|
+
const total = 2 + options.length;
|
|
3345
|
+
const render = (redraw) => {
|
|
3346
|
+
if (redraw)
|
|
3347
|
+
out.write(_up(total));
|
|
3348
|
+
out.write(`${_cl()} ${_B}${question}${_R}
|
|
3349
|
+
`);
|
|
3350
|
+
out.write(`${_cl()} ${_D}↑↓ navigate · Space select · Enter confirm${_R}
|
|
3351
|
+
`);
|
|
3352
|
+
for (let i = 0;i < options.length; i++) {
|
|
3353
|
+
const arrow = i === cursor ? `${_C}❯${_R}` : " ";
|
|
3354
|
+
const box = selected.has(i) ? `${_G}●${_R}` : `${_D}○${_R}`;
|
|
3355
|
+
const text = i === cursor ? `${_B}${options[i]}${_R}` : `${_D}${options[i]}${_R}`;
|
|
3356
|
+
out.write(`${_cl()} ${arrow} ${box} ${text}
|
|
3357
|
+
`);
|
|
3358
|
+
}
|
|
3359
|
+
};
|
|
3360
|
+
out.write(_HIDE);
|
|
3361
|
+
render(false);
|
|
3362
|
+
await _readKeys((key) => {
|
|
3363
|
+
if (key === _UP_KEY && cursor > 0) {
|
|
3364
|
+
cursor--;
|
|
3365
|
+
render(true);
|
|
3366
|
+
} else if (key === _DOWN_KEY && cursor < options.length - 1) {
|
|
3367
|
+
cursor++;
|
|
3368
|
+
render(true);
|
|
3369
|
+
} else if (key === " ") {
|
|
3370
|
+
selected.has(cursor) ? selected.delete(cursor) : selected.add(cursor);
|
|
3371
|
+
render(true);
|
|
3372
|
+
} else if (key === "\r") {
|
|
3373
|
+
return true;
|
|
3374
|
+
}
|
|
3375
|
+
return false;
|
|
3376
|
+
});
|
|
3377
|
+
const picked = [...selected].sort((a, b) => a - b);
|
|
3378
|
+
const summary = picked.length > 0 ? picked.map((i) => options[i]).join(", ") : "none";
|
|
3379
|
+
out.write(_up(total));
|
|
3380
|
+
out.write(`${_cl()} ${question} ${_C}${_B}${summary}${_R}
|
|
3381
|
+
`);
|
|
3382
|
+
for (let i = 0;i < total - 1; i++)
|
|
3383
|
+
out.write(`${_cl()}
|
|
3384
|
+
`);
|
|
3385
|
+
out.write(_up(total - 1));
|
|
3386
|
+
out.write(_SHOW);
|
|
3387
|
+
return picked;
|
|
3388
|
+
}
|
|
3389
|
+
var PLUGINS = [
|
|
3390
|
+
{ pkg: "@swc/plugin-emotion", version: "12.0.0", label: "Emotion (CSS-in-JS)" },
|
|
3391
|
+
{ pkg: "@swc/plugin-styled-components", version: "10.0.0", label: "styled-components" },
|
|
3392
|
+
{ pkg: "@swc/plugin-relay", version: "10.0.0", label: "Relay (GraphQL)" },
|
|
3393
|
+
{ pkg: "@swc/plugin-styled-jsx", version: "11.0.0", label: "styled-jsx" },
|
|
3394
|
+
{ pkg: "@swc/plugin-transform-imports", version: "10.0.0", label: "transform-imports" },
|
|
3395
|
+
{ pkg: "@swc/plugin-loadable-components", version: "9.0.0", label: "Loadable Components" },
|
|
3396
|
+
{ pkg: "@swc/plugin-formatjs", version: "7.0.0", label: "FormatJS (i18n)" }
|
|
3397
|
+
];
|
|
3398
|
+
function renderSwcPluginsConfig(plugins) {
|
|
3399
|
+
if (plugins.length === 0)
|
|
3400
|
+
return "";
|
|
3401
|
+
const lines = plugins.map((p) => {
|
|
3402
|
+
if (p.pkg === "@swc/plugin-relay") {
|
|
3403
|
+
return ` ['${p.pkg}', { rootDir: process.cwd(), artifactDirectory: 'src/__generated__' }],`;
|
|
3404
|
+
}
|
|
3405
|
+
return ` ['${p.pkg}', {}],`;
|
|
3406
|
+
});
|
|
3407
|
+
return `
|
|
3408
|
+
swcPlugins: [
|
|
3409
|
+
${lines.join(`
|
|
3410
|
+
`)}
|
|
3411
|
+
],`;
|
|
3412
|
+
}
|
|
3413
|
+
function buildTemplates(name, opts) {
|
|
3414
|
+
const { useTypeScript, plugins } = opts;
|
|
3415
|
+
const appExt = useTypeScript ? "tsx" : "jsx";
|
|
3416
|
+
const cfgExt = useTypeScript ? "ts" : "js";
|
|
3417
|
+
const tsOrJs = useTypeScript ? "tsconfig.json" : "jsconfig.json";
|
|
3418
|
+
const pluginDeps = {};
|
|
3419
|
+
for (const p of plugins)
|
|
3420
|
+
pluginDeps[p.pkg] = p.version;
|
|
3421
|
+
const packageJson = JSON.stringify({
|
|
3237
3422
|
name,
|
|
3238
3423
|
version: "0.1.0",
|
|
3239
3424
|
type: "module",
|
|
@@ -3247,19 +3432,28 @@ var TEMPLATES = {
|
|
|
3247
3432
|
hadars: "latest",
|
|
3248
3433
|
react: "^19.0.0",
|
|
3249
3434
|
"react-dom": "^19.0.0"
|
|
3250
|
-
}
|
|
3435
|
+
},
|
|
3436
|
+
...Object.keys(pluginDeps).length > 0 ? { devDependencies: pluginDeps } : {}
|
|
3251
3437
|
}, null, 2) + `
|
|
3252
|
-
|
|
3253
|
-
|
|
3438
|
+
`;
|
|
3439
|
+
const swcSection = renderSwcPluginsConfig(plugins);
|
|
3440
|
+
const hadarsConfig = useTypeScript ? `import type { HadarsOptions } from 'hadars';
|
|
3254
3441
|
|
|
3255
3442
|
const config: HadarsOptions = {
|
|
3256
3443
|
entry: 'src/App.tsx',
|
|
3257
|
-
port: 3000
|
|
3444
|
+
port: 3000,${swcSection}
|
|
3258
3445
|
};
|
|
3259
3446
|
|
|
3260
3447
|
export default config;
|
|
3261
|
-
|
|
3262
|
-
|
|
3448
|
+
` : `/** @type {import('hadars').HadarsOptions} */
|
|
3449
|
+
const config = {
|
|
3450
|
+
entry: 'src/App.jsx',
|
|
3451
|
+
port: 3000,${swcSection}
|
|
3452
|
+
};
|
|
3453
|
+
|
|
3454
|
+
export default config;
|
|
3455
|
+
`;
|
|
3456
|
+
const tsConfigContent = useTypeScript ? JSON.stringify({
|
|
3263
3457
|
compilerOptions: {
|
|
3264
3458
|
lib: ["ESNext", "DOM"],
|
|
3265
3459
|
target: "ESNext",
|
|
@@ -3274,215 +3468,184 @@ export default config;
|
|
|
3274
3468
|
skipLibCheck: true
|
|
3275
3469
|
}
|
|
3276
3470
|
}, null, 2) + `
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3471
|
+
` : JSON.stringify({
|
|
3472
|
+
compilerOptions: {
|
|
3473
|
+
lib: ["ESNext", "DOM"],
|
|
3474
|
+
target: "ESNext",
|
|
3475
|
+
module: "ESNext",
|
|
3476
|
+
moduleResolution: "bundler",
|
|
3477
|
+
jsx: "react-jsx",
|
|
3478
|
+
checkJs: true,
|
|
3479
|
+
noEmit: true,
|
|
3480
|
+
skipLibCheck: true
|
|
3481
|
+
}
|
|
3482
|
+
}, null, 2) + `
|
|
3483
|
+
`;
|
|
3484
|
+
const appImports = useTypeScript ? `import React from 'react';
|
|
3485
|
+
import { HadarsHead, type HadarsApp } from 'hadars';` : `import React from 'react';
|
|
3486
|
+
import { HadarsHead } from 'hadars';`;
|
|
3487
|
+
const appSignature = useTypeScript ? `const App: HadarsApp<{}> = () => {` : `const App = () => {`;
|
|
3488
|
+
const appContent = `${appImports}
|
|
3284
3489
|
|
|
3285
3490
|
const css = \`
|
|
3286
|
-
*, *::before, *::after { box-sizing: border-box;
|
|
3491
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
3287
3492
|
|
|
3288
|
-
|
|
3289
|
-
font-family: -
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3493
|
+
:root {
|
|
3494
|
+
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
3495
|
+
line-height: 1.5;
|
|
3496
|
+
font-weight: 400;
|
|
3497
|
+
color-scheme: light dark;
|
|
3498
|
+
color: rgba(255, 255, 255, 0.87);
|
|
3499
|
+
background-color: #242424;
|
|
3500
|
+
font-synthesis: none;
|
|
3501
|
+
text-rendering: optimizeLegibility;
|
|
3502
|
+
-webkit-font-smoothing: antialiased;
|
|
3293
3503
|
}
|
|
3294
3504
|
|
|
3295
|
-
|
|
3296
|
-
display: flex;
|
|
3297
|
-
align-items: center;
|
|
3298
|
-
justify-content: space-between;
|
|
3299
|
-
padding: 1rem 2rem;
|
|
3300
|
-
border-bottom: 1px solid #1e1e2e;
|
|
3301
|
-
}
|
|
3302
|
-
.nav-brand { font-weight: 700; font-size: 1.1rem; color: #a78bfa; letter-spacing: -0.02em; }
|
|
3303
|
-
.nav-links { display: flex; gap: 1.5rem; }
|
|
3304
|
-
.nav-links a { color: #94a3b8; text-decoration: none; font-size: 0.9rem; }
|
|
3305
|
-
.nav-links a:hover { color: #e2e8f0; }
|
|
3505
|
+
body { margin: 0; }
|
|
3306
3506
|
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
padding: 5rem 1rem 4rem;
|
|
3310
|
-
max-width: 680px;
|
|
3507
|
+
#app {
|
|
3508
|
+
max-width: 1280px;
|
|
3311
3509
|
margin: 0 auto;
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
display:
|
|
3315
|
-
|
|
3316
|
-
border: 1px solid #4c1d95;
|
|
3317
|
-
color: #a78bfa;
|
|
3318
|
-
font-size: 0.75rem;
|
|
3319
|
-
font-weight: 600;
|
|
3320
|
-
letter-spacing: 0.05em;
|
|
3321
|
-
text-transform: uppercase;
|
|
3322
|
-
padding: 0.3rem 0.8rem;
|
|
3323
|
-
border-radius: 999px;
|
|
3324
|
-
margin-bottom: 1.5rem;
|
|
3325
|
-
}
|
|
3326
|
-
.hero h1 {
|
|
3327
|
-
font-size: clamp(2rem, 5vw, 3.25rem);
|
|
3328
|
-
font-weight: 800;
|
|
3329
|
-
letter-spacing: -0.03em;
|
|
3330
|
-
line-height: 1.15;
|
|
3331
|
-
margin-bottom: 1rem;
|
|
3332
|
-
}
|
|
3333
|
-
.hero h1 span { color: #a78bfa; }
|
|
3334
|
-
.hero p {
|
|
3335
|
-
font-size: 1.1rem;
|
|
3336
|
-
color: #94a3b8;
|
|
3337
|
-
line-height: 1.7;
|
|
3338
|
-
margin-bottom: 2.5rem;
|
|
3339
|
-
}
|
|
3340
|
-
.hero-actions { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }
|
|
3341
|
-
.btn {
|
|
3342
|
-
display: inline-flex;
|
|
3510
|
+
padding: 2rem;
|
|
3511
|
+
text-align: center;
|
|
3512
|
+
display: flex;
|
|
3513
|
+
flex-direction: column;
|
|
3343
3514
|
align-items: center;
|
|
3344
|
-
|
|
3345
|
-
|
|
3515
|
+
justify-content: center;
|
|
3516
|
+
min-height: 100vh;
|
|
3517
|
+
}
|
|
3518
|
+
|
|
3519
|
+
.logos { display: flex; align-items: center; justify-content: center; gap: 1rem; margin-bottom: 1.5rem; }
|
|
3520
|
+
|
|
3521
|
+
.logo {
|
|
3522
|
+
height: 6em;
|
|
3523
|
+
padding: 1.5em;
|
|
3524
|
+
will-change: filter;
|
|
3525
|
+
transition: filter 300ms;
|
|
3526
|
+
}
|
|
3527
|
+
.logo-react { animation: spin 20s linear infinite; }
|
|
3528
|
+
.logo-react:hover { filter: drop-shadow(0 0 2em #61dafbaa); }
|
|
3529
|
+
|
|
3530
|
+
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
|
3531
|
+
@media (prefers-reduced-motion: reduce) { .logo-react { animation: none; } }
|
|
3532
|
+
|
|
3533
|
+
h1 { font-size: 3.2em; line-height: 1.1; }
|
|
3534
|
+
|
|
3535
|
+
.card { padding: 2em; }
|
|
3536
|
+
.card p { color: #aaa; }
|
|
3537
|
+
|
|
3538
|
+
button {
|
|
3346
3539
|
border-radius: 8px;
|
|
3347
|
-
|
|
3348
|
-
|
|
3540
|
+
border: 1px solid transparent;
|
|
3541
|
+
padding: 0.6em 1.2em;
|
|
3542
|
+
font-size: 1em;
|
|
3543
|
+
font-weight: 500;
|
|
3544
|
+
font-family: inherit;
|
|
3545
|
+
background-color: #1a1a1a;
|
|
3349
3546
|
cursor: pointer;
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
}
|
|
3354
|
-
.btn:hover { opacity: 0.85; transform: translateY(-1px); }
|
|
3355
|
-
.btn:active { transform: translateY(0); }
|
|
3356
|
-
.btn-primary { background: #7c3aed; color: #fff; }
|
|
3357
|
-
.btn-ghost { background: #1e1e2e; color: #e2e8f0; border: 1px solid #2d2d3e; }
|
|
3547
|
+
transition: border-color 0.25s;
|
|
3548
|
+
}
|
|
3549
|
+
button:hover { border-color: #a78bfa; }
|
|
3550
|
+
button:focus-visible { outline: 4px auto -webkit-focus-ring-color; }
|
|
3358
3551
|
|
|
3359
|
-
.
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
gap: 1rem;
|
|
3363
|
-
max-width: 900px;
|
|
3364
|
-
margin: 0 auto 4rem;
|
|
3365
|
-
padding: 0 1.5rem;
|
|
3366
|
-
}
|
|
3367
|
-
.card {
|
|
3368
|
-
background: #16161f;
|
|
3369
|
-
border: 1px solid #1e1e2e;
|
|
3370
|
-
border-radius: 12px;
|
|
3371
|
-
padding: 1.5rem;
|
|
3372
|
-
}
|
|
3373
|
-
.card-icon { font-size: 1.5rem; margin-bottom: 0.75rem; }
|
|
3374
|
-
.card h3 { font-size: 0.95rem; font-weight: 700; margin-bottom: 0.4rem; }
|
|
3375
|
-
.card p { font-size: 0.85rem; color: #64748b; line-height: 1.6; }
|
|
3552
|
+
.hint { color: #555; font-size: 0.9em; }
|
|
3553
|
+
.hint a { color: inherit; }
|
|
3554
|
+
.hint a:hover { color: #a78bfa; }
|
|
3376
3555
|
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3556
|
+
@media (prefers-color-scheme: light) {
|
|
3557
|
+
:root { color: #213547; background-color: #ffffff; }
|
|
3558
|
+
button { background-color: #f9f9f9; }
|
|
3559
|
+
.card p { color: #666; }
|
|
3560
|
+
.hint { color: #999; }
|
|
3382
3561
|
}
|
|
3383
|
-
.demo-box {
|
|
3384
|
-
background: #16161f;
|
|
3385
|
-
border: 1px solid #1e1e2e;
|
|
3386
|
-
border-radius: 12px;
|
|
3387
|
-
padding: 2rem;
|
|
3388
|
-
}
|
|
3389
|
-
.demo-box h2 { font-size: 0.8rem; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 1.25rem; }
|
|
3390
|
-
.counter { font-size: 3.5rem; font-weight: 800; color: #a78bfa; letter-spacing: -0.04em; margin-bottom: 1.25rem; }
|
|
3391
|
-
.demo-actions { display: flex; gap: 0.75rem; justify-content: center; }
|
|
3392
|
-
|
|
3393
3562
|
\`;
|
|
3394
3563
|
|
|
3395
|
-
|
|
3564
|
+
${appSignature}
|
|
3396
3565
|
const [count, setCount] = React.useState(0);
|
|
3397
3566
|
|
|
3398
3567
|
return (
|
|
3399
3568
|
<>
|
|
3400
3569
|
<HadarsHead status={200}>
|
|
3401
|
-
<title
|
|
3570
|
+
<title>${name}</title>
|
|
3402
3571
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
3403
3572
|
<style data-id="app-styles" dangerouslySetInnerHTML={{ __html: css }} />
|
|
3404
3573
|
</HadarsHead>
|
|
3405
3574
|
|
|
3406
|
-
<
|
|
3407
|
-
<
|
|
3408
|
-
|
|
3409
|
-
|
|
3575
|
+
<div id="app">
|
|
3576
|
+
<div className="logos">
|
|
3577
|
+
<a href="https://react.dev" target="_blank" rel="noopener noreferrer">
|
|
3578
|
+
<svg className="logo logo-react" xmlns="http://www.w3.org/2000/svg" viewBox="-11.5 -10.232 23 20.463" aria-label="React">
|
|
3579
|
+
<circle cx="0" cy="0" r="2.05" fill="#61dafb" />
|
|
3580
|
+
<g stroke="#61dafb" strokeWidth="1" fill="none">
|
|
3581
|
+
<ellipse rx="11" ry="4.2" />
|
|
3582
|
+
<ellipse rx="11" ry="4.2" transform="rotate(60)" />
|
|
3583
|
+
<ellipse rx="11" ry="4.2" transform="rotate(120)" />
|
|
3584
|
+
</g>
|
|
3585
|
+
</svg>
|
|
3586
|
+
</a>
|
|
3410
3587
|
</div>
|
|
3411
|
-
</nav>
|
|
3412
3588
|
|
|
3413
|
-
|
|
3414
|
-
<div className="hero-badge">built with hadars</div>
|
|
3415
|
-
<h1>Ship <span>React apps</span><br />at full speed</h1>
|
|
3416
|
-
<p>
|
|
3417
|
-
SSR out of the box, zero config, instant hot-reload.
|
|
3418
|
-
Edit <code>src/App.tsx</code> to get started.
|
|
3419
|
-
</p>
|
|
3420
|
-
<div className="hero-actions">
|
|
3421
|
-
<button className="btn btn-primary" onClick={() => setCount(c => c + 1)}>
|
|
3422
|
-
Try the counter ↓
|
|
3423
|
-
</button>
|
|
3424
|
-
</div>
|
|
3425
|
-
</section>
|
|
3589
|
+
<h1>React + hadars</h1>
|
|
3426
3590
|
|
|
3427
|
-
<div className="features">
|
|
3428
|
-
<div className="card">
|
|
3429
|
-
<div className="card-icon">⚡</div>
|
|
3430
|
-
<h3>Server-side rendering</h3>
|
|
3431
|
-
<p>Pages render on the server and hydrate on the client — great for SEO and first paint.</p>
|
|
3432
|
-
</div>
|
|
3433
|
-
<div className="card">
|
|
3434
|
-
<div className="card-icon">\uD83D\uDD25</div>
|
|
3435
|
-
<h3>Hot module reload</h3>
|
|
3436
|
-
<p>Changes in <code>src/App.tsx</code> reflect instantly in the browser during development.</p>
|
|
3437
|
-
</div>
|
|
3438
|
-
<div className="card">
|
|
3439
|
-
<div className="card-icon">\uD83D\uDCE6</div>
|
|
3440
|
-
<h3>Zero config</h3>
|
|
3441
|
-
<p>One config file. Export a React component, run <code>hadars dev</code>, done.</p>
|
|
3442
|
-
</div>
|
|
3443
3591
|
<div className="card">
|
|
3444
|
-
<
|
|
3445
|
-
|
|
3446
|
-
|
|
3592
|
+
<button onClick={() => setCount(c => c + 1)}>
|
|
3593
|
+
count is {count}
|
|
3594
|
+
</button>
|
|
3595
|
+
<p>
|
|
3596
|
+
Edit <code>src/App.${appExt}</code> and save to test HMR
|
|
3597
|
+
</p>
|
|
3447
3598
|
</div>
|
|
3448
|
-
</div>
|
|
3449
3599
|
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
<
|
|
3454
|
-
|
|
3455
|
-
<button className="btn btn-ghost" onClick={() => setCount(c => c - 1)}>− dec</button>
|
|
3456
|
-
<button className="btn btn-primary" onClick={() => setCount(c => c + 1)}>+ inc</button>
|
|
3457
|
-
</div>
|
|
3458
|
-
</div>
|
|
3600
|
+
<p className="hint">
|
|
3601
|
+
<a href="https://hadars.xyz" target="_blank" rel="noopener noreferrer">hadars docs</a>
|
|
3602
|
+
·
|
|
3603
|
+
<a href="https://react.dev" target="_blank" rel="noopener noreferrer">react docs</a>
|
|
3604
|
+
</p>
|
|
3459
3605
|
</div>
|
|
3460
|
-
|
|
3461
3606
|
</>
|
|
3462
3607
|
);
|
|
3463
3608
|
};
|
|
3464
3609
|
|
|
3465
3610
|
export default App;
|
|
3466
|
-
|
|
3467
|
-
|
|
3611
|
+
`;
|
|
3612
|
+
return {
|
|
3613
|
+
"package.json": packageJson,
|
|
3614
|
+
[`hadars.config.${cfgExt}`]: hadarsConfig,
|
|
3615
|
+
[tsOrJs]: tsConfigContent,
|
|
3616
|
+
".gitignore": `node_modules/
|
|
3617
|
+
.hadars/
|
|
3618
|
+
dist/
|
|
3619
|
+
`,
|
|
3620
|
+
[`src/App.${appExt}`]: appContent
|
|
3621
|
+
};
|
|
3622
|
+
}
|
|
3468
3623
|
async function createProject(name, cwd) {
|
|
3469
3624
|
const dir = resolve(cwd, name);
|
|
3470
3625
|
if (existsSync3(dir)) {
|
|
3471
3626
|
console.error(`Directory already exists: ${dir}`);
|
|
3472
3627
|
process.exit(1);
|
|
3473
3628
|
}
|
|
3474
|
-
|
|
3629
|
+
const useTypeScript = await promptRadio("Language?", ["TypeScript", "JavaScript"]) === 0;
|
|
3630
|
+
const selectedIndices = await promptMultiSelect("Select SWC plugins to enable (optional):", PLUGINS.map((p) => p.label));
|
|
3631
|
+
const plugins = selectedIndices.map((i) => PLUGINS[i]);
|
|
3632
|
+
console.log(`
|
|
3633
|
+
Creating hadars project in ${dir}`);
|
|
3475
3634
|
await mkdir2(join2(dir, "src"), { recursive: true });
|
|
3476
|
-
|
|
3477
|
-
|
|
3635
|
+
const files = buildTemplates(name, { useTypeScript, plugins });
|
|
3636
|
+
for (const [file, content] of Object.entries(files)) {
|
|
3478
3637
|
await writeFile2(join2(dir, file), content, "utf-8");
|
|
3479
3638
|
console.log(` created ${file}`);
|
|
3480
3639
|
}
|
|
3640
|
+
const installHint = plugins.length > 0 ? `
|
|
3641
|
+
# Also install selected SWC plugins:
|
|
3642
|
+
npm install -D ${plugins.map((p) => `${p.pkg}@${p.version}`).join(" ")}
|
|
3643
|
+
` : "";
|
|
3481
3644
|
console.log(`
|
|
3482
3645
|
Done! Next steps:
|
|
3483
3646
|
|
|
3484
3647
|
cd ${name}
|
|
3485
|
-
npm install # or: bun install / pnpm install
|
|
3648
|
+
npm install # or: bun install / pnpm install${installHint}
|
|
3486
3649
|
npm run dev # or: bun run dev
|
|
3487
3650
|
`);
|
|
3488
3651
|
}
|