bertui 1.2.9 → 2.0.0

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.
Files changed (183) hide show
  1. package/README.md +44 -242
  2. package/TYPES_PATCH.md +17 -0
  3. package/bin/bertui.js +2 -7
  4. package/package.json +32 -98
  5. package/src/config.ts +4 -0
  6. package/src/index.ts +32 -0
  7. package/src/optional.ts +49 -0
  8. package/src/router.ts +3 -0
  9. package/tsconfig.json +29 -0
  10. package/LICENSE +0 -21
  11. package/index.js +0 -103
  12. package/src/analyzer/index.js +0 -370
  13. package/src/build/compiler/file-transpiler.js +0 -216
  14. package/src/build/compiler/index.js +0 -31
  15. package/src/build/compiler/route-discoverer.js +0 -49
  16. package/src/build/compiler/router-generator.js +0 -105
  17. package/src/build/css-builder.js +0 -81
  18. package/src/build/generators/html-generator.js +0 -263
  19. package/src/build/generators/robots-generator.js +0 -58
  20. package/src/build/generators/sitemap-generator.js +0 -63
  21. package/src/build/image-optimizer.js +0 -137
  22. package/src/build/processors/asset-processor.js +0 -19
  23. package/src/build/processors/css-builder.js +0 -142
  24. package/src/build/server-island-validator.js +0 -67
  25. package/src/build/ssr-renderer.js +0 -64
  26. package/src/build.js +0 -273
  27. package/src/cli.js +0 -131
  28. package/src/client/compiler.js +0 -522
  29. package/src/client/fast-refresh.js +0 -72
  30. package/src/client/hmr-runtime.js +0 -59
  31. package/src/compiler/index.js +0 -25
  32. package/src/compiler/router-generator-pure.js +0 -104
  33. package/src/compiler/transform.js +0 -149
  34. package/src/config/defaultConfig.js +0 -37
  35. package/src/config/index.js +0 -2
  36. package/src/config/loadConfig.js +0 -64
  37. package/src/config/og-image.png +0 -0
  38. package/src/css/index.js +0 -46
  39. package/src/css/processor.js +0 -172
  40. package/src/dev.js +0 -68
  41. package/src/hydration/index.js +0 -151
  42. package/src/image-optimizer/index.js +0 -103
  43. package/src/images/index.js +0 -102
  44. package/src/images/processor.js +0 -169
  45. package/src/layouts/index.js +0 -165
  46. package/src/loading/index.js +0 -210
  47. package/src/logger/logger.js +0 -320
  48. package/src/logger/notes.md +0 -20
  49. package/src/middleware/index.js +0 -182
  50. package/src/router/Router.js +0 -150
  51. package/src/router/SSRRouter.js +0 -156
  52. package/src/router/index.js +0 -3
  53. package/src/scaffolder/index.js +0 -310
  54. package/src/serve.js +0 -193
  55. package/src/server/dev-handler.js +0 -195
  56. package/src/server/dev-server-utils.js +0 -406
  57. package/src/server/dev-server.js +0 -15
  58. package/src/server/hmr-handler.js +0 -148
  59. package/src/server/index.js +0 -3
  60. package/src/server/notes.md +0 -1
  61. package/src/server/request-handler.js +0 -36
  62. package/src/server-islands/extractor.js +0 -198
  63. package/src/server-islands/index.js +0 -59
  64. package/src/styles/bertui.css +0 -210
  65. package/src/utils/cache.js +0 -297
  66. package/src/utils/env.js +0 -87
  67. package/src/utils/importhow.js +0 -52
  68. package/src/utils/index.js +0 -11
  69. package/src/utils/meta-extractor.js +0 -127
  70. package/types/bin/bertui.d.ts +0 -3
  71. package/types/bin/bertui.d.ts.map +0 -1
  72. package/types/error-overlay.d.ts +0 -2
  73. package/types/error-overlay.d.ts.map +0 -1
  74. package/types/index.d.ts +0 -26
  75. package/types/index.d.ts.map +0 -1
  76. package/types/scripts/fix-wasm-exports.d.ts +0 -2
  77. package/types/scripts/fix-wasm-exports.d.ts.map +0 -1
  78. package/types/src/analyzer/index.d.ts +0 -8
  79. package/types/src/analyzer/index.d.ts.map +0 -1
  80. package/types/src/build/compiler/file-transpiler.d.ts +0 -5
  81. package/types/src/build/compiler/file-transpiler.d.ts.map +0 -1
  82. package/types/src/build/compiler/index.d.ts +0 -12
  83. package/types/src/build/compiler/index.d.ts.map +0 -1
  84. package/types/src/build/compiler/route-discoverer.d.ts +0 -2
  85. package/types/src/build/compiler/route-discoverer.d.ts.map +0 -1
  86. package/types/src/build/compiler/router-generator.d.ts +0 -2
  87. package/types/src/build/compiler/router-generator.d.ts.map +0 -1
  88. package/types/src/build/css-builder.d.ts +0 -18
  89. package/types/src/build/css-builder.d.ts.map +0 -1
  90. package/types/src/build/generators/html-generator.d.ts +0 -2
  91. package/types/src/build/generators/html-generator.d.ts.map +0 -1
  92. package/types/src/build/generators/robots-generator.d.ts +0 -11
  93. package/types/src/build/generators/robots-generator.d.ts.map +0 -1
  94. package/types/src/build/generators/sitemap-generator.d.ts +0 -5
  95. package/types/src/build/generators/sitemap-generator.d.ts.map +0 -1
  96. package/types/src/build/image-optimizer.d.ts +0 -11
  97. package/types/src/build/image-optimizer.d.ts.map +0 -1
  98. package/types/src/build/processors/asset-processor.d.ts +0 -2
  99. package/types/src/build/processors/asset-processor.d.ts.map +0 -1
  100. package/types/src/build/processors/css-builder.d.ts +0 -2
  101. package/types/src/build/processors/css-builder.d.ts.map +0 -1
  102. package/types/src/build/server-island-validator.d.ts +0 -27
  103. package/types/src/build/server-island-validator.d.ts.map +0 -1
  104. package/types/src/build.d.ts +0 -5
  105. package/types/src/build.d.ts.map +0 -1
  106. package/types/src/cli.d.ts +0 -2
  107. package/types/src/cli.d.ts.map +0 -1
  108. package/types/src/client/compiler.d.ts +0 -16
  109. package/types/src/client/compiler.d.ts.map +0 -1
  110. package/types/src/client/fast-refresh.d.ts +0 -3
  111. package/types/src/client/fast-refresh.d.ts.map +0 -1
  112. package/types/src/client/hmr-runtime.d.ts +0 -4
  113. package/types/src/client/hmr-runtime.d.ts.map +0 -1
  114. package/types/src/compiler/index.d.ts +0 -8
  115. package/types/src/compiler/index.d.ts.map +0 -1
  116. package/types/src/compiler/router-generator-pure.d.ts +0 -2
  117. package/types/src/compiler/router-generator-pure.d.ts.map +0 -1
  118. package/types/src/compiler/transform.d.ts +0 -36
  119. package/types/src/compiler/transform.d.ts.map +0 -1
  120. package/types/src/config/defaultConfig.d.ts +0 -26
  121. package/types/src/config/defaultConfig.d.ts.map +0 -1
  122. package/types/src/config/index.d.ts +0 -3
  123. package/types/src/config/index.d.ts.map +0 -1
  124. package/types/src/config/loadConfig.d.ts +0 -2
  125. package/types/src/config/loadConfig.d.ts.map +0 -1
  126. package/types/src/css/index.d.ts +0 -6
  127. package/types/src/css/index.d.ts.map +0 -1
  128. package/types/src/css/processor.d.ts +0 -23
  129. package/types/src/css/processor.d.ts.map +0 -1
  130. package/types/src/dev.d.ts +0 -2
  131. package/types/src/dev.d.ts.map +0 -1
  132. package/types/src/hydration/index.d.ts +0 -33
  133. package/types/src/hydration/index.d.ts.map +0 -1
  134. package/types/src/image-optimizer/index.d.ts +0 -24
  135. package/types/src/image-optimizer/index.d.ts.map +0 -1
  136. package/types/src/images/index.d.ts +0 -12
  137. package/types/src/images/index.d.ts.map +0 -1
  138. package/types/src/images/processor.d.ts +0 -30
  139. package/types/src/images/processor.d.ts.map +0 -1
  140. package/types/src/layouts/index.d.ts +0 -28
  141. package/types/src/layouts/index.d.ts.map +0 -1
  142. package/types/src/loading/index.d.ts +0 -28
  143. package/types/src/loading/index.d.ts.map +0 -1
  144. package/types/src/logger/logger.d.ts +0 -30
  145. package/types/src/logger/logger.d.ts.map +0 -1
  146. package/types/src/middleware/index.d.ts +0 -61
  147. package/types/src/middleware/index.d.ts.map +0 -1
  148. package/types/src/router/Router.d.ts +0 -16
  149. package/types/src/router/Router.d.ts.map +0 -1
  150. package/types/src/router/SSRRouter.d.ts +0 -20
  151. package/types/src/router/SSRRouter.d.ts.map +0 -1
  152. package/types/src/router/index.d.ts +0 -3
  153. package/types/src/router/index.d.ts.map +0 -1
  154. package/types/src/scaffolder/index.d.ts +0 -14
  155. package/types/src/scaffolder/index.d.ts.map +0 -1
  156. package/types/src/serve.d.ts +0 -3
  157. package/types/src/serve.d.ts.map +0 -1
  158. package/types/src/server/dev-handler.d.ts +0 -13
  159. package/types/src/server/dev-handler.d.ts.map +0 -1
  160. package/types/src/server/dev-server-utils.d.ts +0 -6
  161. package/types/src/server/dev-server-utils.d.ts.map +0 -1
  162. package/types/src/server/dev-server.d.ts +0 -18
  163. package/types/src/server/dev-server.d.ts.map +0 -1
  164. package/types/src/server/hmr-handler.d.ts +0 -19
  165. package/types/src/server/hmr-handler.d.ts.map +0 -1
  166. package/types/src/server/index.d.ts +0 -4
  167. package/types/src/server/index.d.ts.map +0 -1
  168. package/types/src/server/request-handler.d.ts +0 -19
  169. package/types/src/server/request-handler.d.ts.map +0 -1
  170. package/types/src/server-islands/extractor.d.ts +0 -16
  171. package/types/src/server-islands/extractor.d.ts.map +0 -1
  172. package/types/src/server-islands/index.d.ts +0 -3
  173. package/types/src/server-islands/index.d.ts.map +0 -1
  174. package/types/src/utils/cache.d.ts +0 -52
  175. package/types/src/utils/cache.d.ts.map +0 -1
  176. package/types/src/utils/env.d.ts +0 -20
  177. package/types/src/utils/env.d.ts.map +0 -1
  178. package/types/src/utils/importhow.d.ts +0 -15
  179. package/types/src/utils/importhow.d.ts.map +0 -1
  180. package/types/src/utils/index.d.ts +0 -3
  181. package/types/src/utils/index.d.ts.map +0 -1
  182. package/types/src/utils/meta-extractor.d.ts +0 -13
  183. package/types/src/utils/meta-extractor.d.ts.map +0 -1
