@mandujs/core 0.18.8 → 0.18.10
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 +93 -5
- package/src/client/router.ts +0 -7
- package/src/runtime/ssr.ts +6 -10
- package/src/runtime/streaming-ssr.ts +5 -0
package/package.json
CHANGED
package/src/bundler/build.ts
CHANGED
|
@@ -744,6 +744,73 @@ 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
|
+
// React를 인라인 번들링 (import map 없이도 독립 동작)
|
|
782
|
+
// DevTools는 Shadow DOM 격리 → 앱 React와 충돌 없음
|
|
783
|
+
define: {
|
|
784
|
+
"process.env.NODE_ENV": JSON.stringify("development"),
|
|
785
|
+
...options.define,
|
|
786
|
+
},
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
await fs.unlink(srcPath).catch(() => {});
|
|
790
|
+
|
|
791
|
+
if (!result.success) {
|
|
792
|
+
return {
|
|
793
|
+
success: false,
|
|
794
|
+
outputPath: "",
|
|
795
|
+
errors: result.logs.map((l) => l.message),
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
return {
|
|
800
|
+
success: true,
|
|
801
|
+
outputPath: `/.mandu/client/${outputName}`,
|
|
802
|
+
errors: [],
|
|
803
|
+
};
|
|
804
|
+
} catch (error) {
|
|
805
|
+
await fs.unlink(srcPath).catch(() => {});
|
|
806
|
+
return {
|
|
807
|
+
success: false,
|
|
808
|
+
outputPath: "",
|
|
809
|
+
errors: [String(error)],
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
747
814
|
/**
|
|
748
815
|
* Router 런타임 번들 빌드
|
|
749
816
|
*/
|
|
@@ -1185,6 +1252,15 @@ export async function buildClientBundles(
|
|
|
1185
1252
|
// Hydration 라우트가 없어도 빈 매니페스트를 저장해야 함
|
|
1186
1253
|
// (이전 빌드의 stale 매니페스트 참조 방지)
|
|
1187
1254
|
if (hydratedRoutes.length === 0) {
|
|
1255
|
+
// Dev 모드에서는 DevTools 번들 빌드 (island 없어도 동작해야 함)
|
|
1256
|
+
const isDev = env === "development";
|
|
1257
|
+
if (isDev) {
|
|
1258
|
+
const devtoolsResult = await buildDevtoolsBundle(outDir, options);
|
|
1259
|
+
if (!devtoolsResult.success) {
|
|
1260
|
+
console.warn("[Mandu] DevTools bundle build failed:", devtoolsResult.errors.join(", "));
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1188
1264
|
const emptyManifest = createEmptyManifest(env);
|
|
1189
1265
|
await fs.writeFile(
|
|
1190
1266
|
path.join(rootDir, ".mandu/manifest.json"),
|
|
@@ -1251,22 +1327,34 @@ export async function buildClientBundles(
|
|
|
1251
1327
|
return { success: errors.length === 0, outputs, errors, manifest: existingManifest, stats };
|
|
1252
1328
|
}
|
|
1253
1329
|
|
|
1254
|
-
// 3-4. Runtime, Router, Vendor 번들 병렬 빌드 (서로 독립적)
|
|
1255
|
-
const [
|
|
1330
|
+
// 3-4. Runtime, Router, Vendor, DevTools 번들 병렬 빌드 (서로 독립적)
|
|
1331
|
+
const buildPromises: Promise<any>[] = [
|
|
1256
1332
|
buildRuntime(outDir, options),
|
|
1257
1333
|
buildRouterRuntime(outDir, options),
|
|
1258
1334
|
buildVendorShims(outDir, options),
|
|
1259
|
-
]
|
|
1335
|
+
];
|
|
1336
|
+
|
|
1337
|
+
// DevTools 번들은 dev 모드에서만 빌드
|
|
1338
|
+
const isDev = env === "development";
|
|
1339
|
+
if (isDev) {
|
|
1340
|
+
buildPromises.push(buildDevtoolsBundle(outDir, options));
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
const [runtimeResult, routerResult, vendorResult, devtoolsResult] = await Promise.all(buildPromises);
|
|
1260
1344
|
|
|
1261
1345
|
if (!runtimeResult.success) {
|
|
1262
|
-
errors.push(...runtimeResult.errors.map((e) => `[Runtime] ${e}`));
|
|
1346
|
+
errors.push(...runtimeResult.errors.map((e: string) => `[Runtime] ${e}`));
|
|
1263
1347
|
}
|
|
1264
1348
|
if (!routerResult.success) {
|
|
1265
|
-
errors.push(...routerResult.errors.map((e) => `[Router] ${e}`));
|
|
1349
|
+
errors.push(...routerResult.errors.map((e: string) => `[Router] ${e}`));
|
|
1266
1350
|
}
|
|
1267
1351
|
if (!vendorResult.success) {
|
|
1268
1352
|
errors.push(...vendorResult.errors);
|
|
1269
1353
|
}
|
|
1354
|
+
if (devtoolsResult && !devtoolsResult.success) {
|
|
1355
|
+
// DevTools 빌드 실패는 경고만 (개발 중단시키지 않음)
|
|
1356
|
+
console.warn("[Mandu] DevTools bundle build failed:", devtoolsResult.errors.join(", "));
|
|
1357
|
+
}
|
|
1270
1358
|
|
|
1271
1359
|
// 5. 각 Island 번들 빌드
|
|
1272
1360
|
for (const route of hydratedRoutes) {
|
package/src/client/router.ts
CHANGED
|
@@ -410,13 +410,6 @@ export function initializeRouter(): void {
|
|
|
410
410
|
// 링크 클릭 이벤트 위임
|
|
411
411
|
document.addEventListener("click", handleLinkClick);
|
|
412
412
|
|
|
413
|
-
// DevTools 자동 초기화 (개발 모드에서 SSR이 __MANDU_DEV_TOOLS__를 주입한 경우)
|
|
414
|
-
if ((window as any).__MANDU_DEV_TOOLS__) {
|
|
415
|
-
import("../devtools/init").then(({ initManduKitchen }) => {
|
|
416
|
-
initManduKitchen({ position: "bottom-right" });
|
|
417
|
-
}).catch(() => {});
|
|
418
|
-
}
|
|
419
|
-
|
|
420
413
|
console.log("[Mandu Router] Initialized");
|
|
421
414
|
}
|
|
422
415
|
|
package/src/runtime/ssr.ts
CHANGED
|
@@ -238,10 +238,10 @@ export function renderToHTML(element: ReactElement, options: SSROptions = {}): s
|
|
|
238
238
|
hmrScript = generateHMRScript(hmrPort);
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
// DevTools
|
|
241
|
+
// DevTools 번들 로드 (개발 모드)
|
|
242
242
|
let devtoolsScript = "";
|
|
243
243
|
if (isDev) {
|
|
244
|
-
devtoolsScript =
|
|
244
|
+
devtoolsScript = generateDevtoolsScript();
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
return `<!doctype html>
|
|
@@ -372,15 +372,11 @@ function generateHMRScript(port: number): string {
|
|
|
372
372
|
}
|
|
373
373
|
|
|
374
374
|
/**
|
|
375
|
-
* DevTools
|
|
375
|
+
* DevTools 번들 로드 스크립트 생성 (개발 모드 전용)
|
|
376
|
+
* _devtools.js 번들이 자체적으로 initManduKitchen()을 호출
|
|
376
377
|
*/
|
|
377
|
-
function
|
|
378
|
-
return `<script
|
|
379
|
-
(function() {
|
|
380
|
-
if (typeof window === 'undefined') return;
|
|
381
|
-
window.__MANDU_DEV_TOOLS__ = true;
|
|
382
|
-
})();
|
|
383
|
-
</script>`;
|
|
378
|
+
function generateDevtoolsScript(): string {
|
|
379
|
+
return `<script type="module" src="/.mandu/client/_devtools.js"></script>`;
|
|
384
380
|
}
|
|
385
381
|
|
|
386
382
|
export function createHTMLResponse(html: string, status: number = 200): Response {
|
|
@@ -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>" : "";
|