@fuzionx/framework 0.1.2 → 0.1.4
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/lib/core/Application.js +15 -1
- package/lib/view/View.js +29 -29
- package/package.json +2 -2
package/lib/core/Application.js
CHANGED
|
@@ -34,7 +34,10 @@ let FuzionXApp;
|
|
|
34
34
|
try {
|
|
35
35
|
const core = await import('@fuzionx/core');
|
|
36
36
|
FuzionXApp = core.FuzionXApp || core.RuxyApp;
|
|
37
|
-
} catch {
|
|
37
|
+
} catch (e) {
|
|
38
|
+
console.error('[fuzionx-framework] ⚠️ @fuzionx/core 로드 실패 — Bridge 없이 테스트 모드로 실행됩니다:',
|
|
39
|
+
e.message);
|
|
40
|
+
}
|
|
38
41
|
|
|
39
42
|
export default class Application {
|
|
40
43
|
/**
|
|
@@ -304,6 +307,17 @@ export default class Application {
|
|
|
304
307
|
: undefined,
|
|
305
308
|
port,
|
|
306
309
|
});
|
|
310
|
+
// FuzionXApp 생성 후 Bridge 전파 — boot() 시점에는 null이었음
|
|
311
|
+
this._bridge = this._coreApp._bridge;
|
|
312
|
+
if (this._bridge) {
|
|
313
|
+
if (this._view) this._view._bridge = this._bridge;
|
|
314
|
+
if (this.logger) this.logger._bridge = this._bridge;
|
|
315
|
+
if (this.crypto) this.crypto._bridge = this._bridge;
|
|
316
|
+
if (this.hash) this.hash._bridge = this._bridge;
|
|
317
|
+
if (this.media) this.media._bridge = this._bridge;
|
|
318
|
+
if (this.file) this.file._bridge = this._bridge;
|
|
319
|
+
if (this.i18n) this.i18n._bridge = this._bridge;
|
|
320
|
+
}
|
|
307
321
|
}
|
|
308
322
|
this._registerBridgeRoutes(this._coreApp);
|
|
309
323
|
this._coreApp.listen(port, callback);
|
package/lib/view/View.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* View — 뷰 렌더링 (
|
|
2
|
+
* View — 뷰 렌더링 (Bridge SSR)
|
|
3
3
|
*
|
|
4
4
|
* ctx.theme에 따른 테마 경로 해석.
|
|
5
|
-
* Bridge
|
|
5
|
+
* Bridge renderTemplateFile N-API로 렌더링.
|
|
6
6
|
*
|
|
7
7
|
* @see docs/framework/03-views-templates.md
|
|
8
8
|
*/
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
|
|
9
11
|
export default class View {
|
|
10
12
|
/**
|
|
11
13
|
* @param {object} opts
|
|
12
14
|
* @param {string} opts.viewsPath - 뷰 파일 루트 경로
|
|
13
15
|
* @param {string} [opts.theme='default'] - 기본 테마
|
|
14
|
-
* @param {object} [opts.bridge] - Bridge
|
|
15
|
-
* @param {object} [opts.globals] - 모든 뷰에 주입되는 전역 변수
|
|
16
|
+
* @param {object} [opts.bridge] - Bridge N-API 인스턴스
|
|
16
17
|
*/
|
|
17
18
|
constructor(opts = {}) {
|
|
18
19
|
this.viewsPath = opts.viewsPath || '';
|
|
19
20
|
this.theme = opts.theme || 'default';
|
|
20
21
|
this._bridge = opts.bridge || null;
|
|
21
|
-
this._globals = opts.globals || {};
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -27,46 +27,46 @@ export default class View {
|
|
|
27
27
|
* @param {*} value
|
|
28
28
|
*/
|
|
29
29
|
share(key, value) {
|
|
30
|
+
this._globals = this._globals || {};
|
|
30
31
|
this._globals[key] = value;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
|
-
* 템플릿 렌더링
|
|
35
|
+
* 템플릿 렌더링 — Bridge renderTemplateFile N-API 사용
|
|
35
36
|
*
|
|
36
37
|
* 테마 경로 해석 (03-views-templates.md):
|
|
37
|
-
* '
|
|
38
|
+
* 'home' → {viewsPath}/{theme}/pages/home.html
|
|
38
39
|
*
|
|
39
|
-
* @param {string} template - 'users/index' 등
|
|
40
|
+
* @param {string} template - 'home', 'users/index' 등
|
|
40
41
|
* @param {object} [data] - 템플릿 변수
|
|
41
|
-
* @param {string} [theme] - 테마 오버라이드
|
|
42
|
+
* @param {string} [theme] - 테마 오버라이드
|
|
42
43
|
* @returns {string} - 렌더링된 HTML
|
|
43
44
|
*/
|
|
44
45
|
render(template, data = {}, theme) {
|
|
45
46
|
const activeTheme = theme || data.theme || this.theme;
|
|
46
47
|
const mergedData = { ...this._globals, ...data, theme: activeTheme };
|
|
47
48
|
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
} catch {
|
|
54
|
-
// SSR 실패 시 폴백
|
|
55
|
-
}
|
|
56
|
-
}
|
|
49
|
+
// 파일 경로 해석: pages/{name}.html 우선
|
|
50
|
+
const candidates = [
|
|
51
|
+
join(this.viewsPath, activeTheme, 'pages', `${template}.html`),
|
|
52
|
+
join(this.viewsPath, activeTheme, `${template}.html`),
|
|
53
|
+
];
|
|
57
54
|
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
// Bridge renderTemplateFile N-API 호출
|
|
56
|
+
if (this._bridge && typeof this._bridge.renderTemplateFile === 'function') {
|
|
57
|
+
const contextJson = JSON.stringify(mergedData);
|
|
61
58
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
59
|
+
for (const filePath of candidates) {
|
|
60
|
+
try {
|
|
61
|
+
return this._bridge.renderTemplateFile(filePath, contextJson);
|
|
62
|
+
} catch {
|
|
63
|
+
// 파일 없음 → 다음 후보
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
throw new Error(`View '${template}' not found. Searched: ${candidates.join(', ')}`);
|
|
69
68
|
}
|
|
70
|
-
|
|
69
|
+
|
|
70
|
+
throw new Error(`Bridge not available — cannot render view '${template}'`);
|
|
71
71
|
}
|
|
72
72
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fuzionx/framework",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Full-stack MVC framework built on @fuzionx/core — Controller, Service, Model, Middleware, DI, EventBus",
|
|
6
6
|
"main": "index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"url": "https://github.com/saytohenry/fuzionx"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@fuzionx/core": "^0.1.
|
|
37
|
+
"@fuzionx/core": "^0.1.4",
|
|
38
38
|
"better-sqlite3": "^12.8.0",
|
|
39
39
|
"knex": "^3.2.5",
|
|
40
40
|
"mongoose": "^9.3.2",
|