@coherent.js/koa 1.0.0-beta.3 → 1.0.0-beta.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/README.md +421 -0
- package/dist/index.cjs +10 -120
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +10 -110
- package/dist/index.js.map +4 -4
- package/package.json +3 -2
package/README.md
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
# @coherent.js/koa
|
|
2
|
+
|
|
3
|
+
Koa.js adapter for Coherent.js - High-performance server-side rendering with Koa integration.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @coherent.js/koa
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @coherent.js/koa
|
|
11
|
+
# or
|
|
12
|
+
yarn add @coherent.js/koa
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Note:** You also need to install Koa and Coherent.js core:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install koa @coherent.js/core
|
|
19
|
+
# or
|
|
20
|
+
pnpm add koa @coherent.js/core
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Overview
|
|
24
|
+
|
|
25
|
+
The `@coherent.js/koa` package provides seamless integration between Coherent.js and Koa.js, enabling you to build high-performance server-side rendered applications with Koa's middleware ecosystem.
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
import Koa from 'koa';
|
|
31
|
+
import { createCoherentHandler } from '@coherent.js/koa';
|
|
32
|
+
|
|
33
|
+
// Create your Coherent.js component
|
|
34
|
+
function App({ name = 'World' }) {
|
|
35
|
+
return {
|
|
36
|
+
div: {
|
|
37
|
+
children: [
|
|
38
|
+
{ h1: { text: `Hello, ${name}!` } },
|
|
39
|
+
{ p: { text: 'This is rendered with Coherent.js' } }
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Create Koa app
|
|
46
|
+
const app = new Koa();
|
|
47
|
+
|
|
48
|
+
// Add Coherent.js handler
|
|
49
|
+
app.use(createCoherentHandler(App, {
|
|
50
|
+
// Optional configuration
|
|
51
|
+
template: ({ html, head, body }) => `
|
|
52
|
+
<!DOCTYPE html>
|
|
53
|
+
<html>
|
|
54
|
+
<head>
|
|
55
|
+
<title>Coherent.js Koa App</title>
|
|
56
|
+
${head}
|
|
57
|
+
</head>
|
|
58
|
+
<body>
|
|
59
|
+
<div id="app">${body}</div>
|
|
60
|
+
</body>
|
|
61
|
+
</html>
|
|
62
|
+
`
|
|
63
|
+
}));
|
|
64
|
+
|
|
65
|
+
// Start server
|
|
66
|
+
const PORT = process.env.PORT || 3000;
|
|
67
|
+
app.listen(PORT, () => {
|
|
68
|
+
console.log(`Server running on http://localhost:${PORT}`);
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Features
|
|
73
|
+
|
|
74
|
+
### Middleware Integration
|
|
75
|
+
|
|
76
|
+
Use Koa middleware alongside Coherent.js rendering:
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
import Koa from 'koa';
|
|
80
|
+
import logger from 'koa-logger';
|
|
81
|
+
import { createCoherentHandler } from '@coherent.js/koa';
|
|
82
|
+
|
|
83
|
+
const app = new Koa();
|
|
84
|
+
|
|
85
|
+
// Add Koa middleware
|
|
86
|
+
app.use(logger());
|
|
87
|
+
|
|
88
|
+
// Add Coherent.js rendering
|
|
89
|
+
app.use(createCoherentHandler(App));
|
|
90
|
+
|
|
91
|
+
app.listen(3000);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Request Context Access
|
|
95
|
+
|
|
96
|
+
Access Koa request context in your components:
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
function App({ ctx }) {
|
|
100
|
+
// ctx is the Koa context object
|
|
101
|
+
const userAgent = ctx.get('User-Agent');
|
|
102
|
+
const ipAddress = ctx.ip;
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
div: {
|
|
106
|
+
children: [
|
|
107
|
+
{ p: { text: `Your IP: ${ipAddress}` } },
|
|
108
|
+
{ p: { text: `User Agent: ${userAgent}` } }
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Custom Routes
|
|
116
|
+
|
|
117
|
+
Handle specific routes with Coherent.js:
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
import Koa from 'koa';
|
|
121
|
+
import Router from '@koa/router';
|
|
122
|
+
import { createCoherentHandler } from '@coherent.js/koa';
|
|
123
|
+
|
|
124
|
+
const app = new Koa();
|
|
125
|
+
const router = new Router();
|
|
126
|
+
|
|
127
|
+
// Handle specific routes
|
|
128
|
+
router.get('/', createCoherentHandler(HomePage));
|
|
129
|
+
router.get('/about', createCoherentHandler(AboutPage));
|
|
130
|
+
router.get('/users/:id', createCoherentHandler(UserProfile));
|
|
131
|
+
|
|
132
|
+
app.use(router.routes());
|
|
133
|
+
app.listen(3000);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Error Handling
|
|
137
|
+
|
|
138
|
+
Integrate with Koa's error handling:
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
import Koa from 'koa';
|
|
142
|
+
import { createCoherentHandler } from '@coherent.js/koa';
|
|
143
|
+
|
|
144
|
+
const app = new Koa();
|
|
145
|
+
|
|
146
|
+
// Error handling middleware
|
|
147
|
+
app.use(async (ctx, next) => {
|
|
148
|
+
try {
|
|
149
|
+
await next();
|
|
150
|
+
} catch (err) {
|
|
151
|
+
ctx.status = err.status || 500;
|
|
152
|
+
ctx.body = { error: err.message };
|
|
153
|
+
ctx.app.emit('error', err, ctx);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Coherent.js handler
|
|
158
|
+
app.use(createCoherentHandler(App));
|
|
159
|
+
|
|
160
|
+
app.listen(3000);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Configuration Options
|
|
164
|
+
|
|
165
|
+
### Template Function
|
|
166
|
+
|
|
167
|
+
Customize the HTML template:
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
app.use(createCoherentHandler(App, {
|
|
171
|
+
template: ({ html, head, body, ctx }) => `
|
|
172
|
+
<!DOCTYPE html>
|
|
173
|
+
<html lang="${ctx.acceptsLanguages()[0] || 'en'}">
|
|
174
|
+
<head>
|
|
175
|
+
<meta charset="utf-8">
|
|
176
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
177
|
+
${head}
|
|
178
|
+
</head>
|
|
179
|
+
<body>
|
|
180
|
+
<div id="app">${body}</div>
|
|
181
|
+
<script>
|
|
182
|
+
window.__INITIAL_DATA__ = ${JSON.stringify(ctx.state)};
|
|
183
|
+
</script>
|
|
184
|
+
</body>
|
|
185
|
+
</html>
|
|
186
|
+
`
|
|
187
|
+
}));
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Props Function
|
|
191
|
+
|
|
192
|
+
Customize component props based on Koa context:
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
app.use(createCoherentHandler(App, {
|
|
196
|
+
props: (ctx) => ({
|
|
197
|
+
userAgent: ctx.get('User-Agent'),
|
|
198
|
+
url: ctx.url,
|
|
199
|
+
user: ctx.state.user || null,
|
|
200
|
+
query: ctx.query
|
|
201
|
+
})
|
|
202
|
+
}));
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Error Component
|
|
206
|
+
|
|
207
|
+
Provide a custom error component:
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
function ErrorPage({ error, status }) {
|
|
211
|
+
return {
|
|
212
|
+
div: {
|
|
213
|
+
className: 'error-page',
|
|
214
|
+
children: [
|
|
215
|
+
{ h1: { text: `Error ${status}` } },
|
|
216
|
+
{ p: { text: error.message } }
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
app.use(createCoherentHandler(App, {
|
|
223
|
+
errorComponent: ErrorPage
|
|
224
|
+
}));
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Performance Optimizations
|
|
228
|
+
|
|
229
|
+
### Caching
|
|
230
|
+
|
|
231
|
+
Enable response caching:
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
import cache from 'koa-cache-lite';
|
|
235
|
+
|
|
236
|
+
app.use(cache({
|
|
237
|
+
'/api/*': 5 * 60 * 1000, // 5 minutes for API routes
|
|
238
|
+
'/static/*': 60 * 60 * 1000 // 1 hour for static assets
|
|
239
|
+
}));
|
|
240
|
+
|
|
241
|
+
app.use(createCoherentHandler(App));
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Compression
|
|
245
|
+
|
|
246
|
+
Add response compression:
|
|
247
|
+
|
|
248
|
+
```javascript
|
|
249
|
+
import compress from 'koa-compress';
|
|
250
|
+
|
|
251
|
+
app.use(compress({
|
|
252
|
+
threshold: 2048,
|
|
253
|
+
gzip: { flush: require('zlib').constants.Z_SYNC_FLUSH }
|
|
254
|
+
}));
|
|
255
|
+
|
|
256
|
+
app.use(createCoherentHandler(App));
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Advanced Usage
|
|
260
|
+
|
|
261
|
+
### Server-Side State Management
|
|
262
|
+
|
|
263
|
+
Manage state during server rendering:
|
|
264
|
+
|
|
265
|
+
```javascript
|
|
266
|
+
function App({ ctx }) {
|
|
267
|
+
// Create request-scoped state
|
|
268
|
+
const requestState = {
|
|
269
|
+
requestId: Math.random().toString(36),
|
|
270
|
+
renderStartTime: Date.now()
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
ctx.state.requestState = requestState;
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
div: {
|
|
277
|
+
children: [
|
|
278
|
+
{ p: { text: `Request ID: ${requestState.requestId}` } }
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Integration with Koa Router
|
|
286
|
+
|
|
287
|
+
Advanced routing with parameters:
|
|
288
|
+
|
|
289
|
+
```javascript
|
|
290
|
+
import Router from '@koa/router';
|
|
291
|
+
|
|
292
|
+
const router = new Router();
|
|
293
|
+
|
|
294
|
+
router.get('/', createCoherentHandler(HomePage));
|
|
295
|
+
router.get('/users/:id', createCoherentHandler(UserProfile, {
|
|
296
|
+
props: (ctx) => ({
|
|
297
|
+
userId: ctx.params.id,
|
|
298
|
+
query: ctx.query
|
|
299
|
+
})
|
|
300
|
+
}));
|
|
301
|
+
router.get('/api/*', createCoherentHandler(ApiDocs));
|
|
302
|
+
|
|
303
|
+
app.use(router.routes());
|
|
304
|
+
app.use(router.allowedMethods());
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## API Reference
|
|
308
|
+
|
|
309
|
+
### createCoherentHandler(component, options)
|
|
310
|
+
|
|
311
|
+
Create a Koa middleware for Coherent.js rendering.
|
|
312
|
+
|
|
313
|
+
**Parameters:**
|
|
314
|
+
- `component` - Coherent.js component function
|
|
315
|
+
- `options.template` - Function to customize HTML template
|
|
316
|
+
- `options.props` - Function to generate component props from Koa context
|
|
317
|
+
- `options.errorComponent` - Component to render on errors
|
|
318
|
+
- `options.enableHydration` - Boolean to enable client-side hydration (default: true)
|
|
319
|
+
|
|
320
|
+
**Returns:** Koa middleware function
|
|
321
|
+
|
|
322
|
+
### Options
|
|
323
|
+
|
|
324
|
+
- `template` - Function receiving { html, head, body, ctx } and returning HTML string
|
|
325
|
+
- `props` - Function receiving Koa context and returning component props
|
|
326
|
+
- `errorComponent` - Component for error rendering
|
|
327
|
+
- `enableHydration` - Enable/disable hydration support
|
|
328
|
+
|
|
329
|
+
## Examples
|
|
330
|
+
|
|
331
|
+
### Full Application Example
|
|
332
|
+
|
|
333
|
+
```javascript
|
|
334
|
+
import Koa from 'koa';
|
|
335
|
+
import Router from '@koa/router';
|
|
336
|
+
import bodyParser from 'koa-bodyparser';
|
|
337
|
+
import logger from 'koa-logger';
|
|
338
|
+
import session from 'koa-session';
|
|
339
|
+
import { createCoherentHandler } from '@coherent.js/koa';
|
|
340
|
+
|
|
341
|
+
// Components
|
|
342
|
+
function HomePage({ user }) {
|
|
343
|
+
return {
|
|
344
|
+
div: {
|
|
345
|
+
children: [
|
|
346
|
+
{ h1: { text: 'Welcome to Coherent.js + Koa' } },
|
|
347
|
+
user
|
|
348
|
+
? { p: { text: `Hello, ${user.name}!` } }
|
|
349
|
+
: { a: { href: '/login', text: 'Login' } }
|
|
350
|
+
]
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function LoginPage() {
|
|
356
|
+
return {
|
|
357
|
+
form: {
|
|
358
|
+
action: '/login',
|
|
359
|
+
method: 'POST',
|
|
360
|
+
children: [
|
|
361
|
+
{ input: { type: 'email', name: 'email', placeholder: 'Email' } },
|
|
362
|
+
{ input: { type: 'password', name: 'password', placeholder: 'Password' } },
|
|
363
|
+
{ button: { type: 'submit', text: 'Login' } }
|
|
364
|
+
]
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Create app
|
|
370
|
+
const app = new Koa();
|
|
371
|
+
const router = new Router();
|
|
372
|
+
|
|
373
|
+
// Middleware
|
|
374
|
+
app.use(logger());
|
|
375
|
+
app.use(bodyParser());
|
|
376
|
+
app.keys = ['secret-key'];
|
|
377
|
+
app.use(session(app));
|
|
378
|
+
|
|
379
|
+
// Routes
|
|
380
|
+
router.get('/', createCoherentHandler(HomePage, {
|
|
381
|
+
props: (ctx) => ({ user: ctx.session.user })
|
|
382
|
+
}));
|
|
383
|
+
|
|
384
|
+
router.get('/login', createCoherentHandler(LoginPage));
|
|
385
|
+
router.post('/login', async (ctx) => {
|
|
386
|
+
// Simple auth (in production, use proper authentication)
|
|
387
|
+
const { email, password } = ctx.request.body;
|
|
388
|
+
if (email && password) {
|
|
389
|
+
ctx.session.user = { name: email.split('@')[0], email };
|
|
390
|
+
ctx.redirect('/');
|
|
391
|
+
} else {
|
|
392
|
+
ctx.status = 400;
|
|
393
|
+
ctx.body = { error: 'Invalid credentials' };
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
router.get('/logout', (ctx) => {
|
|
398
|
+
ctx.session = null;
|
|
399
|
+
ctx.redirect('/');
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Setup
|
|
403
|
+
app.use(router.routes());
|
|
404
|
+
app.use(router.allowedMethods());
|
|
405
|
+
|
|
406
|
+
const PORT = process.env.PORT || 3000;
|
|
407
|
+
app.listen(PORT, () => {
|
|
408
|
+
console.log(`Server running on http://localhost:${PORT}`);
|
|
409
|
+
});
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## Related Packages
|
|
413
|
+
|
|
414
|
+
- [@coherent.js/core](../core/README.md) - Core framework
|
|
415
|
+
- [@coherent.js/express](../express/README.md) - Express.js adapter
|
|
416
|
+
- [@coherent.js/fastify](../fastify/README.md) - Fastify adapter
|
|
417
|
+
- [@coherent.js/nextjs](../nextjs/README.md) - Next.js integration
|
|
418
|
+
|
|
419
|
+
## License
|
|
420
|
+
|
|
421
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
|
|
30
20
|
// src/index.js
|
|
@@ -53,9 +43,9 @@ Or with yarn: yarn add ${packageName}`
|
|
|
53
43
|
}
|
|
54
44
|
|
|
55
45
|
// ../core/src/core/object-utils.js
|
|
56
|
-
function validateComponent(component,
|
|
46
|
+
function validateComponent(component, path = "root") {
|
|
57
47
|
if (component === null || component === void 0) {
|
|
58
|
-
throw new Error(`Invalid component at ${
|
|
48
|
+
throw new Error(`Invalid component at ${path}: null or undefined`);
|
|
59
49
|
}
|
|
60
50
|
if (["string", "number", "boolean"].includes(typeof component)) {
|
|
61
51
|
return true;
|
|
@@ -65,31 +55,31 @@ function validateComponent(component, path2 = "root") {
|
|
|
65
55
|
}
|
|
66
56
|
if (Array.isArray(component)) {
|
|
67
57
|
component.forEach((child, index) => {
|
|
68
|
-
validateComponent(child, `${
|
|
58
|
+
validateComponent(child, `${path}[${index}]`);
|
|
69
59
|
});
|
|
70
60
|
return true;
|
|
71
61
|
}
|
|
72
62
|
if (typeof component === "object") {
|
|
73
63
|
const keys = Object.keys(component);
|
|
74
64
|
if (keys.length === 0) {
|
|
75
|
-
throw new Error(`Empty object at ${
|
|
65
|
+
throw new Error(`Empty object at ${path}`);
|
|
76
66
|
}
|
|
77
67
|
keys.forEach((key) => {
|
|
78
68
|
const value = component[key];
|
|
79
69
|
if (!/^[a-zA-Z][a-zA-Z0-9-]*$/.test(key) && key !== "text") {
|
|
80
|
-
console.warn(`Potentially invalid tag name at ${
|
|
70
|
+
console.warn(`Potentially invalid tag name at ${path}: ${key}`);
|
|
81
71
|
}
|
|
82
72
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
83
73
|
if (value.children) {
|
|
84
|
-
validateComponent(value.children, `${
|
|
74
|
+
validateComponent(value.children, `${path}.${key}.children`);
|
|
85
75
|
}
|
|
86
76
|
} else if (value && typeof value !== "string" && typeof value !== "number" && typeof value !== "function") {
|
|
87
|
-
throw new Error(`Invalid value type at ${
|
|
77
|
+
throw new Error(`Invalid value type at ${path}.${key}: ${typeof value}`);
|
|
88
78
|
}
|
|
89
79
|
});
|
|
90
80
|
return true;
|
|
91
81
|
}
|
|
92
|
-
throw new Error(`Invalid component type at ${
|
|
82
|
+
throw new Error(`Invalid component type at ${path}: ${typeof component}`);
|
|
93
83
|
}
|
|
94
84
|
function isCoherentObject(obj) {
|
|
95
85
|
if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
|
|
@@ -171,6 +161,7 @@ function createPerformanceMonitor(options = {}) {
|
|
|
171
161
|
},
|
|
172
162
|
alerts: {
|
|
173
163
|
enabled: true,
|
|
164
|
+
debounceMs: 5e3,
|
|
174
165
|
rules: []
|
|
175
166
|
},
|
|
176
167
|
resources: {
|
|
@@ -332,7 +323,7 @@ function createPerformanceMonitor(options = {}) {
|
|
|
332
323
|
const alertKey = `${rule.metric}-${rule.condition}-${rule.threshold}`;
|
|
333
324
|
const lastTriggered = alertState.triggered.get(alertKey);
|
|
334
325
|
const now = Date.now();
|
|
335
|
-
if (!lastTriggered || now - lastTriggered >
|
|
326
|
+
if (!lastTriggered || now - lastTriggered > opts.alerts.debounceMs) {
|
|
336
327
|
alertState.triggered.set(alertKey, now);
|
|
337
328
|
alertState.history.push({
|
|
338
329
|
rule,
|
|
@@ -1314,107 +1305,6 @@ function createCacheManager(options = {}) {
|
|
|
1314
1305
|
}
|
|
1315
1306
|
var cacheManager = createCacheManager();
|
|
1316
1307
|
|
|
1317
|
-
// ../core/src/rendering/css-manager.js
|
|
1318
|
-
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
1319
|
-
var import_node_path = __toESM(require("node:path"), 1);
|
|
1320
|
-
var CSSManager = class {
|
|
1321
|
-
constructor(options = {}) {
|
|
1322
|
-
this.options = {
|
|
1323
|
-
basePath: process.cwd(),
|
|
1324
|
-
minify: false,
|
|
1325
|
-
cache: true,
|
|
1326
|
-
autoprefixer: false,
|
|
1327
|
-
...options
|
|
1328
|
-
};
|
|
1329
|
-
this.cache = /* @__PURE__ */ new Map();
|
|
1330
|
-
this.loadedFiles = /* @__PURE__ */ new Set();
|
|
1331
|
-
}
|
|
1332
|
-
/**
|
|
1333
|
-
* Load CSS file content
|
|
1334
|
-
*/
|
|
1335
|
-
async loadCSSFile(filePath) {
|
|
1336
|
-
const fullPath = import_node_path.default.resolve(this.options.basePath, filePath);
|
|
1337
|
-
const cacheKey = fullPath;
|
|
1338
|
-
if (this.options.cache && this.cache.has(cacheKey)) {
|
|
1339
|
-
return this.cache.get(cacheKey);
|
|
1340
|
-
}
|
|
1341
|
-
try {
|
|
1342
|
-
let content = await import_promises.default.readFile(fullPath, "utf8");
|
|
1343
|
-
if (this.options.minify) {
|
|
1344
|
-
content = this.minifyCSS(content);
|
|
1345
|
-
}
|
|
1346
|
-
if (this.options.cache) {
|
|
1347
|
-
this.cache.set(cacheKey, content);
|
|
1348
|
-
}
|
|
1349
|
-
this.loadedFiles.add(filePath);
|
|
1350
|
-
return content;
|
|
1351
|
-
} catch (_error) {
|
|
1352
|
-
console.warn(`Failed to load CSS file: ${filePath}`, _error.message);
|
|
1353
|
-
return "";
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
/**
|
|
1357
|
-
* Load multiple CSS files
|
|
1358
|
-
*/
|
|
1359
|
-
async loadCSSFiles(filePaths) {
|
|
1360
|
-
if (!Array.isArray(filePaths)) {
|
|
1361
|
-
filePaths = [filePaths];
|
|
1362
|
-
}
|
|
1363
|
-
const cssContents = await Promise.all(
|
|
1364
|
-
filePaths.map((filePath) => this.loadCSSFile(filePath))
|
|
1365
|
-
);
|
|
1366
|
-
return cssContents.join("\n");
|
|
1367
|
-
}
|
|
1368
|
-
/**
|
|
1369
|
-
* Generate CSS link tags for external files
|
|
1370
|
-
*/
|
|
1371
|
-
generateCSSLinks(filePaths, baseUrl = "/") {
|
|
1372
|
-
if (!Array.isArray(filePaths)) {
|
|
1373
|
-
filePaths = [filePaths];
|
|
1374
|
-
}
|
|
1375
|
-
return filePaths.map((filePath) => {
|
|
1376
|
-
const href = filePath.startsWith("http") ? filePath : `${baseUrl}${filePath}`.replace(/\/+/g, "/");
|
|
1377
|
-
return `<link rel="stylesheet" href="${this.escapeHtml(href)}" />`;
|
|
1378
|
-
}).join("\n");
|
|
1379
|
-
}
|
|
1380
|
-
/**
|
|
1381
|
-
* Generate inline style tag with CSS content
|
|
1382
|
-
*/
|
|
1383
|
-
generateInlineStyles(cssContent) {
|
|
1384
|
-
if (!cssContent) return "";
|
|
1385
|
-
return `<style type="text/css">
|
|
1386
|
-
${cssContent}
|
|
1387
|
-
</style>`;
|
|
1388
|
-
}
|
|
1389
|
-
/**
|
|
1390
|
-
* Basic CSS minification
|
|
1391
|
-
*/
|
|
1392
|
-
minifyCSS(css) {
|
|
1393
|
-
return css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").replace(/;\s*}/g, "}").replace(/{\s+/g, "{").replace(/;\s+/g, ";").trim();
|
|
1394
|
-
}
|
|
1395
|
-
/**
|
|
1396
|
-
* Escape HTML entities
|
|
1397
|
-
*/
|
|
1398
|
-
escapeHtml(text) {
|
|
1399
|
-
const div = { textContent: text };
|
|
1400
|
-
return div.innerHTML || text;
|
|
1401
|
-
}
|
|
1402
|
-
/**
|
|
1403
|
-
* Clear cache
|
|
1404
|
-
*/
|
|
1405
|
-
clearCache() {
|
|
1406
|
-
this.cache.clear();
|
|
1407
|
-
this.loadedFiles.clear();
|
|
1408
|
-
}
|
|
1409
|
-
/**
|
|
1410
|
-
* Get loaded file list
|
|
1411
|
-
*/
|
|
1412
|
-
getLoadedFiles() {
|
|
1413
|
-
return Array.from(this.loadedFiles);
|
|
1414
|
-
}
|
|
1415
|
-
};
|
|
1416
|
-
var defaultCSSManager = new CSSManager();
|
|
1417
|
-
|
|
1418
1308
|
// ../core/src/rendering/html-renderer.js
|
|
1419
1309
|
var rendererCache = createCacheManager({
|
|
1420
1310
|
maxSize: 1e3,
|