@aetherframework/template-engine 1.0.1 ā 1.0.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 +430 -0
- package/index.js +17 -1
- package/package.json +1 -1
- package/src/core/ModeManager.js +0 -3
- package/src/core/TemplateEngineFactory.js +0 -10
- package/src/engines/AetherEngine.js +118 -48
- package/src/engines/CompressionEngine.js +642 -0
- package/src/engines/SSRModeEngine.js +29 -4
- package/src/engines/TemplateModeEngine.js +29 -7
- package/src/examples/basic-usage.js +217 -0
- package/src/examples/layout-example.js +404 -0
- package/src/examples/ssr-example.js +180 -0
- package/src/utils/ConfigLoader.js +2 -3
- package/examples/dist/basic-usage-result.html +0 -31
- package/examples/dist/layout-example-result.html +0 -210
- package/examples/dist/templates/layouts/main.aether +0 -58
- package/examples/dist/templates/pages/home.aether +0 -116
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout Example - Demonstrates template inheritance using @extends and @section
|
|
3
|
+
* This example shows how to use template layouts and inheritance with Aether template engine
|
|
4
|
+
* Uses the same factory pattern as ssr-example.js and basic-usage.js for consistency
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createEngine } from '../index.js';
|
|
8
|
+
import fs from 'fs/promises';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
|
|
12
|
+
// Helper function to get current directory in ES Module environment
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = path.dirname(__filename);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Main function to run layout example
|
|
18
|
+
* Demonstrates template inheritance using @extends and @section directives
|
|
19
|
+
* @returns {Promise<void>}
|
|
20
|
+
*/
|
|
21
|
+
async function runLayoutExample() {
|
|
22
|
+
console.log('š Starting Layout Example...\n');
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// 1ļøā£ Initialize Engine using Factory Pattern
|
|
26
|
+
console.log('1ļøā£ Initializing Engine with Factory Pattern...');
|
|
27
|
+
|
|
28
|
+
// Create engine factory with template mode configuration
|
|
29
|
+
const factory = await createEngine({
|
|
30
|
+
mode: 'template', // Use template mode for layout rendering
|
|
31
|
+
cacheEnabled: true, // Enable caching for better performance
|
|
32
|
+
debug: true, // Enable debug logging to see compilation details
|
|
33
|
+
templateDir: path.join(__dirname, './dist/templates') // Set template directory
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
console.log('ā
Engine factory initialized successfully\n');
|
|
37
|
+
|
|
38
|
+
// 2ļøā£ Create Renderer from Factory
|
|
39
|
+
console.log('2ļøā£ Creating Template Renderer...');
|
|
40
|
+
|
|
41
|
+
// Create a renderer instance using the factory
|
|
42
|
+
// The 'aether' engine name refers to the default Aether template engine
|
|
43
|
+
const renderer = factory.createRenderer('aether');
|
|
44
|
+
console.log('ā
Template renderer created successfully\n');
|
|
45
|
+
|
|
46
|
+
// 3ļøā£ Setup Template Directory Structure
|
|
47
|
+
console.log('3ļøā£ Setting up template directories...');
|
|
48
|
+
|
|
49
|
+
// Create necessary directories for templates
|
|
50
|
+
const layoutsDir = path.join(__dirname, './dist/templates/layouts');
|
|
51
|
+
const pagesDir = path.join(__dirname, './dist/templates/pages');
|
|
52
|
+
const distDir = path.join(__dirname, './dist');
|
|
53
|
+
|
|
54
|
+
// Create directories if they don't exist
|
|
55
|
+
await fs.mkdir(layoutsDir, { recursive: true });
|
|
56
|
+
await fs.mkdir(pagesDir, { recursive: true });
|
|
57
|
+
await fs.mkdir(distDir, { recursive: true });
|
|
58
|
+
|
|
59
|
+
console.log('š Directory structure created');
|
|
60
|
+
console.log(` - Layouts: ${layoutsDir}`);
|
|
61
|
+
console.log(` - Pages: ${pagesDir}`);
|
|
62
|
+
console.log(` - Output: ${distDir}\n`);
|
|
63
|
+
|
|
64
|
+
// 4ļøā£ Create Main Layout Template
|
|
65
|
+
console.log('4ļøā£ Creating Main Layout Template...');
|
|
66
|
+
|
|
67
|
+
// Define the main layout template with @yield directives
|
|
68
|
+
// @yield directives define sections that child templates can fill
|
|
69
|
+
const layoutContent = `<!DOCTYPE html>
|
|
70
|
+
<html lang="zh-CN">
|
|
71
|
+
<head>
|
|
72
|
+
<meta charset="UTF-8">
|
|
73
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
74
|
+
<title>@yield('title', 'Aether Framework')</title>
|
|
75
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
76
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
77
|
+
@yield('head')
|
|
78
|
+
</head>
|
|
79
|
+
<body class="bg-gray-900 text-white">
|
|
80
|
+
<!-- Header Section -->
|
|
81
|
+
<header class="bg-gray-800 shadow-lg">
|
|
82
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
83
|
+
<div class="flex justify-between h-16">
|
|
84
|
+
<div class="flex items-center">
|
|
85
|
+
<span class="text-xl font-bold text-indigo-400">Aether<span class="text-white">Framework</span></span>
|
|
86
|
+
</div>
|
|
87
|
+
<nav class="flex items-center space-x-4">
|
|
88
|
+
<a href="/" class="text-gray-300 hover:text-white transition-colors duration-200">Home</a>
|
|
89
|
+
<a href="/about" class="text-gray-300 hover:text-white transition-colors duration-200">About</a>
|
|
90
|
+
<a href="/docs" class="text-gray-300 hover:text-white transition-colors duration-200">Documentation</a>
|
|
91
|
+
</nav>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</header>
|
|
95
|
+
|
|
96
|
+
<!-- Main Content Section -->
|
|
97
|
+
<main class="py-8">
|
|
98
|
+
@yield('content')
|
|
99
|
+
</main>
|
|
100
|
+
|
|
101
|
+
<!-- Footer Section -->
|
|
102
|
+
<footer class="bg-gray-800 border-t border-gray-700 mt-12">
|
|
103
|
+
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
|
104
|
+
<div class="flex justify-between items-center">
|
|
105
|
+
<p class="text-sm text-gray-400">
|
|
106
|
+
© {{ currentYear }} Aether Template Engine. All rights reserved.
|
|
107
|
+
</p>
|
|
108
|
+
<div class="flex space-x-4">
|
|
109
|
+
<a href="#" class="text-gray-400 hover:text-white">
|
|
110
|
+
<i class="fab fa-github"></i>
|
|
111
|
+
</a>
|
|
112
|
+
<a href="#" class="text-gray-400 hover:text-white">
|
|
113
|
+
<i class="fab fa-twitter"></i>
|
|
114
|
+
</a>
|
|
115
|
+
<a href="#" class="text-gray-400 hover:text-white">
|
|
116
|
+
<i class="fab fa-discord"></i>
|
|
117
|
+
</a>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</footer>
|
|
122
|
+
|
|
123
|
+
<!-- Scripts Section -->
|
|
124
|
+
@yield('scripts')
|
|
125
|
+
</body>
|
|
126
|
+
</html>`;
|
|
127
|
+
|
|
128
|
+
// Save layout template to file
|
|
129
|
+
const layoutPath = path.join(layoutsDir, 'main.aether');
|
|
130
|
+
await fs.writeFile(layoutPath, layoutContent, 'utf-8');
|
|
131
|
+
console.log(`ā
Layout template saved to: ${layoutPath}\n`);
|
|
132
|
+
|
|
133
|
+
// 5ļøā£ Create Child Template with @extends and @section
|
|
134
|
+
console.log('5ļøā£ Creating Child Template with Layout Inheritance...');
|
|
135
|
+
|
|
136
|
+
// Define child template that extends the main layout
|
|
137
|
+
// IMPORTANT: Use Aether/Blade syntax (@foreach), NOT Handlebars syntax ({{#each}})
|
|
138
|
+
const childTemplate = `@extends('layouts/main')
|
|
139
|
+
|
|
140
|
+
@section('title', 'Home Page - Aether Framework')
|
|
141
|
+
|
|
142
|
+
@section('head')
|
|
143
|
+
<style>
|
|
144
|
+
body {
|
|
145
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
146
|
+
line-height: 1.6;
|
|
147
|
+
}
|
|
148
|
+
.feature-grid {
|
|
149
|
+
display: grid;
|
|
150
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
151
|
+
gap: 2rem;
|
|
152
|
+
margin-top: 2rem;
|
|
153
|
+
}
|
|
154
|
+
.feature-card {
|
|
155
|
+
background: rgba(255, 255, 255, 0.05);
|
|
156
|
+
border-radius: 0.75rem;
|
|
157
|
+
padding: 1.5rem;
|
|
158
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
159
|
+
transition: all 0.3s ease;
|
|
160
|
+
}
|
|
161
|
+
.feature-card:hover {
|
|
162
|
+
transform: translateY(-5px);
|
|
163
|
+
border-color: #4f46e5;
|
|
164
|
+
box-shadow: 0 10px 25px rgba(79, 70, 229, 0.2);
|
|
165
|
+
}
|
|
166
|
+
.feature-icon {
|
|
167
|
+
font-size: 2rem;
|
|
168
|
+
color: #4f46e5;
|
|
169
|
+
margin-bottom: 1rem;
|
|
170
|
+
}
|
|
171
|
+
</style>
|
|
172
|
+
@endsection
|
|
173
|
+
|
|
174
|
+
@section('content')
|
|
175
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
176
|
+
<!-- Hero Section -->
|
|
177
|
+
<div class="text-center py-12">
|
|
178
|
+
<h1 class="text-4xl font-bold text-white mb-4">
|
|
179
|
+
Welcome to Aether Framework
|
|
180
|
+
</h1>
|
|
181
|
+
<p class="text-xl text-gray-300 max-w-3xl mx-auto">
|
|
182
|
+
A modern template engine with layout inheritance, SSR support, and enhanced syntax.
|
|
183
|
+
This content is injected into the main layout using @section directives.
|
|
184
|
+
</p>
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<!-- Features Grid -->
|
|
188
|
+
<div class="feature-grid">
|
|
189
|
+
@foreach(features as feature)
|
|
190
|
+
<div class="feature-card">
|
|
191
|
+
<div class="feature-icon">
|
|
192
|
+
<i class="{{ feature.icon }}"></i>
|
|
193
|
+
</div>
|
|
194
|
+
<h3 class="text-xl font-semibold text-white mb-2">
|
|
195
|
+
{{ feature.name }}
|
|
196
|
+
</h3>
|
|
197
|
+
<p class="text-gray-300">
|
|
198
|
+
{{ feature.description }}
|
|
199
|
+
</p>
|
|
200
|
+
<div class="mt-4">
|
|
201
|
+
<span class="inline-block bg-indigo-900 text-indigo-200 text-xs font-semibold px-3 py-1 rounded-full">
|
|
202
|
+
{{ feature.tag }}
|
|
203
|
+
</span>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
@endforeach
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
<!-- Additional Content -->
|
|
210
|
+
<div class="mt-12 bg-gradient-to-r from-indigo-900/30 to-purple-900/30 rounded-2xl p-8 border border-indigo-800/30">
|
|
211
|
+
<h2 class="text-2xl font-bold text-white mb-4">
|
|
212
|
+
Why Choose Aether?
|
|
213
|
+
</h2>
|
|
214
|
+
<ul class="space-y-3 text-gray-300">
|
|
215
|
+
<li class="flex items-center">
|
|
216
|
+
<i class="fas fa-check text-green-400 mr-3"></i>
|
|
217
|
+
<span>Blade-style syntax with @extends, @section, and @yield directives</span>
|
|
218
|
+
</li>
|
|
219
|
+
<li class="flex items-center">
|
|
220
|
+
<i class="fas fa-check text-green-400 mr-3"></i>
|
|
221
|
+
<span>Server-side rendering (SSR) support with hydration</span>
|
|
222
|
+
</li>
|
|
223
|
+
<li class="flex items-center">
|
|
224
|
+
<i class="fas fa-check text-green-400 mr-3"></i>
|
|
225
|
+
<span>Template inheritance and component reuse</span>
|
|
226
|
+
</li>
|
|
227
|
+
<li class="flex items-center">
|
|
228
|
+
<i class="fas fa-check text-green-400 mr-3"></i>
|
|
229
|
+
<span>Built-in caching for optimal performance</span>
|
|
230
|
+
</li>
|
|
231
|
+
</ul>
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
@endsection
|
|
235
|
+
|
|
236
|
+
@section('scripts')
|
|
237
|
+
<script>
|
|
238
|
+
console.log('Home page loaded successfully');
|
|
239
|
+
|
|
240
|
+
// Add interactive features
|
|
241
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
242
|
+
const featureCards = document.querySelectorAll('.feature-card');
|
|
243
|
+
featureCards.forEach(card => {
|
|
244
|
+
card.addEventListener('click', function() {
|
|
245
|
+
this.classList.toggle('ring-2');
|
|
246
|
+
this.classList.toggle('ring-indigo-500');
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
console.log('Interactive features initialized');
|
|
251
|
+
});
|
|
252
|
+
</script>
|
|
253
|
+
@endsection`;
|
|
254
|
+
|
|
255
|
+
// Save child template to file
|
|
256
|
+
const childPath = path.join(pagesDir, 'home.aether');
|
|
257
|
+
await fs.writeFile(childPath, childTemplate, 'utf-8');
|
|
258
|
+
console.log(`ā
Child template saved to: ${childPath}\n`);
|
|
259
|
+
|
|
260
|
+
// 6ļøā£ Define Template Data
|
|
261
|
+
console.log('6ļøā£ Defining Template Data...');
|
|
262
|
+
|
|
263
|
+
// Data to be passed to the template
|
|
264
|
+
const data = {
|
|
265
|
+
// Current year for dynamic copyright notice
|
|
266
|
+
currentYear: new Date().getFullYear(),
|
|
267
|
+
|
|
268
|
+
// Features array for dynamic rendering - FIXED: Use 'description' not 'desc'
|
|
269
|
+
features: [
|
|
270
|
+
{
|
|
271
|
+
name: 'Fast Rendering',
|
|
272
|
+
description: 'High performance template compilation and execution with built-in caching',
|
|
273
|
+
icon: 'fas fa-bolt',
|
|
274
|
+
tag: 'Performance'
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: 'Layout Inheritance',
|
|
278
|
+
description: 'Powerful @extends and @section directives for reusable layouts',
|
|
279
|
+
icon: 'fas fa-layer-group',
|
|
280
|
+
tag: 'Productivity'
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
name: 'SSR Support',
|
|
284
|
+
description: 'Server-side rendering with hydration for optimal SEO and performance',
|
|
285
|
+
icon: 'fas fa-server',
|
|
286
|
+
tag: 'Modern'
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
name: 'Easy Syntax',
|
|
290
|
+
description: 'Blade-style syntax that is intuitive and easy to learn',
|
|
291
|
+
icon: 'fas fa-code',
|
|
292
|
+
tag: 'Developer Experience'
|
|
293
|
+
}
|
|
294
|
+
],
|
|
295
|
+
|
|
296
|
+
// Helper functions available in template
|
|
297
|
+
formatDate: (date) => {
|
|
298
|
+
return new Date(date).toLocaleDateString('zh-CN', {
|
|
299
|
+
year: 'numeric',
|
|
300
|
+
month: 'long',
|
|
301
|
+
day: 'numeric'
|
|
302
|
+
});
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
// Route helper function
|
|
306
|
+
route: (name) => {
|
|
307
|
+
const routes = {
|
|
308
|
+
'home': '/',
|
|
309
|
+
'about': '/about',
|
|
310
|
+
'docs': '/documentation',
|
|
311
|
+
'contact': '/contact'
|
|
312
|
+
};
|
|
313
|
+
return routes[name] || '#';
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
console.log(`ā
Data defined with ${data.features.length} features\n`);
|
|
318
|
+
|
|
319
|
+
// 7ļøā£ Render Template with Layout Inheritance
|
|
320
|
+
console.log('7ļøā£ Rendering Template with Layout Inheritance...');
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
// Render the child template with data
|
|
324
|
+
// The engine will automatically handle @extends and @section directives
|
|
325
|
+
const result = await renderer.render(childTemplate, data);
|
|
326
|
+
|
|
327
|
+
console.log('ā
Rendering completed successfully\n');
|
|
328
|
+
|
|
329
|
+
// 8ļøā£ Display Rendered Output
|
|
330
|
+
console.log('--- Rendered Output (First 1500 characters) ---');
|
|
331
|
+
console.log(result.substring(0, 1500) + (result.length > 1500 ? '...' : ''));
|
|
332
|
+
console.log('-----------------------------------------------\n');
|
|
333
|
+
|
|
334
|
+
// 9ļøā£ Save Rendered Output to dist Folder
|
|
335
|
+
console.log('8ļøā£ Saving rendered output to dist folder...');
|
|
336
|
+
|
|
337
|
+
const outputPath = path.join(distDir, 'layout-example-result.html');
|
|
338
|
+
await fs.writeFile(outputPath, result, 'utf-8');
|
|
339
|
+
|
|
340
|
+
console.log(`š¾ HTML file saved to: ${outputPath}`);
|
|
341
|
+
console.log(`š File size: ${result.length} characters\n`);
|
|
342
|
+
|
|
343
|
+
// š Display Engine Statistics
|
|
344
|
+
console.log('š Engine Factory Statistics:');
|
|
345
|
+
const stats = factory.getStats();
|
|
346
|
+
console.log(JSON.stringify(stats, null, 2));
|
|
347
|
+
|
|
348
|
+
// Additional debug information
|
|
349
|
+
console.log('\nš§ Configuration Details:');
|
|
350
|
+
console.log(` - Mode: ${stats.mode}`);
|
|
351
|
+
console.log(` - Cache Enabled: ${stats.cacheEnabled}`);
|
|
352
|
+
console.log(` - Cache Size: ${stats.cacheSize}`);
|
|
353
|
+
console.log(` - Available Engines: ${stats.engines.join(', ')}`);
|
|
354
|
+
console.log(` - Template Directory: ${stats.templateDir || 'Not specified'}`);
|
|
355
|
+
|
|
356
|
+
// Layout-specific information
|
|
357
|
+
console.log('\nšÆ Layout Features Demonstrated:');
|
|
358
|
+
console.log(' 1. Template inheritance with @extends directive');
|
|
359
|
+
console.log(' 2. Section definition with @section directive');
|
|
360
|
+
console.log(' 3. Content injection with @yield directive');
|
|
361
|
+
console.log(' 4. Default content for @yield sections');
|
|
362
|
+
console.log(' 5. Multiple sections (title, head, content, scripts)');
|
|
363
|
+
console.log(' 6. Conditional rendering with @if/@else');
|
|
364
|
+
console.log(' 7. Looping with @foreach directive');
|
|
365
|
+
console.log(' 8. Variable interpolation with {{ }} syntax');
|
|
366
|
+
|
|
367
|
+
} catch (error) {
|
|
368
|
+
// Enhanced error handling for rendering errors
|
|
369
|
+
console.error('ā Error during template rendering:');
|
|
370
|
+
console.error(` Message: ${error.message}`);
|
|
371
|
+
console.error(` Stack: ${error.stack}`);
|
|
372
|
+
|
|
373
|
+
// Provide helpful debugging information
|
|
374
|
+
console.error('\nš§ Debugging Tips:');
|
|
375
|
+
console.error(' 1. Check that layout file exists at: ' + layoutPath);
|
|
376
|
+
console.error(' 2. Verify @extends path is correct (should match file path)');
|
|
377
|
+
console.error(' 3. Ensure all @section directives have matching @endsection');
|
|
378
|
+
console.error(' 4. Check for syntax errors in template files');
|
|
379
|
+
console.error(' 5. Make sure you are using Aether syntax (@foreach) not Handlebars ({{#each}})');
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
} catch (error) {
|
|
383
|
+
// Handle initialization and setup errors
|
|
384
|
+
console.error('ā Error during engine initialization or setup:');
|
|
385
|
+
console.error(` Message: ${error.message}`);
|
|
386
|
+
console.error(` Stack: ${error.stack}`);
|
|
387
|
+
|
|
388
|
+
console.error('\nš§ Troubleshooting:');
|
|
389
|
+
console.error(' 1. Check that all required modules are installed');
|
|
390
|
+
console.error(' 2. Verify the index.js file exports createEngine correctly');
|
|
391
|
+
console.error(' 3. Ensure file system permissions allow directory creation');
|
|
392
|
+
console.error(' 4. Check that template directory structure is correct');
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Execute the main function with error handling
|
|
397
|
+
runLayoutExample().catch(error => {
|
|
398
|
+
console.error('š„ Unhandled error in main execution:');
|
|
399
|
+
console.error(error);
|
|
400
|
+
process.exit(1);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// Export the run function for potential module usage
|
|
404
|
+
export { runLayoutExample };
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSR Mode Example
|
|
3
|
+
* Demonstrates Server-Side Rendering capabilities with hydration data
|
|
4
|
+
* This example shows how to use the TemplateEngineFactory to create SSR-enabled renderers
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createEngine } from '../index.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Main function to run SSR example
|
|
11
|
+
* @returns {Promise<void>}
|
|
12
|
+
*/
|
|
13
|
+
async function runSSRExample() {
|
|
14
|
+
console.log('š Starting SSR Mode Example...\n');
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// 1. Initialize Engine in SSR Mode
|
|
18
|
+
console.log('1ļøā£ Initializing Engine in SSR Mode...');
|
|
19
|
+
|
|
20
|
+
// Create engine factory with SSR mode enabled
|
|
21
|
+
const factory = await createEngine({
|
|
22
|
+
mode: 'ssr', // Set to SSR mode for server-side rendering
|
|
23
|
+
debug: true, // Enable debug logging
|
|
24
|
+
ssrHydrate: true, // Enable hydration data injection
|
|
25
|
+
cacheEnabled: true, // Enable caching for better performance
|
|
26
|
+
templateDir: './dist' // Optional: specify template directory
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
console.log('ā
Engine factory initialized in SSR mode\n');
|
|
30
|
+
|
|
31
|
+
// 2. Create SSR Renderer using factory
|
|
32
|
+
console.log('2ļøā£ Creating SSR Renderer...');
|
|
33
|
+
|
|
34
|
+
// Create renderer with SSR mode engine
|
|
35
|
+
const renderer = factory.createRenderer('ssr-mode');
|
|
36
|
+
console.log('ā
SSR Renderer created\n');
|
|
37
|
+
|
|
38
|
+
// 3. Define Template with Aether syntax (not Handlebars)
|
|
39
|
+
// Note: Aether uses Blade-style syntax, not Handlebars
|
|
40
|
+
const template = `
|
|
41
|
+
<div class="app-container">
|
|
42
|
+
<h1 class="title">{{title}}</h1>
|
|
43
|
+
<p class="description">{{description}}</p>
|
|
44
|
+
|
|
45
|
+
<div class="user-list">
|
|
46
|
+
@foreach(users as user)
|
|
47
|
+
<div class="user-card" id="user-{{user.id}}">
|
|
48
|
+
<img src="{{user.avatar}}" alt="{{user.name}}" />
|
|
49
|
+
<h3>{{user.name}}</h3>
|
|
50
|
+
<p>{{user.role}}</p>
|
|
51
|
+
</div>
|
|
52
|
+
@endforeach
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<button id="load-more" onclick="loadMore()">Load More</button>
|
|
56
|
+
</div>`;
|
|
57
|
+
|
|
58
|
+
// 4. Define Data for template rendering
|
|
59
|
+
const data = {
|
|
60
|
+
title: 'User Dashboard',
|
|
61
|
+
description: 'Manage your team members efficiently',
|
|
62
|
+
users: [
|
|
63
|
+
{
|
|
64
|
+
id: 1,
|
|
65
|
+
name: 'Alice Johnson',
|
|
66
|
+
role: 'Admin',
|
|
67
|
+
avatar: 'https://picsum.photos/50/50?random=1'
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 2,
|
|
71
|
+
name: 'Bob Smith',
|
|
72
|
+
role: 'Developer',
|
|
73
|
+
avatar: 'https://picsum.photos/50/50?random=2'
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: 3,
|
|
77
|
+
name: 'Charlie Brown',
|
|
78
|
+
role: 'Designer',
|
|
79
|
+
avatar: 'https://picsum.photos/50/50?random=3'
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
// Additional metadata for SSR enhancement
|
|
83
|
+
keywords: 'Aether,Framework,Web,SSR',
|
|
84
|
+
head: '<link rel="stylesheet" href="/custom-styles.css">',
|
|
85
|
+
scripts: '<script src="/custom-script.js"></script>'
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// 5. Render template with SSR enhancements
|
|
89
|
+
console.log('3ļøā£ Rendering with SSR Enhancements...');
|
|
90
|
+
|
|
91
|
+
// Use the renderer to process template with data
|
|
92
|
+
const result = await renderer.render(template, data);
|
|
93
|
+
console.log('ā
SSR Rendering completed\n');
|
|
94
|
+
|
|
95
|
+
// 6. Output the rendered result
|
|
96
|
+
console.log('--- SSR Rendered Output (First 1000 chars) ---');
|
|
97
|
+
console.log(result.substring(0, 1000) + (result.length > 1000 ? '...' : ''));
|
|
98
|
+
console.log('----------------------------------------------\n');
|
|
99
|
+
|
|
100
|
+
// 7. Verify SSR features are working
|
|
101
|
+
console.log('š Verifying SSR Features:');
|
|
102
|
+
|
|
103
|
+
// Check for hydration data injection
|
|
104
|
+
if (result.includes('ssr-data')) {
|
|
105
|
+
console.log('ā
Hydration data injected successfully');
|
|
106
|
+
} else {
|
|
107
|
+
console.log('ā ļø Hydration data missing');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Check for full HTML document structure
|
|
111
|
+
if (result.includes('<!DOCTYPE html>')) {
|
|
112
|
+
console.log('ā
Full HTML document generated');
|
|
113
|
+
} else {
|
|
114
|
+
console.log('ā ļø Not a complete HTML document');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Check for Tailwind CSS inclusion
|
|
118
|
+
if (result.includes('tailwindcss.com')) {
|
|
119
|
+
console.log('ā
Tailwind CSS included');
|
|
120
|
+
} else {
|
|
121
|
+
console.log('ā ļø Tailwind CSS not found');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Check for Font Awesome icons
|
|
125
|
+
if (result.includes('font-awesome')) {
|
|
126
|
+
console.log('ā
Font Awesome included');
|
|
127
|
+
} else {
|
|
128
|
+
console.log('ā ļø Font Awesome not found');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 8. Save rendered output to dist folder for inspection
|
|
132
|
+
console.log('\nš¾ Saving output to dist folder...');
|
|
133
|
+
|
|
134
|
+
// Import file system module for saving output
|
|
135
|
+
import('fs').then(fs => {
|
|
136
|
+
// Create dist directory if it doesn't exist
|
|
137
|
+
const distDir = './dist';
|
|
138
|
+
if (!fs.existsSync(distDir)) {
|
|
139
|
+
fs.mkdirSync(distDir, { recursive: true });
|
|
140
|
+
console.log(`š Created directory: ${distDir}`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Save to dist folder
|
|
144
|
+
const outputPath = './dist/ssr-output.html';
|
|
145
|
+
fs.writeFileSync(outputPath, result, 'utf-8');
|
|
146
|
+
console.log(`ā
Output saved to: ${outputPath}`);
|
|
147
|
+
}).catch(err => {
|
|
148
|
+
console.log('ā ļø Could not save to file:', err.message);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// 9. Display engine statistics
|
|
152
|
+
console.log('\nš Engine Statistics:');
|
|
153
|
+
const stats = factory.getStats();
|
|
154
|
+
console.log(JSON.stringify(stats, null, 2));
|
|
155
|
+
|
|
156
|
+
// Additional debug information
|
|
157
|
+
console.log('\nš§ Debug Information:');
|
|
158
|
+
console.log(`- Mode: ${stats.mode}`);
|
|
159
|
+
console.log(`- Available Engines: ${stats.engines.join(', ')}`);
|
|
160
|
+
console.log(`- Cache Enabled: ${stats.cacheEnabled}`);
|
|
161
|
+
console.log(`- Cache Size: ${stats.cacheSize}`);
|
|
162
|
+
console.log(`- Template Directory: ${stats.templateDir}`);
|
|
163
|
+
|
|
164
|
+
} catch (error) {
|
|
165
|
+
// Enhanced error handling with detailed information
|
|
166
|
+
console.error('ā Error occurred during SSR example execution:');
|
|
167
|
+
console.error(`Message: ${error.message}`);
|
|
168
|
+
console.error(`Stack Trace: ${error.stack}`);
|
|
169
|
+
|
|
170
|
+
// Provide troubleshooting suggestions
|
|
171
|
+
console.error('\nš§ Troubleshooting Suggestions:');
|
|
172
|
+
console.error('1. Check that SSRModeEngine is properly registered in the factory');
|
|
173
|
+
console.error('2. Verify template syntax uses Aether/Blade style (@foreach not {{#each}})');
|
|
174
|
+
console.error('3. Ensure factory is initialized with mode: "ssr"');
|
|
175
|
+
console.error('4. Check that all required engines are imported and registered');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Execute the SSR example
|
|
180
|
+
runSSRExample();
|
|
@@ -128,12 +128,11 @@ class ConfigLoader {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
|
-
|
|
132
|
-
console.log(`š Configuration loaded from: ${configPath}`);
|
|
131
|
+
|
|
133
132
|
}
|
|
134
133
|
} catch (error) {
|
|
135
134
|
// Log warning but don't fail if configuration file cannot be loaded
|
|
136
|
-
console.warn(
|
|
135
|
+
console.warn(`Could not load config file: ${error.message}`);
|
|
137
136
|
}
|
|
138
137
|
}
|
|
139
138
|
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
<header class="header">
|
|
3
|
-
<nav class="navbar">
|
|
4
|
-
<div class="container">
|
|
5
|
-
<a class="navbar-brand" href="/">
|
|
6
|
-
<img src="/assets/images/logo.png" alt="Logo" height="40">
|
|
7
|
-
</a>
|
|
8
|
-
|
|
9
|
-
<ul class="navbar-nav">
|
|
10
|
-
<li class="nav-item">
|
|
11
|
-
<a class="nav-link" href="/">Home</a>
|
|
12
|
-
</li>
|
|
13
|
-
<li class="nav-item">
|
|
14
|
-
<a class="nav-link" href="/about">About</a>
|
|
15
|
-
</li>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
<li class="nav-item dropdown">
|
|
19
|
-
<a class="nav-link dropdown-toggle" href="#" role="button">
|
|
20
|
-
John Doe
|
|
21
|
-
</a>
|
|
22
|
-
<div class="dropdown-menu">
|
|
23
|
-
<a class="dropdown-item" href="/profile">Profile</a>
|
|
24
|
-
<a class="dropdown-item" href="/logout">Logout</a>
|
|
25
|
-
</div>
|
|
26
|
-
</li>
|
|
27
|
-
|
|
28
|
-
</ul>
|
|
29
|
-
</div>
|
|
30
|
-
</nav>
|
|
31
|
-
</header>
|