@mandujs/core 0.18.7 → 0.18.9
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/package.json +1 -1
- package/src/bundler/build.ts +83 -5
- package/src/filling/filling.ts +12 -0
- package/src/runtime/ssr.ts +15 -0
- package/src/runtime/streaming-ssr.ts +5 -0
package/package.json
CHANGED
package/src/bundler/build.ts
CHANGED
|
@@ -744,6 +744,72 @@ if (document.readyState === 'loading') {
|
|
|
744
744
|
`;
|
|
745
745
|
}
|
|
746
746
|
|
|
747
|
+
/**
|
|
748
|
+
* DevTools 번들 빌드 (개발 모드 전용)
|
|
749
|
+
* devtools/init.ts를 브라우저용 번들로 컴파일하여 _devtools.js 생성
|
|
750
|
+
*/
|
|
751
|
+
async function buildDevtoolsBundle(
|
|
752
|
+
outDir: string,
|
|
753
|
+
options: BundlerOptions
|
|
754
|
+
): Promise<{ success: boolean; outputPath: string; errors: string[] }> {
|
|
755
|
+
const srcPath = path.join(outDir, "_devtools.src.js");
|
|
756
|
+
const outputName = "_devtools.js";
|
|
757
|
+
|
|
758
|
+
// devtools/init.ts의 절대 경로 (build.ts → ../devtools/init.ts)
|
|
759
|
+
const devtoolsInitPath = path.resolve(
|
|
760
|
+
import.meta.dir, '..', 'devtools', 'init.ts'
|
|
761
|
+
).replace(/\\/g, '/');
|
|
762
|
+
|
|
763
|
+
const source = `
|
|
764
|
+
import { initManduKitchen } from "${devtoolsInitPath}";
|
|
765
|
+
if (typeof window !== 'undefined') {
|
|
766
|
+
window.__MANDU_DEV_TOOLS__ = true;
|
|
767
|
+
initManduKitchen({ position: 'bottom-right' });
|
|
768
|
+
}
|
|
769
|
+
`;
|
|
770
|
+
|
|
771
|
+
try {
|
|
772
|
+
await Bun.write(srcPath, source);
|
|
773
|
+
|
|
774
|
+
const result = await Bun.build({
|
|
775
|
+
entrypoints: [srcPath],
|
|
776
|
+
outdir: outDir,
|
|
777
|
+
naming: outputName,
|
|
778
|
+
minify: false, // dev only
|
|
779
|
+
sourcemap: options.sourcemap ? "external" : "none",
|
|
780
|
+
target: "browser",
|
|
781
|
+
external: ["react", "react-dom", "react-dom/client"],
|
|
782
|
+
define: {
|
|
783
|
+
"process.env.NODE_ENV": JSON.stringify("development"),
|
|
784
|
+
...options.define,
|
|
785
|
+
},
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
await fs.unlink(srcPath).catch(() => {});
|
|
789
|
+
|
|
790
|
+
if (!result.success) {
|
|
791
|
+
return {
|
|
792
|
+
success: false,
|
|
793
|
+
outputPath: "",
|
|
794
|
+
errors: result.logs.map((l) => l.message),
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
return {
|
|
799
|
+
success: true,
|
|
800
|
+
outputPath: `/.mandu/client/${outputName}`,
|
|
801
|
+
errors: [],
|
|
802
|
+
};
|
|
803
|
+
} catch (error) {
|
|
804
|
+
await fs.unlink(srcPath).catch(() => {});
|
|
805
|
+
return {
|
|
806
|
+
success: false,
|
|
807
|
+
outputPath: "",
|
|
808
|
+
errors: [String(error)],
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
747
813
|
/**
|
|
748
814
|
* Router 런타임 번들 빌드
|
|
749
815
|
*/
|
|
@@ -1251,22 +1317,34 @@ export async function buildClientBundles(
|
|
|
1251
1317
|
return { success: errors.length === 0, outputs, errors, manifest: existingManifest, stats };
|
|
1252
1318
|
}
|
|
1253
1319
|
|
|
1254
|
-
// 3-4. Runtime, Router, Vendor 번들 병렬 빌드 (서로 독립적)
|
|
1255
|
-
const [
|
|
1320
|
+
// 3-4. Runtime, Router, Vendor, DevTools 번들 병렬 빌드 (서로 독립적)
|
|
1321
|
+
const buildPromises: Promise<any>[] = [
|
|
1256
1322
|
buildRuntime(outDir, options),
|
|
1257
1323
|
buildRouterRuntime(outDir, options),
|
|
1258
1324
|
buildVendorShims(outDir, options),
|
|
1259
|
-
]
|
|
1325
|
+
];
|
|
1326
|
+
|
|
1327
|
+
// DevTools 번들은 dev 모드에서만 빌드
|
|
1328
|
+
const isDev = env === "development";
|
|
1329
|
+
if (isDev) {
|
|
1330
|
+
buildPromises.push(buildDevtoolsBundle(outDir, options));
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
const [runtimeResult, routerResult, vendorResult, devtoolsResult] = await Promise.all(buildPromises);
|
|
1260
1334
|
|
|
1261
1335
|
if (!runtimeResult.success) {
|
|
1262
|
-
errors.push(...runtimeResult.errors.map((e) => `[Runtime] ${e}`));
|
|
1336
|
+
errors.push(...runtimeResult.errors.map((e: string) => `[Runtime] ${e}`));
|
|
1263
1337
|
}
|
|
1264
1338
|
if (!routerResult.success) {
|
|
1265
|
-
errors.push(...routerResult.errors.map((e) => `[Router] ${e}`));
|
|
1339
|
+
errors.push(...routerResult.errors.map((e: string) => `[Router] ${e}`));
|
|
1266
1340
|
}
|
|
1267
1341
|
if (!vendorResult.success) {
|
|
1268
1342
|
errors.push(...vendorResult.errors);
|
|
1269
1343
|
}
|
|
1344
|
+
if (devtoolsResult && !devtoolsResult.success) {
|
|
1345
|
+
// DevTools 빌드 실패는 경고만 (개발 중단시키지 않음)
|
|
1346
|
+
console.warn("[Mandu] DevTools bundle build failed:", devtoolsResult.errors.join(", "));
|
|
1347
|
+
}
|
|
1270
1348
|
|
|
1271
1349
|
// 5. 각 Island 번들 빌드
|
|
1272
1350
|
for (const route of hydratedRoutes) {
|
package/src/filling/filling.ts
CHANGED
|
@@ -375,6 +375,18 @@ export class ManduFilling<TLoaderData = unknown> {
|
|
|
375
375
|
return Array.from(this.config.handlers.keys());
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
+
/**
|
|
379
|
+
* Convert to named handler exports compatible with Mandu route.ts files.
|
|
380
|
+
* Usage: export const { GET, POST } = filling.toHandlers();
|
|
381
|
+
*/
|
|
382
|
+
toHandlers(): Partial<Record<HttpMethod, (req: Request) => Promise<Response>>> {
|
|
383
|
+
const result: Partial<Record<HttpMethod, (req: Request) => Promise<Response>>> = {};
|
|
384
|
+
for (const method of this.config.handlers.keys()) {
|
|
385
|
+
result[method] = (req: Request) => this.handle(req, {}, undefined);
|
|
386
|
+
}
|
|
387
|
+
return result;
|
|
388
|
+
}
|
|
389
|
+
|
|
378
390
|
hasMethod(method: HttpMethod): boolean {
|
|
379
391
|
return this.config.handlers.has(method);
|
|
380
392
|
}
|
package/src/runtime/ssr.ts
CHANGED
|
@@ -238,6 +238,12 @@ export function renderToHTML(element: ReactElement, options: SSROptions = {}): s
|
|
|
238
238
|
hmrScript = generateHMRScript(hmrPort);
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
+
// DevTools 번들 로드 (개발 모드)
|
|
242
|
+
let devtoolsScript = "";
|
|
243
|
+
if (isDev) {
|
|
244
|
+
devtoolsScript = generateDevtoolsScript();
|
|
245
|
+
}
|
|
246
|
+
|
|
241
247
|
return `<!doctype html>
|
|
242
248
|
<html lang="${escapeHtmlAttr(lang)}">
|
|
243
249
|
<head>
|
|
@@ -255,6 +261,7 @@ export function renderToHTML(element: ReactElement, options: SSROptions = {}): s
|
|
|
255
261
|
${needsHydration ? REACT_INTERNALS_SHIM_SCRIPT : ""}
|
|
256
262
|
${routerScript}
|
|
257
263
|
${hmrScript}
|
|
264
|
+
${devtoolsScript}
|
|
258
265
|
${bodyEndTags}
|
|
259
266
|
</body>
|
|
260
267
|
</html>`;
|
|
@@ -364,6 +371,14 @@ function generateHMRScript(port: number): string {
|
|
|
364
371
|
</script>`;
|
|
365
372
|
}
|
|
366
373
|
|
|
374
|
+
/**
|
|
375
|
+
* DevTools 번들 로드 스크립트 생성 (개발 모드 전용)
|
|
376
|
+
* _devtools.js 번들이 자체적으로 initManduKitchen()을 호출
|
|
377
|
+
*/
|
|
378
|
+
function generateDevtoolsScript(): string {
|
|
379
|
+
return `<script type="module" src="/.mandu/client/_devtools.js"></script>`;
|
|
380
|
+
}
|
|
381
|
+
|
|
367
382
|
export function createHTMLResponse(html: string, status: number = 200): Response {
|
|
368
383
|
return new Response(html, {
|
|
369
384
|
status,
|
|
@@ -530,6 +530,11 @@ function generateHTMLTailContent(options: StreamingSSROptions): string {
|
|
|
530
530
|
scripts.push(generateHMRScript(hmrPort));
|
|
531
531
|
}
|
|
532
532
|
|
|
533
|
+
// 10. DevTools 번들 로드 (개발 모드)
|
|
534
|
+
if (isDev) {
|
|
535
|
+
scripts.push(`<script type="module" src="/.mandu/client/_devtools.js"></script>`);
|
|
536
|
+
}
|
|
537
|
+
|
|
533
538
|
// Island wrapper 닫기 (hydration이 필요한 경우)
|
|
534
539
|
const needsHydration = hydration && hydration.strategy !== "none" && routeId && bundleManifest;
|
|
535
540
|
const islandCloseTag = needsHydration ? "</div>" : "";
|