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,31 +0,0 @@
1
- // bertui/src/build/compiler/index.js
2
- import { join } from 'path';
3
- import { existsSync } from 'fs';
4
- import logger from '../../logger/logger.js';
5
- import { discoverRoutes } from './route-discoverer.js';
6
- import { compileBuildDirectory } from './file-transpiler.js';
7
- import { generateBuildRouter } from './router-generator.js';
8
-
9
- export async function compileForBuild(root, buildDir, envVars, config = {}) {
10
- const srcDir = join(root, 'src');
11
- const pagesDir = join(srcDir, 'pages');
12
-
13
- if (!existsSync(srcDir)) {
14
- throw new Error('src/ directory not found!');
15
- }
16
-
17
- const importhow = config.importhow || {};
18
- let routes = [];
19
-
20
- if (existsSync(pagesDir)) {
21
- routes = await discoverRoutes(pagesDir);
22
- }
23
-
24
- await compileBuildDirectory(srcDir, buildDir, root, envVars, importhow);
25
-
26
- if (routes.length > 0) {
27
- await generateBuildRouter(routes, buildDir);
28
- }
29
-
30
- return { routes };
31
- }
@@ -1,49 +0,0 @@
1
- // bertui/src/build/compiler/route-discoverer.js
2
- import { join, extname } from 'path';
3
- import { readdirSync, statSync } from 'fs';
4
-
5
- export async function discoverRoutes(pagesDir) {
6
- const routes = [];
7
-
8
- async function scanDirectory(dir, basePath = '') {
9
- const entries = readdirSync(dir, { withFileTypes: true });
10
-
11
- for (const entry of entries) {
12
- const fullPath = join(dir, entry.name);
13
- const relativePath = join(basePath, entry.name);
14
-
15
- if (entry.isDirectory()) {
16
- await scanDirectory(fullPath, relativePath);
17
- } else if (entry.isFile()) {
18
- const ext = extname(entry.name);
19
- if (ext === '.css') continue;
20
-
21
- if (['.jsx', '.tsx', '.js', '.ts'].includes(ext)) {
22
- const fileName = entry.name.replace(ext, '');
23
-
24
- // Only loading is reserved - index is a valid route (becomes /)
25
- if (fileName === 'loading') continue;
26
-
27
- let route = '/' + relativePath.replace(/\\/g, '/').replace(ext, '');
28
- if (fileName === 'index') {
29
- route = route.replace('/index', '') || '/';
30
- }
31
-
32
- const isDynamic = fileName.includes('[') && fileName.includes(']');
33
-
34
- routes.push({
35
- route: route === '' ? '/' : route,
36
- file: relativePath.replace(/\\/g, '/'),
37
- path: fullPath,
38
- type: isDynamic ? 'dynamic' : 'static'
39
- });
40
- }
41
- }
42
- }
43
- }
44
-
45
- await scanDirectory(pagesDir);
46
- routes.sort((a, b) => a.type === b.type ? a.route.localeCompare(b.route) : a.type === 'static' ? -1 : 1);
47
-
48
- return routes;
49
- }
@@ -1,105 +0,0 @@
1
- // bertui/src/build/compiler/router-generator.js
2
- import { join } from 'path';
3
-
4
- export async function generateBuildRouter(routes, buildDir) {
5
- const imports = routes.map((route, i) => {
6
- const componentName = `Page${i}`;
7
- const importPath = `./pages/${route.file.replace(/\.(jsx|tsx|ts)$/, '.js')}`;
8
- return `import ${componentName} from '${importPath}';`;
9
- }).join('\n');
10
-
11
- const routeConfigs = routes.map((route, i) => {
12
- const componentName = `Page${i}`;
13
- return ` { path: '${route.route}', component: ${componentName}, type: '${route.type}' }`;
14
- }).join(',\n');
15
-
16
- const routerCode = `import React, { useState, useEffect, createContext, useContext } from 'react';
17
-
18
- const RouterContext = createContext(null);
19
-
20
- export function useRouter() {
21
- const context = useContext(RouterContext);
22
- if (!context) throw new Error('useRouter must be used within a Router');
23
- return context;
24
- }
25
-
26
- export function Router({ routes }) {
27
- const [currentRoute, setCurrentRoute] = useState(null);
28
- const [params, setParams] = useState({});
29
-
30
- useEffect(() => {
31
- matchAndSetRoute(window.location.pathname);
32
- const handlePopState = () => matchAndSetRoute(window.location.pathname);
33
- window.addEventListener('popstate', handlePopState);
34
- return () => window.removeEventListener('popstate', handlePopState);
35
- }, [routes]);
36
-
37
- function matchAndSetRoute(pathname) {
38
- for (const route of routes) {
39
- if (route.type === 'static' && route.path === pathname) {
40
- setCurrentRoute(route);
41
- setParams({});
42
- return;
43
- }
44
- }
45
- for (const route of routes) {
46
- if (route.type === 'dynamic') {
47
- const pattern = route.path.replace(/\\[([^\\]]+)\\]/g, '([^/]+)');
48
- const regex = new RegExp('^' + pattern + '$');
49
- const match = pathname.match(regex);
50
- if (match) {
51
- const paramNames = [...route.path.matchAll(/\\[([^\\]]+)\\]/g)].map(m => m[1]);
52
- const extractedParams = {};
53
- paramNames.forEach((name, i) => { extractedParams[name] = match[i + 1]; });
54
- setCurrentRoute(route);
55
- setParams(extractedParams);
56
- return;
57
- }
58
- }
59
- }
60
- setCurrentRoute(null);
61
- setParams({});
62
- }
63
-
64
- function navigate(path) {
65
- window.history.pushState({}, '', path);
66
- matchAndSetRoute(path);
67
- }
68
-
69
- const Component = currentRoute?.component;
70
- return React.createElement(
71
- RouterContext.Provider,
72
- { value: { currentRoute, params, navigate, pathname: window.location.pathname } },
73
- Component ? React.createElement(Component, { params }) : React.createElement(NotFound)
74
- );
75
- }
76
-
77
- export function Link({ to, children, ...props }) {
78
- const { navigate } = useRouter();
79
- return React.createElement('a', {
80
- href: to,
81
- onClick: (e) => { e.preventDefault(); navigate(to); },
82
- ...props
83
- }, children);
84
- }
85
-
86
- function NotFound() {
87
- return React.createElement('div', {
88
- style: { display: 'flex', flexDirection: 'column', alignItems: 'center',
89
- justifyContent: 'center', minHeight: '100vh', fontFamily: 'system-ui' }
90
- },
91
- React.createElement('h1', { style: { fontSize: '6rem', margin: 0 } }, '404'),
92
- React.createElement('p', { style: { fontSize: '1.5rem', color: '#666' } }, 'Page not found'),
93
- React.createElement('a', { href: '/', style: { color: '#10b981', textDecoration: 'none' } }, 'Go home')
94
- );
95
- }
96
-
97
- ${imports}
98
-
99
- export const routes = [
100
- ${routeConfigs}
101
- ];
102
- `;
103
-
104
- await Bun.write(join(buildDir, 'router.js'), routerCode);
105
- }
@@ -1,81 +0,0 @@
1
- import { join } from 'path';
2
- import { existsSync, mkdirSync } from 'fs';
3
- import { transform } from 'lightningcss';
4
- import logger from '../logger/logger.js';
5
-
6
- /**
7
- * Build and minify CSS for production using Lightning CSS
8
- * @param {string} srcPath - Source CSS file path
9
- * @param {string} destPath - Destination CSS file path
10
- */
11
- export async function buildCSS(srcPath, destPath) {
12
- try {
13
- logger.info(`Processing CSS: ${srcPath.split('/').pop()}`);
14
-
15
- // Ensure destination directory exists
16
- const destDir = join(destPath, '..');
17
- if (!existsSync(destDir)) {
18
- mkdirSync(destDir, { recursive: true });
19
- }
20
-
21
- // Read source CSS
22
- const css = await Bun.file(srcPath).text();
23
- const originalSize = Buffer.byteLength(css);
24
-
25
- // Transform with Lightning CSS (blazing fast)
26
- const { code } = transform({
27
- filename: srcPath,
28
- code: Buffer.from(css),
29
- minify: true,
30
- sourceMap: false,
31
- targets: {
32
- // Support last 2 versions of major browsers
33
- chrome: 90 << 16,
34
- firefox: 88 << 16,
35
- safari: 14 << 16,
36
- edge: 90 << 16
37
- },
38
- drafts: {
39
- nesting: true // Enable CSS nesting
40
- }
41
- });
42
-
43
- // Write minified CSS
44
- await Bun.write(destPath, code);
45
-
46
- // Calculate size reduction
47
- const minifiedSize = code.length;
48
- const originalKB = (originalSize / 1024).toFixed(2);
49
- const minifiedKB = (minifiedSize / 1024).toFixed(2);
50
- const reduction = ((1 - minifiedSize / originalSize) * 100).toFixed(1);
51
-
52
- logger.success(`CSS minified: ${originalKB}KB β†’ ${minifiedKB}KB (-${reduction}%)`);
53
-
54
- return { success: true, size: minifiedKB };
55
- } catch (error) {
56
- logger.error(`CSS build failed: ${error.message}`);
57
- throw error;
58
- }
59
- }
60
-
61
- /**
62
- * Copy CSS without minification (for dev)
63
- * @param {string} srcPath - Source CSS file path
64
- * @param {string} destPath - Destination CSS file path
65
- */
66
- export async function copyCSS(srcPath, destPath) {
67
- try {
68
- const destDir = join(destPath, '..');
69
- if (!existsSync(destDir)) {
70
- mkdirSync(destDir, { recursive: true });
71
- }
72
-
73
- await Bun.write(destPath, Bun.file(srcPath));
74
- logger.info('CSS copied for development');
75
-
76
- return { success: true };
77
- } catch (error) {
78
- logger.error(`CSS copy failed: ${error.message}`);
79
- throw error;
80
- }
81
- }
@@ -1,263 +0,0 @@
1
- // bertui/src/build/generators/html-generator.js
2
- import { join, relative } from 'path'
3
- import { mkdirSync, existsSync, cpSync } from 'fs'
4
- import logger from '../../logger/logger.js'
5
- import { extractMetaFromSource } from '../../utils/meta-extractor.js'
6
- import { renderPageToHTML, getPageRenderMode } from '../ssr-renderer.js'
7
-
8
- export async function generateProductionHTML(root, outDir, buildResult, routes, config, buildDir) {
9
- const mainBundle = buildResult.outputs.find(o =>
10
- o.path.includes('main') && o.kind === 'entry-point'
11
- )
12
-
13
- if (!mainBundle) {
14
- logger.error('Could not find main bundle')
15
- return
16
- }
17
-
18
- const bundlePath = relative(outDir, mainBundle.path).replace(/\\/g, '/')
19
- const defaultMeta = config.meta || {}
20
- const bertuiPackages = await copyBertuiPackagesToProduction(root, outDir)
21
-
22
-
23
- logger.info(`Generating HTML for ${routes.length} routes...`)
24
-
25
- for (const route of routes) {
26
- await processSingleRoute(route, config, defaultMeta, bundlePath, outDir, bertuiPackages, buildDir)
27
- }
28
-
29
- logger.success(`HTML generation complete for ${routes.length} routes`)
30
- }
31
-
32
- async function processSingleRoute(route, config, defaultMeta, bundlePath, outDir, bertuiPackages, buildDir) {
33
- try {
34
- const sourceCode = await Bun.file(route.path).text()
35
- const pageMeta = extractMetaFromSource(sourceCode)
36
- const meta = { ...defaultMeta, ...pageMeta }
37
-
38
- // Determine render mode from source
39
- const renderMode = await getPageRenderMode(route.path)
40
-
41
- let html
42
-
43
- if (renderMode === 'server' || renderMode === 'static') {
44
- // Find the compiled version of this page in buildDir
45
- const compiledPath = findCompiledPath(route, buildDir)
46
-
47
- if (compiledPath && existsSync(compiledPath)) {
48
- logger.info(` SSR rendering: ${route.route}`)
49
- const ssrHTML = await renderPageToHTML(compiledPath, buildDir)
50
-
51
- if (ssrHTML) {
52
- if (renderMode === 'static') {
53
- // Pure static β€” no JS at all
54
- html = generateStaticHTML({ ssrHTML, meta, bertuiPackages })
55
- } else {
56
- // Server island β€” SSR HTML + JS bundle for hydration
57
- html = generateServerIslandHTML({ ssrHTML, meta, bundlePath, bertuiPackages })
58
- }
59
- logger.success(` βœ“ SSR: ${route.route} (${renderMode})`)
60
- } else {
61
- // SSR failed β€” fall back to client render with a warning
62
- logger.warn(` SSR failed for ${route.route}, falling back to client render`)
63
- html = generateClientHTML({ meta, bundlePath, bertuiPackages })
64
- }
65
- } else {
66
- logger.warn(` Compiled path not found for ${route.route}, using client render`)
67
- html = generateClientHTML({ meta, bundlePath, bertuiPackages })
68
- }
69
- } else {
70
- // Default: client-only SPA
71
- html = generateClientHTML({ meta, bundlePath, bertuiPackages })
72
- }
73
-
74
- // Write to dist/
75
- let htmlPath
76
- if (route.route === '/') {
77
- htmlPath = join(outDir, 'index.html')
78
- } else {
79
- const routeDir = join(outDir, route.route.replace(/^\//, ''))
80
- mkdirSync(routeDir, { recursive: true })
81
- htmlPath = join(routeDir, 'index.html')
82
- }
83
-
84
- await Bun.write(htmlPath, html)
85
- logger.success(` ${route.route}`)
86
-
87
- } catch (error) {
88
- logger.error(`Failed HTML for ${route.route}: ${error.message}`)
89
- }
90
- }
91
-
92
- /**
93
- * Find the compiled .js path for a route's source file
94
- */
95
- function findCompiledPath(route, buildDir) {
96
- const compiledFile = route.file.replace(/\.(jsx|tsx|ts)$/, '.js')
97
- return join(buildDir, 'pages', compiledFile)
98
- }
99
- // ─── HTML generators ──────────────────────────────────────────────────────────
100
-
101
- /**
102
- * render = "static" β†’ pure HTML, zero JS
103
- */
104
- function generateStaticHTML({ ssrHTML, meta, bertuiPackages }) {
105
- const bertuiAnimateCSS = bertuiPackages.bertuiAnimate
106
- ? '<link rel="stylesheet" href="/css/bertui-animate.min.css">'
107
- : ''
108
-
109
- return `<!DOCTYPE html>
110
- <html lang="${meta.lang || 'en'}">
111
- <head>
112
- <meta charset="UTF-8">
113
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
114
- <title>${meta.title || 'BertUI App'}</title>
115
- <meta name="description" content="${meta.description || ''}">
116
- ${meta.keywords ? `<meta name="keywords" content="${meta.keywords}">` : ''}
117
- ${meta.author ? `<meta name="author" content="${meta.author}">` : ''}
118
- ${meta.themeColor ? `<meta name="theme-color" content="${meta.themeColor}">` : ''}
119
- <meta property="og:title" content="${meta.ogTitle || meta.title || 'BertUI App'}">
120
- <meta property="og:description" content="${meta.ogDescription || meta.description || ''}">
121
- ${meta.ogImage ? `<meta property="og:image" content="${meta.ogImage}">` : ''}
122
- <link rel="stylesheet" href="/styles/bertui.min.css">
123
- ${bertuiAnimateCSS}
124
- <link rel="icon" type="image/svg+xml" href="/favicon.svg">
125
- </head>
126
- <body>
127
- ${ssrHTML}
128
- </body>
129
- </html>`
130
- }
131
-
132
- /**
133
- * render = "server" β†’ SSR HTML + JS bundle for hydration
134
- */
135
- function generateServerIslandHTML({ ssrHTML, meta, bundlePath, bertuiPackages }) {
136
- const { importMapScript, bertuiAnimateCSS } = buildSharedAssets(meta, bertuiPackages)
137
-
138
- return `<!DOCTYPE html>
139
- <html lang="${meta.lang || 'en'}">
140
- <head>
141
- <meta charset="UTF-8">
142
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
143
- <title>${meta.title || 'BertUI App'}</title>
144
- <meta name="description" content="${meta.description || ''}">
145
- ${meta.keywords ? `<meta name="keywords" content="${meta.keywords}">` : ''}
146
- ${meta.author ? `<meta name="author" content="${meta.author}">` : ''}
147
- ${meta.themeColor ? `<meta name="theme-color" content="${meta.themeColor}">` : ''}
148
- <meta property="og:title" content="${meta.ogTitle || meta.title || 'BertUI App'}">
149
- <meta property="og:description" content="${meta.ogDescription || meta.description || ''}">
150
- ${meta.ogImage ? `<meta property="og:image" content="${meta.ogImage}">` : ''}
151
- <link rel="stylesheet" href="/styles/bertui.min.css">
152
- ${bertuiAnimateCSS}
153
- <link rel="icon" type="image/svg+xml" href="/favicon.svg">
154
- ${importMapScript}
155
- </head>
156
- <body>
157
- <div id="root">${ssrHTML}</div>
158
- <script type="module" src="/${bundlePath}"></script>
159
- </body>
160
- </html>`
161
- }
162
-
163
- /**
164
- * default β†’ client-only SPA (existing behavior)
165
- */
166
- function generateClientHTML({ meta, bundlePath, bertuiPackages }) {
167
- const { importMapScript, bertuiAnimateCSS } = buildSharedAssets(meta, bertuiPackages)
168
-
169
- return `<!DOCTYPE html>
170
- <html lang="${meta.lang || 'en'}">
171
- <head>
172
- <meta charset="UTF-8">
173
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
174
- <title>${meta.title || 'BertUI App'}</title>
175
- <meta name="description" content="${meta.description || ''}">
176
- ${meta.keywords ? `<meta name="keywords" content="${meta.keywords}">` : ''}
177
- ${meta.author ? `<meta name="author" content="${meta.author}">` : ''}
178
- ${meta.themeColor ? `<meta name="theme-color" content="${meta.themeColor}">` : ''}
179
- <meta property="og:title" content="${meta.ogTitle || meta.title || 'BertUI App'}">
180
- <meta property="og:description" content="${meta.ogDescription || meta.description || ''}">
181
- ${meta.ogImage ? `<meta property="og:image" content="${meta.ogImage}">` : ''}
182
- <link rel="stylesheet" href="/styles/bertui.min.css">
183
- ${bertuiAnimateCSS}
184
- <link rel="icon" type="image/svg+xml" href="/favicon.svg">
185
- ${importMapScript}
186
- </head>
187
- <body>
188
- <div id="root"></div>
189
- <script type="module" src="/${bundlePath}"></script>
190
- </body>
191
- </html>`
192
- }
193
-
194
- // ─── Shared helpers ───────────────────────────────────────────────────────────
195
-
196
- function buildSharedAssets(meta, bertuiPackages) {
197
- const bertuiIconsImport = bertuiPackages.bertuiIcons
198
- ? ',\n "bertui-icons": "/node_modules/bertui-icons/generated/index.js"'
199
- : ''
200
- const elysiaEdenImport = bertuiPackages.elysiaEden
201
- ? ',\n "@elysiajs/eden": "/node_modules/@elysiajs/eden/dist/index.mjs"'
202
- : ''
203
- const bertuiAnimateCSS = bertuiPackages.bertuiAnimate
204
- ? '<link rel="stylesheet" href="/css/bertui-animate.min.css">'
205
- : ''
206
-
207
- const importMapScript = `<script type="importmap">
208
- {
209
- "imports": {
210
- "react": "https://esm.sh/react@18.2.0",
211
- "react-dom": "https://esm.sh/react-dom@18.2.0",
212
- "react-dom/client": "https://esm.sh/react-dom@18.2.0/client",
213
- "react/jsx-runtime": "https://esm.sh/react@18.2.0/jsx-runtime",
214
- "react/jsx-dev-runtime": "https://esm.sh/react@18.2.0/jsx-dev-runtime",
215
- "@bunnyx/api": "/bunnyx-api/api-client.js"${bertuiIconsImport}${elysiaEdenImport}
216
- }
217
- }
218
- </script>`
219
-
220
- return { importMapScript, bertuiAnimateCSS }
221
- }
222
-
223
- async function copyBertuiPackagesToProduction(root, outDir) {
224
- const nodeModulesDir = join(root, 'node_modules')
225
- const packages = { bertuiIcons: false, bertuiAnimate: false, elysiaEden: false }
226
-
227
- if (!existsSync(nodeModulesDir)) return packages
228
-
229
- const bertuiIconsSrc = join(nodeModulesDir, 'bertui-icons')
230
- if (existsSync(bertuiIconsSrc)) {
231
- try {
232
- const dest = join(outDir, 'node_modules', 'bertui-icons')
233
- mkdirSync(join(outDir, 'node_modules'), { recursive: true })
234
- cpSync(bertuiIconsSrc, dest, { recursive: true })
235
- packages.bertuiIcons = true
236
- } catch {}
237
- }
238
-
239
- const bertuiAnimateSrc = join(nodeModulesDir, 'bertui-animate', 'dist')
240
- if (existsSync(bertuiAnimateSrc)) {
241
- try {
242
- const dest = join(outDir, 'css')
243
- mkdirSync(dest, { recursive: true })
244
- const minCSS = join(bertuiAnimateSrc, 'bertui-animate.min.css')
245
- if (existsSync(minCSS)) {
246
- cpSync(minCSS, join(dest, 'bertui-animate.min.css'))
247
- packages.bertuiAnimate = true
248
- }
249
- } catch {}
250
- }
251
-
252
- const elysiaEdenSrc = join(nodeModulesDir, '@elysiajs', 'eden')
253
- if (existsSync(elysiaEdenSrc)) {
254
- try {
255
- const dest = join(outDir, 'node_modules', '@elysiajs', 'eden')
256
- mkdirSync(join(outDir, 'node_modules', '@elysiajs'), { recursive: true })
257
- cpSync(elysiaEdenSrc, dest, { recursive: true })
258
- packages.elysiaEden = true
259
- } catch {}
260
- }
261
-
262
- return packages
263
- }
@@ -1,58 +0,0 @@
1
- // bertui/src/build/robots-generator.js
2
- import { join } from 'path';
3
- import logger from '../../logger/logger.js';
4
-
5
- /**
6
- * Generate robots.txt from sitemap data
7
- * @param {Object} config - BertUI config with baseUrl
8
- * @param {string} outDir - Output directory (dist/)
9
- * @param {Array} routes - Optional: routes to disallow (e.g., admin pages)
10
- */
11
- export async function generateRobots(config, outDir, routes = []) {
12
- logger.info('πŸ€– Generating robots.txt...');
13
-
14
- // βœ… FIX: Check if baseUrl exists, then remove trailing slash
15
- if (!config?.baseUrl) {
16
- logger.error('❌ baseUrl is required in bertui.config.js for robots.txt generation!');
17
- logger.error(' Add: baseUrl: "https://your-domain.com" to your config');
18
- throw new Error('Missing baseUrl in config - robots.txt generation failed');
19
- }
20
-
21
- const baseUrl = config.baseUrl.replace(/\/$/, ''); // Remove trailing slash
22
- const sitemapUrl = `${baseUrl}/sitemap.xml`;
23
-
24
- logger.info(` Sitemap URL: ${sitemapUrl}`);
25
-
26
- // Default robots.txt - Allow all
27
- let robotsTxt = `# BertUI Generated robots.txt
28
- User-agent: *
29
- Allow: /
30
-
31
- # Sitemap
32
- Sitemap: ${sitemapUrl}
33
- `;
34
-
35
- // Add custom disallow rules if specified in config
36
- if (config?.robots?.disallow && Array.isArray(config.robots.disallow) && config.robots.disallow.length > 0) {
37
- robotsTxt += '\n# Custom Disallow Rules\n';
38
- config.robots.disallow.forEach(path => {
39
- robotsTxt += `Disallow: ${path}\n`;
40
- });
41
- logger.info(` Blocked ${config.robots.disallow.length} path(s)`);
42
- }
43
-
44
- // Add crawl delay if specified
45
- if (config?.robots?.crawlDelay && typeof config.robots.crawlDelay === 'number') {
46
- robotsTxt += `\nCrawl-delay: ${config.robots.crawlDelay}\n`;
47
- logger.info(` Crawl delay: ${config.robots.crawlDelay}s`);
48
- }
49
-
50
- // Write to dist/robots.txt
51
- const robotsPath = join(outDir, 'robots.txt');
52
- await Bun.write(robotsPath, robotsTxt);
53
-
54
- logger.success('βœ… robots.txt generated');
55
- logger.info(` Location: ${robotsPath}`);
56
-
57
- return { path: robotsPath, content: robotsTxt };
58
- }
@@ -1,63 +0,0 @@
1
- // bertui/src/build/sitemap-generator.js - SIMPLIFIED
2
- import { join } from 'path';
3
- import logger from '../../logger/logger.js';
4
-
5
- function calculatePriority(route) {
6
- if (route === '/') return 1.0;
7
- if (route.includes(':')) return 0.6;
8
- const depth = route.split('/').filter(Boolean).length;
9
- if (depth === 1) return 0.8;
10
- if (depth === 2) return 0.7;
11
- return 0.6;
12
- }
13
-
14
- function generateSitemapXML(routes, baseUrl) {
15
- const urls = routes.map(route => {
16
- const url = `${baseUrl}${route.route}`;
17
- return ` <url>
18
- <loc>${url}</loc>
19
- <lastmod>${route.lastmod}</lastmod>
20
- <changefreq>weekly</changefreq>
21
- <priority>${route.priority}</priority>
22
- </url>`;
23
- }).join('\n');
24
-
25
- return `<?xml version="1.0" encoding="UTF-8"?>
26
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
27
- ${urls}
28
- </urlset>`;
29
- }
30
-
31
- export async function generateSitemap(routes, config, outDir) {
32
- logger.info('πŸ—ΊοΈ Generating sitemap.xml...');
33
-
34
- if (!config?.baseUrl) {
35
- logger.error('❌ baseUrl is required in bertui.config.js for sitemap generation!');
36
- logger.error(' Add: baseUrl: "https://your-domain.com" to your config');
37
- throw new Error('Missing baseUrl in config - sitemap generation failed');
38
- }
39
-
40
- const baseUrl = config.baseUrl.replace(/\/$/, '');
41
- const currentDate = new Date().toISOString().split('T')[0];
42
-
43
- logger.info(` Base URL: ${baseUrl}`);
44
-
45
- const staticRoutes = routes.filter(r => r.type === 'static');
46
- logger.info(` ${staticRoutes.length} static routes will be included in sitemap`);
47
-
48
- // SIMPLE: No file reading, just route processing
49
- const sitemapRoutes = staticRoutes.map(route => ({
50
- route: route.route,
51
- lastmod: currentDate,
52
- priority: calculatePriority(route.route)
53
- }));
54
-
55
- const xml = generateSitemapXML(sitemapRoutes, baseUrl);
56
- const sitemapPath = join(outDir, 'sitemap.xml');
57
- await Bun.write(sitemapPath, xml);
58
-
59
- logger.success(`βœ… Sitemap generated: ${sitemapRoutes.length} URLs`);
60
- logger.info(` Location: ${sitemapPath}`);
61
-
62
- return { routes: sitemapRoutes, path: sitemapPath };
63
- }