@mandujs/core 0.18.2 → 0.18.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mandujs/core",
3
- "version": "0.18.2",
3
+ "version": "0.18.5",
4
4
  "description": "Mandu Framework Core - Spec, Generator, Guard, Runtime",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -44,7 +44,13 @@
44
44
  },
45
45
  "peerDependencies": {
46
46
  "react": "^19.0.0",
47
- "react-dom": "^19.0.0"
47
+ "react-dom": "^19.0.0",
48
+ "@tailwindcss/cli": ">=4.0.0"
49
+ },
50
+ "peerDependenciesMeta": {
51
+ "@tailwindcss/cli": {
52
+ "optional": true
53
+ }
48
54
  },
49
55
  "dependencies": {
50
56
  "chokidar": "^5.0.0",
@@ -205,11 +205,11 @@ async function loadAndHydrate(element, src) {
205
205
  // Dynamic import - 이 시점에 Island 모듈 로드
206
206
  const module = await import(src);
207
207
  const island = module.default;
208
+ const data = getServerData(id);
208
209
 
209
210
  // Mandu Island (preferred)
210
211
  if (island && island.__mandu_island === true) {
211
212
  const { definition } = island;
212
- const data = getServerData(id);
213
213
 
214
214
  // Island 컴포넌트 (Error Boundary + Loading 지원)
215
215
  function IslandComponent() {
@@ -258,11 +258,14 @@ async function loadAndHydrate(element, src) {
258
258
 
259
259
  console.log('[Mandu] Hydrated:', id);
260
260
  }
261
- // Plain React component fallback
261
+ // Plain React component fallback (e.g. "use client" pages)
262
262
  else if (typeof island === 'function' || React.isValidElement(island)) {
263
263
  console.warn('[Mandu] Plain component hydration:', id);
264
- const data = getServerData(id);
265
- const root = hydrateRoot(element, React.createElement(island, data));
264
+
265
+ const root = typeof island === 'function'
266
+ ? hydrateRoot(element, React.createElement(island, data))
267
+ : hydrateRoot(element, island);
268
+
266
269
  hydratedRoots.set(id, root);
267
270
 
268
271
  // 완료 표시
@@ -390,6 +393,8 @@ import React, {
390
393
  Suspense,
391
394
  StrictMode,
392
395
  Profiler,
396
+ // Misc
397
+ version,
393
398
  // Types
394
399
  Component,
395
400
  PureComponent,
@@ -401,15 +406,16 @@ import { jsx, jsxs } from 'react/jsx-runtime';
401
406
  import { jsxDEV } from 'react/jsx-dev-runtime';
402
407
 
403
408
  // React internals (ReactDOM이 내부적으로 접근 필요)
404
- const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
405
-
406
- // React 19 client internals (Playwright headless 환경 호환성)
409
+ // React 19+: __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE
410
+ // React <=18: __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
407
411
  const __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE =
408
412
  React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE || {};
413
+ const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED =
414
+ React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED || {};
409
415
 
410
- // Null safety for Playwright headless browsers
416
+ // Null safety for Playwright headless browsers (React 19)
411
417
  if (__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE.S == null) {
412
- __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE.S = function() {};
418
+ __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE.S = function () {};
413
419
  }
414
420
 
415
421
  // 전역 React 설정 (모든 모듈에서 동일 인스턴스 공유)
@@ -447,20 +453,18 @@ export {
447
453
  Suspense,
448
454
  StrictMode,
449
455
  Profiler,
456
+ version,
450
457
  Component,
451
458
  PureComponent,
452
459
  Children,
453
- __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
454
460
  __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
461
+ __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
455
462
  // JSX Runtime exports
456
463
  jsx,
457
464
  jsxs,
458
465
  jsxDEV,
459
466
  };
460
467
 
461
- // Version export (React 19 compatibility)
462
- export const version = React.version;
463
-
464
468
  // Default export
465
469
  export default React;
466
470
  `;
@@ -478,10 +482,6 @@ function generateReactDOMShimSource(): string {
478
482
  import ReactDOM, {
479
483
  createPortal,
480
484
  flushSync,
481
- render,
482
- unmountComponentAtNode,
483
- findDOMNode,
484
- hydrate,
485
485
  version,
486
486
  } from 'react-dom';
487
487
 
@@ -489,10 +489,6 @@ import ReactDOM, {
489
489
  export {
490
490
  createPortal,
491
491
  flushSync,
492
- render,
493
- unmountComponentAtNode,
494
- findDOMNode,
495
- hydrate,
496
492
  version,
497
493
  };
498
494
 
@@ -849,10 +845,8 @@ async function buildRuntime(
849
845
  },
850
846
  });
851
847
 
852
- // 소스 파일 정리
853
- await fs.unlink(runtimePath).catch(() => {});
854
-
855
848
  if (!result.success) {
849
+ // 실패 시 디버깅을 위해 소스 파일을 남겨둠 (_runtime.src.js)
856
850
  return {
857
851
  success: false,
858
852
  outputPath: "",
@@ -860,17 +854,28 @@ async function buildRuntime(
860
854
  };
861
855
  }
862
856
 
857
+ // 성공 시에만 소스 파일 정리
858
+ await fs.unlink(runtimePath).catch(() => {});
859
+
863
860
  return {
864
861
  success: true,
865
862
  outputPath: `/.mandu/client/${outputName}`,
866
863
  errors: [],
867
864
  };
868
- } catch (error) {
869
- await fs.unlink(runtimePath).catch(() => {});
865
+ } catch (error: any) {
866
+ // 예외 발생 시에도 디버깅을 위해 소스 파일을 남겨둠
867
+ const extra: string[] = [];
868
+ if (error?.errors && Array.isArray(error.errors)) {
869
+ extra.push(...error.errors.map((e: any) => String(e?.message || e)));
870
+ }
871
+ if (error?.logs && Array.isArray(error.logs)) {
872
+ extra.push(...error.logs.map((l: any) => String(l?.message || l)));
873
+ }
874
+
870
875
  return {
871
876
  success: false,
872
877
  outputPath: "",
873
- errors: [String(error)],
878
+ errors: [String(error), ...extra].filter(Boolean),
874
879
  };
875
880
  }
876
881
  }
@@ -1200,20 +1205,19 @@ export async function buildClientBundles(
1200
1205
  };
1201
1206
  }
1202
1207
 
1203
- // 3. Runtime 번들 빌드
1204
- const runtimeResult = await buildRuntime(outDir, options);
1208
+ // 3-4. Runtime, Router, Vendor 번들 병렬 빌드 (서로 독립적)
1209
+ const [runtimeResult, routerResult, vendorResult] = await Promise.all([
1210
+ buildRuntime(outDir, options),
1211
+ buildRouterRuntime(outDir, options),
1212
+ buildVendorShims(outDir, options),
1213
+ ]);
1214
+
1205
1215
  if (!runtimeResult.success) {
1206
1216
  errors.push(...runtimeResult.errors.map((e) => `[Runtime] ${e}`));
1207
1217
  }
1208
-
1209
- // 3.5. Client-side Router 런타임 빌드
1210
- const routerResult = await buildRouterRuntime(outDir, options);
1211
1218
  if (!routerResult.success) {
1212
1219
  errors.push(...routerResult.errors.map((e) => `[Router] ${e}`));
1213
1220
  }
1214
-
1215
- // 4. Vendor shim 번들 빌드 (React, ReactDOM, ReactDOMClient)
1216
- const vendorResult = await buildVendorShims(outDir, options);
1217
1221
  if (!vendorResult.success) {
1218
1222
  errors.push(...vendorResult.errors);
1219
1223
  }