@mandujs/core 0.9.20 → 0.9.22

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mandujs/core",
3
- "version": "0.9.20",
3
+ "version": "0.9.22",
4
4
  "description": "Mandu Framework Core - Spec, Generator, Guard, Runtime",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -358,7 +358,19 @@ async function handleRequest(req: Request, router: Router): Promise<Response> {
358
358
  if (loader) {
359
359
  try {
360
360
  const module = await loader();
361
- registerRouteComponent(route.id, module.default);
361
+ // module.default가 { component, filling } 객체인 경우 component 추출
362
+ const exported = module.default;
363
+ const component = typeof exported === 'function'
364
+ ? exported
365
+ : exported?.component ?? exported;
366
+ registerRouteComponent(route.id, component);
367
+
368
+ // filling이 있으면 loader 실행
369
+ const filling = typeof exported === 'object' ? exported?.filling : null;
370
+ if (filling?.hasLoader?.()) {
371
+ const ctx = new ManduContext(req, params);
372
+ loaderData = await filling.executeLoader(ctx);
373
+ }
362
374
  } catch (err) {
363
375
  const pageError = createPageLoadErrorResponse(
364
376
  route.id,
@@ -345,6 +345,8 @@ function generateHTMLShell(options: StreamingSSROptions): string {
345
345
  lang = "ko",
346
346
  headTags = "",
347
347
  bundleManifest,
348
+ routeId,
349
+ hydration,
348
350
  } = options;
349
351
 
350
352
  // Import map (module scripts 전에 위치해야 함)
@@ -375,6 +377,16 @@ function generateHTMLShell(options: StreamingSSROptions): string {
375
377
  }
376
378
  </style>`;
377
379
 
380
+ // Island wrapper (hydration이 필요한 경우)
381
+ const needsHydration = hydration && hydration.strategy !== "none" && routeId && bundleManifest;
382
+ let islandOpenTag = "";
383
+ if (needsHydration) {
384
+ const bundle = bundleManifest.bundles[routeId];
385
+ const bundleSrc = bundle?.js || "";
386
+ const priority = hydration.priority || "visible";
387
+ islandOpenTag = `<div data-mandu-island="${routeId}" data-mandu-src="${bundleSrc}" data-mandu-priority="${priority}">`;
388
+ }
389
+
378
390
  return `<!DOCTYPE html>
379
391
  <html lang="${lang}">
380
392
  <head>
@@ -386,7 +398,7 @@ function generateHTMLShell(options: StreamingSSROptions): string {
386
398
  ${importMapScript}
387
399
  </head>
388
400
  <body>
389
- <div id="root">`;
401
+ <div id="root">${islandOpenTag}`;
390
402
  }
391
403
 
392
404
  /**
@@ -464,7 +476,11 @@ function generateHTMLTail(options: StreamingSSROptions): string {
464
476
  scripts.push(generateHMRScript(hmrPort));
465
477
  }
466
478
 
467
- return `</div>
479
+ // Island wrapper 닫기 (hydration이 필요한 경우)
480
+ const needsHydration = hydration && hydration.strategy !== "none" && routeId && bundleManifest;
481
+ const islandCloseTag = needsHydration ? "</div>" : "";
482
+
483
+ return `${islandCloseTag}</div>
468
484
  ${scripts.join("\n ")}
469
485
  </body>
470
486
  </html>`;