@kurdel/template-react 0.1.0-beta.1
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/LICENSE +21 -0
- package/README.md +20 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -0
- package/lib/react-template-engine.d.ts +25 -0
- package/lib/react-template-engine.js +52 -0
- package/lib/react-template-engine.js.map +1 -0
- package/lib/react-template-module.d.ts +32 -0
- package/lib/react-template-module.js +47 -0
- package/lib/react-template-module.js.map +1 -0
- package/lib/react-template-options.d.ts +42 -0
- package/lib/react-template-options.js +2 -0
- package/lib/react-template-options.js.map +1 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Andrii Sorokin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# @kurdel/template-react
|
|
2
|
+
|
|
3
|
+
Integration module for using **React components** with the Kurdel framework.
|
|
4
|
+
Provides a unified `TemplateEngine` implementation for server-side rendering (SSR).
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 📦 Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @kurdel/template-react
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
> Requires Node 20.19+, 22.12+, or 24+ and `@kurdel/core` / `@kurdel/runtime`.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 📄 License
|
|
19
|
+
|
|
20
|
+
MIT © Andrii Sorokin
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { TemplateEngine } from '@kurdel/core/template';
|
|
2
|
+
/**
|
|
3
|
+
* ReactTemplateEngine
|
|
4
|
+
*
|
|
5
|
+
* Renders React components (views) into static HTML strings
|
|
6
|
+
* for use in SSR (Server-Side Rendering).
|
|
7
|
+
*
|
|
8
|
+
* Responsibilities:
|
|
9
|
+
* - Dynamically import the base Document and page component
|
|
10
|
+
* - Compose them as a React element tree
|
|
11
|
+
* - Convert the tree to an HTML string
|
|
12
|
+
*/
|
|
13
|
+
export declare class ReactTemplateEngine implements TemplateEngine {
|
|
14
|
+
/** Base directory where `document.js` and view components reside */
|
|
15
|
+
private readonly baseDir;
|
|
16
|
+
constructor(baseDir: string);
|
|
17
|
+
/**
|
|
18
|
+
* Renders a React view wrapped in the shared Document layout.
|
|
19
|
+
*
|
|
20
|
+
* @param view - The view component name (without .js extension)
|
|
21
|
+
* @param data - Props to pass both to Document and the view
|
|
22
|
+
* @returns Rendered HTML string with <!DOCTYPE html>
|
|
23
|
+
*/
|
|
24
|
+
render(view: string, data?: Record<string, unknown>): Promise<string>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { createElement } from 'react';
|
|
4
|
+
import { renderToString } from 'react-dom/server';
|
|
5
|
+
/**
|
|
6
|
+
* ReactTemplateEngine
|
|
7
|
+
*
|
|
8
|
+
* Renders React components (views) into static HTML strings
|
|
9
|
+
* for use in SSR (Server-Side Rendering).
|
|
10
|
+
*
|
|
11
|
+
* Responsibilities:
|
|
12
|
+
* - Dynamically import the base Document and page component
|
|
13
|
+
* - Compose them as a React element tree
|
|
14
|
+
* - Convert the tree to an HTML string
|
|
15
|
+
*/
|
|
16
|
+
export class ReactTemplateEngine {
|
|
17
|
+
constructor(baseDir) {
|
|
18
|
+
this.baseDir = baseDir;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Renders a React view wrapped in the shared Document layout.
|
|
22
|
+
*
|
|
23
|
+
* @param view - The view component name (without .js extension)
|
|
24
|
+
* @param data - Props to pass both to Document and the view
|
|
25
|
+
* @returns Rendered HTML string with <!DOCTYPE html>
|
|
26
|
+
*/
|
|
27
|
+
async render(view, data = {}) {
|
|
28
|
+
// 1️⃣ Load Document (HTML shell)
|
|
29
|
+
const documentPath = path.resolve(this.baseDir, 'document.js');
|
|
30
|
+
const documentUrl = pathToFileURL(documentPath).href;
|
|
31
|
+
const documentModule = await import(documentUrl);
|
|
32
|
+
const Document = documentModule.default;
|
|
33
|
+
if (!Document) {
|
|
34
|
+
throw new Error(`React document has no default export at ${documentPath}`);
|
|
35
|
+
}
|
|
36
|
+
// 2️⃣ Load view (React page component)
|
|
37
|
+
const viewPath = path.resolve(this.baseDir, `${view}.js`);
|
|
38
|
+
const viewUrl = pathToFileURL(viewPath).href;
|
|
39
|
+
const viewModule = await import(viewUrl);
|
|
40
|
+
const Component = viewModule.default;
|
|
41
|
+
if (!Component) {
|
|
42
|
+
throw new Error(`React view "${view}" has no default export at ${viewPath}`);
|
|
43
|
+
}
|
|
44
|
+
// 3️⃣ Compose React tree (Document → Component)
|
|
45
|
+
const content = createElement(Component, data);
|
|
46
|
+
const page = createElement(Document, data, content);
|
|
47
|
+
// 4️⃣ Convert to HTML string with doctype prefix
|
|
48
|
+
const html = renderToString(page);
|
|
49
|
+
return '<!DOCTYPE html>' + html;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=react-template-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-template-engine.js","sourceRoot":"","sources":["../src/react-template-engine.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAqB,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIlD;;;;;;;;;;GAUG;AACH,MAAM,OAAO,mBAAmB;IAI9B,YAAY,OAAe;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,MAAM,CAAC,IAAY,EAAE,OAAgC,EAAE;QAClE,iCAAiC;QACjC,MAAM,YAAY,GAAW,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QACvE,MAAM,WAAW,GAAW,aAAa,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC;QAC7D,MAAM,cAAc,GAAwB,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QACtE,MAAM,QAAQ,GAA8B,cAAc,CAAC,OAAO,CAAC;QAEnE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,2CAA2C,YAAY,EAAE,CAAC,CAAC;QAC7E,CAAC;QAED,uCAAuC;QACvC,MAAM,QAAQ,GAAW,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;QAClE,MAAM,OAAO,GAAW,aAAa,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;QACrD,MAAM,UAAU,GAAwB,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QAC9D,MAAM,SAAS,GAA8B,UAAU,CAAC,OAAO,CAAC;QAEhE,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,eAAe,IAAI,8BAA8B,QAAQ,EAAE,CAAC,CAAC;QAC/E,CAAC;QAED,gDAAgD;QAChD,MAAM,OAAO,GAAiB,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAiB,aAAa,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAElE,iDAAiD;QACjD,MAAM,IAAI,GAAW,cAAc,CAAC,IAAI,CAAC,CAAC;QAC1C,OAAO,iBAAiB,GAAG,IAAI,CAAC;IAClC,CAAC;CACF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { AppModule } from '@kurdel/core/app';
|
|
2
|
+
import type { ReactTemplateOptions } from './react-template-options.js';
|
|
3
|
+
/**
|
|
4
|
+
* ReactTemplateModule
|
|
5
|
+
*
|
|
6
|
+
* Application module that provides server-side React rendering
|
|
7
|
+
* via the {@link ReactTemplateEngine}.
|
|
8
|
+
*
|
|
9
|
+
* Responsibilities:
|
|
10
|
+
* - Registers `ReactTemplateEngine` as the default template engine
|
|
11
|
+
* - Exposes it through the `TemplateEngineToken`
|
|
12
|
+
*
|
|
13
|
+
* @example:
|
|
14
|
+
* ```ts
|
|
15
|
+
* const app = await createNodeApplication({
|
|
16
|
+
* modules: [
|
|
17
|
+
* ReactTemplateModule.forRoot({
|
|
18
|
+
* baseDir: resolve(__dirname, './views'),
|
|
19
|
+
* }),
|
|
20
|
+
* ],
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare class ReactTemplateModule {
|
|
25
|
+
/**
|
|
26
|
+
* Configures the module for root application context.
|
|
27
|
+
*
|
|
28
|
+
* @param options - Configuration options for the React template engine
|
|
29
|
+
* @returns AppModule definition that can be passed into `createApplication()`
|
|
30
|
+
*/
|
|
31
|
+
static forRoot(options: ReactTemplateOptions): AppModule;
|
|
32
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { TOKENS } from '@kurdel/core/tokens';
|
|
2
|
+
import { ReactTemplateEngine } from './react-template-engine.js';
|
|
3
|
+
/**
|
|
4
|
+
* ReactTemplateModule
|
|
5
|
+
*
|
|
6
|
+
* Application module that provides server-side React rendering
|
|
7
|
+
* via the {@link ReactTemplateEngine}.
|
|
8
|
+
*
|
|
9
|
+
* Responsibilities:
|
|
10
|
+
* - Registers `ReactTemplateEngine` as the default template engine
|
|
11
|
+
* - Exposes it through the `TemplateEngineToken`
|
|
12
|
+
*
|
|
13
|
+
* @example:
|
|
14
|
+
* ```ts
|
|
15
|
+
* const app = await createNodeApplication({
|
|
16
|
+
* modules: [
|
|
17
|
+
* ReactTemplateModule.forRoot({
|
|
18
|
+
* baseDir: resolve(__dirname, './views'),
|
|
19
|
+
* }),
|
|
20
|
+
* ],
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export class ReactTemplateModule {
|
|
25
|
+
/**
|
|
26
|
+
* Configures the module for root application context.
|
|
27
|
+
*
|
|
28
|
+
* @param options - Configuration options for the React template engine
|
|
29
|
+
* @returns AppModule definition that can be passed into `createApplication()`
|
|
30
|
+
*/
|
|
31
|
+
static forRoot(options) {
|
|
32
|
+
const providers = [
|
|
33
|
+
{
|
|
34
|
+
provide: TOKENS.TemplateEngineToken,
|
|
35
|
+
useFactory: () => new ReactTemplateEngine(options.baseDir),
|
|
36
|
+
singleton: true,
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
return {
|
|
40
|
+
exports: {
|
|
41
|
+
view: TOKENS.TemplateEngineToken,
|
|
42
|
+
},
|
|
43
|
+
providers,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=react-template-module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-template-module.js","sourceRoot":"","sources":["../src/react-template-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAI7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,mBAAmB;IAC9B;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CAAC,OAA6B;QAC1C,MAAM,SAAS,GAAqB;YAClC;gBACE,OAAO,EAAE,MAAM,CAAC,mBAAmB;gBACnC,UAAU,EAAE,GAAwB,EAAE,CAAC,IAAI,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC;gBAC/E,SAAS,EAAE,IAAI;aAChB;SACF,CAAC;QAEF,OAAO;YACL,OAAO,EAAE;gBACP,IAAI,EAAE,MAAM,CAAC,mBAAmB;aACjC;YACD,SAAS;SACV,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReactTemplateOptions
|
|
3
|
+
*
|
|
4
|
+
* Configuration options for the {@link ReactTemplateEngine}.
|
|
5
|
+
*
|
|
6
|
+
* Defines how and where the engine should locate and render
|
|
7
|
+
* React-based server-side templates.
|
|
8
|
+
*/
|
|
9
|
+
export interface ReactTemplateOptions {
|
|
10
|
+
/**
|
|
11
|
+
* Absolute or relative path to the directory
|
|
12
|
+
* containing your React views and `document.js` layout.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* {
|
|
17
|
+
* baseDir: resolve(__dirname, './views')
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
baseDir: string;
|
|
22
|
+
/**
|
|
23
|
+
* Optional flag to disable wrapping each view
|
|
24
|
+
* inside the shared `Document` component.
|
|
25
|
+
*
|
|
26
|
+
* When set to `false`, the engine will render
|
|
27
|
+
* only the view itself (useful for fragments or APIs).
|
|
28
|
+
*
|
|
29
|
+
* @default true
|
|
30
|
+
*/
|
|
31
|
+
withDocument?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Optional flag to enable React strict mode
|
|
34
|
+
* during server-side rendering.
|
|
35
|
+
*
|
|
36
|
+
* When enabled, the engine will wrap rendered content
|
|
37
|
+
* with `<React.StrictMode>` to help detect unsafe patterns.
|
|
38
|
+
*
|
|
39
|
+
* @default false
|
|
40
|
+
*/
|
|
41
|
+
strictMode?: boolean;
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-template-options.js","sourceRoot":"","sources":["../src/react-template-options.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kurdel/template-react",
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
|
+
"description": "React server-side rendering template engine for Kurdel",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./lib/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./lib/index.js",
|
|
10
|
+
"types": "./lib/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"lib"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"prepack": "npm run build",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"test:ui": "vitest",
|
|
18
|
+
"test:watch": "vitest --watch",
|
|
19
|
+
"coverage": "vitest run --coverage",
|
|
20
|
+
"clean": "rimraf lib ../../.cache/tsconfig.template-react.build.tsbuildinfo",
|
|
21
|
+
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
22
|
+
"build:force": "npm run clean && tsc -p tsconfig.build.json --force && tsc-alias -p tsconfig.build.json"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"kurdel",
|
|
26
|
+
"framework",
|
|
27
|
+
"react",
|
|
28
|
+
"ssr",
|
|
29
|
+
"template"
|
|
30
|
+
],
|
|
31
|
+
"author": "Andrii Sorokin",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/ignorantic/kurdel.git",
|
|
39
|
+
"directory": "packages/template-react"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/ignorantic/kurdel/tree/main/packages/template-react#readme",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/ignorantic/kurdel/issues"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public",
|
|
47
|
+
"tag": "beta"
|
|
48
|
+
},
|
|
49
|
+
"sideEffects": false,
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"react": ">=18.0.0",
|
|
52
|
+
"react-dom": ">=18.0.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"react": "^18.3.1",
|
|
56
|
+
"react-dom": "^18.3.1",
|
|
57
|
+
"@types/react": "^18.3.3",
|
|
58
|
+
"@types/react-dom": "^18.3.3",
|
|
59
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
60
|
+
"vitest": "^3.2.4",
|
|
61
|
+
"rimraf": "^6.0.1",
|
|
62
|
+
"tsc-alias": "^1.8.16"
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"@kurdel/core": "0.1.0-beta.1"
|
|
66
|
+
}
|
|
67
|
+
}
|