@@ -1,137 +0,0 @@
1
- // bertui/src/build/image-optimizer.js - UPDATED WITH WASM
2
- import { join, extname } from 'path';
3
- import { existsSync, mkdirSync, readdirSync } from 'fs';
4
- import logger from '../logger/logger.js';
5
- import { optimizeImage, hasWasm } from '../image-optimizer/index.js';
6
- import { copyImagesSync } from '../images/index.js';
7
-
8
- export async function optimizeImages(srcDir, outDir, options = {}) {
9
- const {
10
- quality = 80,
11
- webpQuality = 75,
12
- verbose = false
13
- } = options;
14
-
15
- // Check if WASM is available
16
- const wasmAvailable = await hasWasm();
17
-
18
- if (wasmAvailable) {
19
- logger.info(`🦀 Optimizing images with Rust WASM (quality: ${quality})...`);
20
- } else {
21
- logger.info('📋 Copying images (WASM optimizer not available)...');
22
- }
23
-
24
- const imageExtensions = [
25
- '.png', '.jpg', '.jpeg', '.webp', '.gif', '.svg',
26
- '.avif', '.ico', '.bmp', '.tiff', '.tif'
27
- ];
28
-
29
- let optimized = 0;
30
- let copied = 0;
31
- let skipped = 0;
32
- let totalSaved = 0;
33
- const results = [];
34
-
35
- if (!existsSync(srcDir)) {
36
- logger.warn(`⚠️ Source not found: ${srcDir}`);
37
- return { optimized: 0, copied: 0, saved: 0, results: [] };
38
- }
39
-
40
- mkdirSync(outDir, { recursive: true });
41
-
42
- async function processDirectory(dir, targetDir) {
43
- const entries = readdirSync(dir, { withFileTypes: true });
44
-
45
- for (const entry of entries) {
46
- const srcPath = join(dir, entry.name);
47
- const destPath = join(targetDir, entry.name);
48
-
49
- if (entry.isDirectory()) {
50
- const subDestPath = join(targetDir, entry.name);
51
- mkdirSync(subDestPath, { recursive: true });
52
- await processDirectory(srcPath, subDestPath);
53
- } else if (entry.isFile()) {
54
- const ext = extname(entry.name).toLowerCase();
55
-
56
- if (imageExtensions.includes(ext)) {
57
- try {
58
- const file = Bun.file(srcPath);
59
- const buffer = await file.arrayBuffer();
60
- const originalSize = buffer.byteLength;
61
-
62
- // Try WASM optimization first, fallback to copy
63
- if (wasmAvailable && ['.png', '.jpg', '.jpeg', '.webp'].includes(ext)) {
64
- const format = ext.slice(1);
65
- const result = await optimizeImage(buffer, {
66
- format,
67
- quality,
68
- webpQuality
69
- });
70
-
71
- await Bun.write(destPath, new Uint8Array(result.data));
72
-
73
- const saved = originalSize - result.optimized_size;
74
- totalSaved += saved;
75
- optimized++;
76
-
77
- results.push({
78
- file: entry.name,
79
- original: formatBytes(originalSize),
80
- optimized: formatBytes(result.optimized_size),
81
- saved: formatBytes(saved),
82
- percent: result.savings_percent.toFixed(1) + '%'
83
- });
84
- } else {
85
- // Just copy unsupported formats
86
- await Bun.write(destPath, file);
87
- copied++;
88
- results.push({
89
- file: entry.name,
90
- status: 'copied'
91
- });
92
- }
93
- } catch (error) {
94
- logger.warn(` Failed to process ${entry.name}: ${error.message}`);
95
- // Fallback: copy original
96
- await Bun.write(destPath, Bun.file(srcPath));
97
- copied++;
98
- }
99
- } else {
100
- // Copy non-image files
101
- await Bun.write(destPath, Bun.file(srcPath));
102
- skipped++;
103
- }
104
- }
105
- }
106
- }
107
-
108
- await processDirectory(srcDir, outDir);
109
-
110
- // Show summary
111
- if (optimized > 0) {
112
- logger.success(`✅ Optimized ${optimized} images with Rust WASM`);
113
- logger.table(results.slice(0, 10));
114
- if (results.length > 10) {
115
- logger.info(` ... and ${results.length - 10} more images`);
116
- }
117
- logger.info(`📊 Total saved: ${formatBytes(totalSaved)}`);
118
- }
119
-
120
- if (copied > 0) {
121
- logger.info(`📋 Copied ${copied} images (fallback)`);
122
- }
123
-
124
- return { optimized, copied, saved: totalSaved, results };
125
- }
126
-
127
- export function copyImages(srcDir, outDir) {
128
- return copyImagesSync(srcDir, outDir);
129
- }
130
-
131
- function formatBytes(bytes) {
132
- if (bytes === 0) return '0 B';
133
- const k = 1024;
134
- const sizes = ['B', 'KB', 'MB', 'GB'];
135
- const i = Math.floor(Math.log(bytes) / Math.log(k));
136
- return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
137
- }
@@ -1,19 +0,0 @@
1
- // bertui/src/build/processors/asset-processor.js
2
- import { join } from 'path';
3
- import { existsSync, mkdirSync } from 'fs'; // ✅ ADD THIS IMPORT
4
- import { copyImages } from '../image-optimizer.js';
5
-
6
- export async function copyAllStaticAssets(root, outDir) {
7
- const publicDir = join(root, 'public');
8
- const srcImagesDir = join(root, 'src', 'images');
9
-
10
- if (existsSync(publicDir)) {
11
- copyImages(publicDir, outDir);
12
- }
13
-
14
- if (existsSync(srcImagesDir)) {
15
- const distImagesDir = join(outDir, 'images');
16
- mkdirSync(distImagesDir, { recursive: true });
17
- copyImages(srcImagesDir, distImagesDir);
18
- }
19
- }
@@ -1,142 +0,0 @@
1
- // bertui/src/build/processors/css-builder.js - WITH SCSS + CACHING + CSS MODULES
2
- import { join } from 'path';
3
- import { existsSync, readdirSync, mkdirSync } from 'fs';
4
- import logger from '../../logger/logger.js';
5
- import { globalCache } from '../../utils/cache.js';
6
- import { minifyCSS, processSCSS } from '../../css/processor.js';
7
-
8
- export async function buildAllCSS(root, outDir) {
9
- const startTime = process.hrtime.bigint();
10
-
11
- const srcStylesDir = join(root, 'src', 'styles');
12
- // CSS modules scoped CSS is staged here by file-transpiler.js
13
- const modulesStagingDir = join(root, '.bertuibuild', 'styles-staged');
14
- const stylesOutDir = join(outDir, 'styles');
15
-
16
- mkdirSync(stylesOutDir, { recursive: true });
17
-
18
- const cacheKey = `css-build:${root}:${Date.now()}`;
19
- const cached = globalCache.get(cacheKey, { ttl: 1000 });
20
-
21
- if (cached) {
22
- logger.info(`⚡ Using cached CSS (${cached.files} files)`);
23
- await Bun.write(join(stylesOutDir, 'bertui.min.css'), cached.content);
24
- return;
25
- }
26
-
27
- let combinedCSS = '';
28
- let fileCount = 0;
29
-
30
- // 1. Process src/styles/ (plain CSS + SCSS)
31
- if (existsSync(srcStylesDir)) {
32
- await processSCSSDirectory(srcStylesDir, root);
33
- const cssFiles = readdirSync(srcStylesDir).filter(f => f.endsWith('.css') && !f.endsWith('.module.css'));
34
-
35
- logger.info(`Processing ${cssFiles.length} CSS file(s)...`);
36
-
37
- for (const cssFile of cssFiles) {
38
- const srcPath = join(srcStylesDir, cssFile);
39
- const fileBuffer = await globalCache.getFile(srcPath, { logSpeed: true });
40
- if (fileBuffer) {
41
- const content = fileBuffer.toString('utf-8');
42
- combinedCSS += `/* ${cssFile} */\n${content}\n\n`;
43
- fileCount++;
44
- }
45
- }
46
- } else {
47
- logger.info('No styles directory found');
48
- }
49
-
50
- // 2. Include scoped CSS from CSS modules (staged by file-transpiler.js)
51
- if (existsSync(modulesStagingDir)) {
52
- const moduleFiles = readdirSync(modulesStagingDir).filter(f => f.endsWith('.css'));
53
- if (moduleFiles.length > 0) {
54
- logger.info(`Including ${moduleFiles.length} CSS module(s)...`);
55
- for (const cssFile of moduleFiles) {
56
- const srcPath = join(modulesStagingDir, cssFile);
57
- const content = await Bun.file(srcPath).text();
58
- combinedCSS += `/* module: ${cssFile} */\n${content}\n\n`;
59
- fileCount++;
60
- }
61
- }
62
- }
63
-
64
- if (!combinedCSS.trim()) {
65
- await Bun.write(join(stylesOutDir, 'bertui.min.css'), '/* No CSS */');
66
- return;
67
- }
68
-
69
- const combinedPath = join(stylesOutDir, 'bertui.min.css');
70
-
71
- const minifyCacheKey = `minify:${Buffer.from(combinedCSS).length}:${combinedCSS.substring(0, 100)}`;
72
- let minified = globalCache.get(minifyCacheKey);
73
-
74
- if (!minified) {
75
- minified = await minifyCSS(combinedCSS, {
76
- filename: 'bertui.min.css',
77
- sourceMap: false
78
- });
79
- globalCache.set(minifyCacheKey, minified, { ttl: 60000 });
80
- }
81
-
82
- await Bun.write(combinedPath, minified);
83
-
84
- const originalSize = Buffer.byteLength(combinedCSS);
85
- const minifiedSize = Buffer.byteLength(minified);
86
- const reduction = ((1 - minifiedSize / originalSize) * 100).toFixed(1);
87
-
88
- const endTime = process.hrtime.bigint();
89
- const duration = Number(endTime - startTime) / 1000;
90
-
91
- logger.success(`CSS optimized: ${(originalSize/1024).toFixed(2)}KB → ${(minifiedSize/1024).toFixed(2)}KB (-${reduction}%)`);
92
- logger.info(`⚡ Processing time: ${duration.toFixed(3)}µs`);
93
-
94
- globalCache.set(cacheKey, {
95
- files: fileCount,
96
- content: minified,
97
- size: minifiedSize
98
- }, { ttl: 5000 });
99
- }
100
-
101
- async function processSCSSDirectory(stylesDir, root) {
102
- try {
103
- const sass = await import('sass').catch(() => null);
104
- if (!sass) return;
105
-
106
- const files = readdirSync(stylesDir);
107
- const scssFiles = files.filter(f => f.endsWith('.scss') || f.endsWith('.sass'));
108
-
109
- if (scssFiles.length === 0) return;
110
-
111
- logger.info(`📝 Compiling ${scssFiles.length} SCSS files...`);
112
-
113
- for (const file of scssFiles) {
114
- const srcPath = join(stylesDir, file);
115
- const cssPath = join(stylesDir, file.replace(/\.(scss|sass)$/, '.css'));
116
-
117
- const fileBuffer = await globalCache.getFile(srcPath);
118
- const cacheKey = `scss:${file}:${Buffer.from(fileBuffer).length}`;
119
- const cached = globalCache.get(cacheKey);
120
-
121
- if (cached && existsSync(cssPath)) {
122
- logger.debug(`⚡ Cached SCSS: ${file} → ${file.replace(/\.(scss|sass)$/, '.css')}`);
123
- continue;
124
- }
125
-
126
- const result = sass.compile(srcPath, {
127
- style: 'expanded',
128
- sourceMap: false,
129
- loadPaths: [stylesDir, join(root, 'node_modules')]
130
- });
131
-
132
- await Bun.write(cssPath, result.css);
133
- globalCache.set(cacheKey, true, { ttl: 30000 });
134
-
135
- logger.debug(` ${file} → ${file.replace(/\.(scss|sass)$/, '.css')}`);
136
- }
137
-
138
- logger.success(`✅ SCSS compilation complete`);
139
- } catch (error) {
140
- logger.warn(`SCSS processing skipped: ${error.message}`);
141
- }
142
- }
@@ -1,67 +0,0 @@
1
- // bertui/src/build/server-island-validator.js
2
- import logger from '../logger/logger.js'
3
-
4
- const BANNED_HOOKS = [
5
- 'useState', 'useEffect', 'useReducer', 'useCallback', 'useMemo',
6
- 'useRef', 'useContext', 'useLayoutEffect', 'useId',
7
- 'useImperativeHandle', 'useDebugValue', 'useDeferredValue',
8
- 'useTransition', 'useSyncExternalStore',
9
- ]
10
-
11
- const BANNED_EVENTS = [
12
- 'onClick', 'onChange', 'onSubmit', 'onInput', 'onFocus',
13
- 'onBlur', 'onMouseEnter', 'onMouseLeave', 'onKeyDown', 'onKeyUp',
14
- ]
15
-
16
- export function validateServerIsland(sourceCode, filePath) {
17
- const errors = []
18
-
19
- for (const hook of BANNED_HOOKS) {
20
- if (new RegExp(`\\b${hook}\\s*\\(`).test(sourceCode)) {
21
- errors.push(`Cannot use React hook "${hook}" in a static/server page — hooks need a browser runtime`)
22
- }
23
- }
24
-
25
- for (const event of BANNED_EVENTS) {
26
- if (sourceCode.includes(`${event}=`)) {
27
- errors.push(`Cannot use event handler "${event}" in a static/server page — events need a browser runtime`)
28
- }
29
- }
30
-
31
- if (/window\.|document\.|localStorage\.|sessionStorage\./.test(sourceCode)) {
32
- errors.push('Cannot access browser APIs (window/document/localStorage) in a static/server page')
33
- }
34
-
35
- return { valid: errors.length === 0, errors }
36
- }
37
-
38
- export function displayValidationErrors(filePath, errors) {
39
- logger.error(`\n❌ Static/Server page validation failed: ${filePath}`)
40
- for (const err of errors) {
41
- logger.error(` · ${err}`)
42
- }
43
- logger.error(` → Remove the above or switch to default render mode\n`)
44
- }
45
-
46
- export async function validateAllServerIslands(routes) {
47
- const serverIslands = []
48
- const validationResults = []
49
-
50
- for (const route of routes) {
51
- try {
52
- const src = await Bun.file(route.path).text()
53
- const isStatic = /export\s+const\s+render\s*=\s*["'](server|static)["']/.test(src)
54
- if (!isStatic) continue
55
-
56
- const result = validateServerIsland(src, route.path)
57
- serverIslands.push(route)
58
- validationResults.push({ ...result, route: route.route, path: route.path })
59
-
60
- if (!result.valid) {
61
- displayValidationErrors(route.path, result.errors)
62
- }
63
- } catch {}
64
- }
65
-
66
- return { serverIslands, validationResults }
67
- }
@@ -1,64 +0,0 @@
1
- // bertui/src/build/ssr-renderer.js
2
- import { join } from 'path'
3
- import { existsSync, mkdirSync, rmSync } from 'fs'
4
- import logger from '../logger/logger.js'
5
-
6
- /**
7
- * Render a static page to HTML string using renderToString.
8
- * Forces both the page and renderToString to use the same React
9
- * instance from the project's own node_modules.
10
- */
11
- export async function renderPageToHTML(compiledPagePath, buildDir) {
12
- try {
13
- // Extract project root from compiled path
14
- // e.g. /project/.bertuibuild/pages/about.js → /project/
15
- const projectRoot = compiledPagePath.split('.bertuibuild')[0]
16
-
17
- // Explicitly resolve React from the PROJECT's node_modules
18
- // This prevents the two-React-instances problem when bertui is bun linked
19
- const reactPath = join(projectRoot, 'node_modules', 'react', 'index.js')
20
- const reactDomServerPath = join(projectRoot, 'node_modules', 'react-dom', 'server.js')
21
-
22
- if (!existsSync(reactPath)) {
23
- logger.warn(`React not found in project node_modules: ${reactPath}`)
24
- return null
25
- }
26
-
27
- if (!existsSync(reactDomServerPath)) {
28
- logger.warn(`react-dom/server not found in project node_modules: ${reactDomServerPath}`)
29
- return null
30
- }
31
-
32
- const React = await import(reactPath)
33
- const { renderToString } = await import(reactDomServerPath)
34
-
35
- // Import the compiled page
36
- const mod = await import(`${compiledPagePath}?t=${Date.now()}`)
37
- const Component = mod.default
38
-
39
- if (typeof Component !== 'function') {
40
- logger.warn(`No default export found in ${compiledPagePath}`)
41
- return null
42
- }
43
-
44
- return renderToString(React.createElement(Component))
45
-
46
- } catch (err) {
47
- logger.warn(`renderToString failed for ${compiledPagePath}: ${err.message}`)
48
- return null
49
- }
50
- }
51
-
52
- /**
53
- * Check if a route's source file has render = "server" or render = "static"
54
- */
55
- export async function getPageRenderMode(sourcePath) {
56
- try {
57
- const src = await Bun.file(sourcePath).text()
58
- if (/export\s+const\s+render\s*=\s*["']server["']/.test(src)) return 'server'
59
- if (/export\s+const\s+render\s*=\s*["']static["']/.test(src)) return 'static'
60
- return 'default'
61
- } catch {
62
- return 'default'
63
- }
64
- }