bertui 1.1.5 → 1.1.6
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/package.json +1 -1
- package/src/build.js +3 -10
- package/src/client/compiler.js +20 -27
- package/src/config/defaultConfig.js +4 -12
- package/src/dev.js +4 -1
- package/types/config.d.ts +1 -48
- package/src/pagebuilder/core.js +0 -191
package/package.json
CHANGED
package/src/build.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
// bertui/src/build.js -
|
|
1
|
+
// bertui/src/build.js - CLEANED (No PageBuilder)
|
|
2
2
|
import { join } from 'path';
|
|
3
|
-
import { existsSync, mkdirSync, rmSync
|
|
3
|
+
import { existsSync, mkdirSync, rmSync } from 'fs';
|
|
4
4
|
import logger from './logger/logger.js';
|
|
5
5
|
import { loadEnvVariables } from './utils/env.js';
|
|
6
|
-
import { runPageBuilder } from './pagebuilder/core.js';
|
|
7
6
|
|
|
8
7
|
import { compileForBuild } from './build/compiler/index.js';
|
|
9
8
|
import { buildAllCSS } from './build/processors/css-builder.js';
|
|
@@ -37,11 +36,6 @@ export async function buildProduction(options = {}) {
|
|
|
37
36
|
const { loadConfig } = await import('./config/loadConfig.js');
|
|
38
37
|
const config = await loadConfig(root);
|
|
39
38
|
|
|
40
|
-
if (config.pageBuilder) {
|
|
41
|
-
logger.info('Step 0.5: Running Page Builder...');
|
|
42
|
-
await runPageBuilder(root, config);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
39
|
logger.info('Step 1: Compiling and detecting Server Islands...');
|
|
46
40
|
const { routes, serverIslands, clientRoutes } = await compileForBuild(root, buildDir, envVars);
|
|
47
41
|
|
|
@@ -94,7 +88,6 @@ export async function buildProduction(options = {}) {
|
|
|
94
88
|
|
|
95
89
|
async function bundleJavaScript(buildEntry, outDir, envVars, buildDir) {
|
|
96
90
|
try {
|
|
97
|
-
// Change to build directory where bunfig.toml is
|
|
98
91
|
const originalCwd = process.cwd();
|
|
99
92
|
process.chdir(buildDir);
|
|
100
93
|
|
|
@@ -172,4 +165,4 @@ function showBuildSummary(routes, serverIslands, clientRoutes, duration) {
|
|
|
172
165
|
}
|
|
173
166
|
|
|
174
167
|
logger.bigLog('READY TO DEPLOY 🚀', { color: 'green' });
|
|
175
|
-
}
|
|
168
|
+
}
|
package/src/client/compiler.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
//
|
|
1
|
+
// ============================================
|
|
2
|
+
// FILE: bertui/src/client/compiler.js (UPDATED - Skip templates/)
|
|
3
|
+
// ============================================
|
|
4
|
+
|
|
2
5
|
import { existsSync, mkdirSync, readdirSync, statSync } from 'fs';
|
|
3
6
|
import { join, extname, relative, dirname } from 'path';
|
|
4
7
|
import logger from '../logger/logger.js';
|
|
@@ -127,9 +130,7 @@ const RouterContext = createContext(null);
|
|
|
127
130
|
|
|
128
131
|
export function useRouter() {
|
|
129
132
|
const context = useContext(RouterContext);
|
|
130
|
-
if (!context)
|
|
131
|
-
throw new Error('useRouter must be used within a Router component');
|
|
132
|
-
}
|
|
133
|
+
if (!context) throw new Error('useRouter must be used within a Router');
|
|
133
134
|
return context;
|
|
134
135
|
}
|
|
135
136
|
|
|
@@ -194,24 +195,13 @@ export function Link({ to, children, ...props }) {
|
|
|
194
195
|
}
|
|
195
196
|
|
|
196
197
|
function NotFound() {
|
|
197
|
-
return React.createElement(
|
|
198
|
-
'
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
display: 'flex',
|
|
202
|
-
flexDirection: 'column',
|
|
203
|
-
alignItems: 'center',
|
|
204
|
-
justifyContent: 'center',
|
|
205
|
-
minHeight: '100vh',
|
|
206
|
-
fontFamily: 'system-ui'
|
|
207
|
-
}
|
|
208
|
-
},
|
|
198
|
+
return React.createElement('div', {
|
|
199
|
+
style: { display: 'flex', flexDirection: 'column', alignItems: 'center',
|
|
200
|
+
justifyContent: 'center', minHeight: '100vh', fontFamily: 'system-ui' }
|
|
201
|
+
},
|
|
209
202
|
React.createElement('h1', { style: { fontSize: '6rem', margin: 0 } }, '404'),
|
|
210
203
|
React.createElement('p', { style: { fontSize: '1.5rem', color: '#666' } }, 'Page not found'),
|
|
211
|
-
React.createElement('a', {
|
|
212
|
-
href: '/',
|
|
213
|
-
style: { color: '#10b981', textDecoration: 'none', fontSize: '1.2rem' }
|
|
214
|
-
}, 'Go home')
|
|
204
|
+
React.createElement('a', { href: '/', style: { color: '#10b981', textDecoration: 'none' } }, 'Go home')
|
|
215
205
|
);
|
|
216
206
|
}
|
|
217
207
|
|
|
@@ -219,11 +209,9 @@ ${imports}
|
|
|
219
209
|
|
|
220
210
|
export const routes = [
|
|
221
211
|
${routeConfigs}
|
|
222
|
-
]
|
|
223
|
-
`;
|
|
212
|
+
];`;
|
|
224
213
|
|
|
225
|
-
|
|
226
|
-
await Bun.write(routerPath, routerComponentCode);
|
|
214
|
+
await Bun.write(join(outDir, 'router.js'), routerComponentCode);
|
|
227
215
|
}
|
|
228
216
|
|
|
229
217
|
async function compileDirectory(srcDir, outDir, root, envVars) {
|
|
@@ -235,6 +223,12 @@ async function compileDirectory(srcDir, outDir, root, envVars) {
|
|
|
235
223
|
const stat = statSync(srcPath);
|
|
236
224
|
|
|
237
225
|
if (stat.isDirectory()) {
|
|
226
|
+
// ✅ NEW: Skip templates directory
|
|
227
|
+
if (file === 'templates') {
|
|
228
|
+
logger.debug('⏭️ Skipping src/templates/ (PageBuilder templates only)');
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
|
|
238
232
|
const subOutDir = join(outDir, file);
|
|
239
233
|
mkdirSync(subOutDir, { recursive: true });
|
|
240
234
|
const subStats = await compileDirectory(srcPath, subOutDir, root, envVars);
|
|
@@ -295,12 +289,11 @@ async function compileFile(srcPath, outDir, filename, relativePath, root, envVar
|
|
|
295
289
|
const outPath = join(outDir, filename.replace(/\.(jsx|tsx|ts)$/, '.js'));
|
|
296
290
|
code = fixRouterImports(code, outPath, root);
|
|
297
291
|
|
|
298
|
-
// ✅ CRITICAL FIX: Force React.createElement instead of jsxDEV
|
|
299
292
|
const transpiler = new Bun.Transpiler({
|
|
300
293
|
loader,
|
|
301
294
|
tsconfig: {
|
|
302
295
|
compilerOptions: {
|
|
303
|
-
jsx: 'react',
|
|
296
|
+
jsx: 'react',
|
|
304
297
|
jsxFactory: 'React.createElement',
|
|
305
298
|
jsxFragmentFactory: 'React.Fragment'
|
|
306
299
|
}
|
|
@@ -369,4 +362,4 @@ function fixRelativeImports(code) {
|
|
|
369
362
|
});
|
|
370
363
|
|
|
371
364
|
return code;
|
|
372
|
-
}
|
|
365
|
+
}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
// bertui/src/config/defaultConfig.js
|
|
2
|
-
// Default configuration used when bertui.config.js is not present
|
|
3
|
-
|
|
1
|
+
// bertui/src/config/defaultConfig.js - CLEANED
|
|
4
2
|
export const defaultConfig = {
|
|
5
|
-
// Site information (used for sitemap generation)
|
|
6
3
|
siteName: "BertUI App",
|
|
7
|
-
baseUrl: "http://localhost:3000",
|
|
4
|
+
baseUrl: "http://localhost:3000",
|
|
8
5
|
|
|
9
|
-
// HTML Meta Tags (SEO)
|
|
10
6
|
meta: {
|
|
11
7
|
title: "BertUI - Lightning Fast React",
|
|
12
8
|
description: "Build lightning-fast React applications with file-based routing powered by Bun",
|
|
@@ -14,23 +10,19 @@ export const defaultConfig = {
|
|
|
14
10
|
author: "Pease Ernest",
|
|
15
11
|
themeColor: "#667eea",
|
|
16
12
|
lang: "en",
|
|
17
|
-
|
|
18
|
-
// Open Graph for social sharing
|
|
19
13
|
ogTitle: "BertUI - Lightning Fast React Framework",
|
|
20
14
|
ogDescription: "Build lightning-fast React apps with zero config",
|
|
21
15
|
ogImage: "/og-image.png"
|
|
22
16
|
},
|
|
23
17
|
|
|
24
|
-
// App Shell Configuration
|
|
25
18
|
appShell: {
|
|
26
19
|
loading: true,
|
|
27
20
|
loadingText: "Loading...",
|
|
28
21
|
backgroundColor: "#ffffff"
|
|
29
22
|
},
|
|
30
23
|
|
|
31
|
-
// robots.txt Configuration
|
|
32
24
|
robots: {
|
|
33
|
-
disallow: [],
|
|
34
|
-
crawlDelay: null
|
|
25
|
+
disallow: [],
|
|
26
|
+
crawlDelay: null
|
|
35
27
|
}
|
|
36
28
|
};
|
package/src/dev.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
// src/dev.js
|
|
1
|
+
// bertui/src/dev.js - CLEANED (No PageBuilder)
|
|
2
2
|
import { compileProject } from './client/compiler.js';
|
|
3
3
|
import { startDevServer } from './server/dev-server.js';
|
|
4
4
|
import logger from './logger/logger.js';
|
|
5
|
+
import { loadConfig } from './config/loadConfig.js';
|
|
5
6
|
|
|
6
7
|
export async function startDev(options = {}) {
|
|
7
8
|
const root = options.root || process.cwd();
|
|
8
9
|
const port = options.port || 3000;
|
|
9
10
|
|
|
10
11
|
try {
|
|
12
|
+
const config = await loadConfig(root);
|
|
13
|
+
|
|
11
14
|
// Step 1: Compile project
|
|
12
15
|
logger.info('Step 1: Compiling project...');
|
|
13
16
|
await compileProject(root);
|
package/types/config.d.ts
CHANGED
|
@@ -1,80 +1,33 @@
|
|
|
1
|
-
// bertui/types/config.d.ts
|
|
1
|
+
// bertui/types/config.d.ts - CLEANED
|
|
2
2
|
declare module 'bertui/config' {
|
|
3
|
-
/**
|
|
4
|
-
* BertUI Configuration
|
|
5
|
-
*/
|
|
6
3
|
export interface BertuiConfig {
|
|
7
|
-
/** Site name for SEO */
|
|
8
4
|
siteName?: string;
|
|
9
|
-
|
|
10
|
-
/** Base URL for sitemap generation (e.g., "https://example.com") */
|
|
11
5
|
baseUrl?: string;
|
|
12
6
|
|
|
13
|
-
/** HTML meta tags configuration */
|
|
14
7
|
meta?: {
|
|
15
|
-
/** Page title */
|
|
16
8
|
title?: string;
|
|
17
|
-
/** Meta description */
|
|
18
9
|
description?: string;
|
|
19
|
-
/** Meta keywords */
|
|
20
10
|
keywords?: string;
|
|
21
|
-
/** Author name */
|
|
22
11
|
author?: string;
|
|
23
|
-
/** Open Graph image URL */
|
|
24
12
|
ogImage?: string;
|
|
25
|
-
/** Open Graph title */
|
|
26
13
|
ogTitle?: string;
|
|
27
|
-
/** Open Graph description */
|
|
28
14
|
ogDescription?: string;
|
|
29
|
-
/** Theme color */
|
|
30
15
|
themeColor?: string;
|
|
31
|
-
/** Language code (e.g., "en") */
|
|
32
16
|
lang?: string;
|
|
33
17
|
};
|
|
34
18
|
|
|
35
|
-
/** App shell configuration */
|
|
36
19
|
appShell?: {
|
|
37
|
-
/** Show loading indicator */
|
|
38
20
|
loading?: boolean;
|
|
39
|
-
/** Loading text */
|
|
40
21
|
loadingText?: string;
|
|
41
|
-
/** Background color */
|
|
42
22
|
backgroundColor?: string;
|
|
43
23
|
};
|
|
44
24
|
|
|
45
|
-
/** robots.txt configuration */
|
|
46
25
|
robots?: {
|
|
47
|
-
/** Paths to disallow in robots.txt */
|
|
48
26
|
disallow?: string[];
|
|
49
|
-
/** Crawl delay in seconds */
|
|
50
27
|
crawlDelay?: number;
|
|
51
28
|
};
|
|
52
29
|
}
|
|
53
30
|
|
|
54
|
-
/**
|
|
55
|
-
* Page meta configuration (exported from page files)
|
|
56
|
-
*/
|
|
57
|
-
export interface PageMeta {
|
|
58
|
-
title?: string;
|
|
59
|
-
description?: string;
|
|
60
|
-
keywords?: string;
|
|
61
|
-
author?: string;
|
|
62
|
-
ogTitle?: string;
|
|
63
|
-
ogDescription?: string;
|
|
64
|
-
ogImage?: string;
|
|
65
|
-
themeColor?: string;
|
|
66
|
-
lang?: string;
|
|
67
|
-
publishedDate?: string;
|
|
68
|
-
updatedDate?: string;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Default BertUI configuration
|
|
73
|
-
*/
|
|
74
31
|
export const defaultConfig: BertuiConfig;
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Load BertUI configuration from bertui.config.js
|
|
78
|
-
*/
|
|
79
32
|
export function loadConfig(root: string): Promise<BertuiConfig>;
|
|
80
33
|
}
|
package/src/pagebuilder/core.js
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
// bertui/src/pagebuilder/core.js
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { existsSync, mkdirSync } from 'fs';
|
|
4
|
-
import logger from '../logger/logger.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Run page builder to generate pages from config
|
|
8
|
-
* @param {string} root - Project root directory
|
|
9
|
-
* @param {Object} config - BertUI configuration
|
|
10
|
-
*/
|
|
11
|
-
export async function runPageBuilder(root, config) {
|
|
12
|
-
const pagesDir = join(root, 'src', 'pages');
|
|
13
|
-
|
|
14
|
-
if (!config.pageBuilder || typeof config.pageBuilder !== 'object') {
|
|
15
|
-
logger.debug('No page builder configuration found');
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const { pages } = config.pageBuilder;
|
|
20
|
-
|
|
21
|
-
if (!pages || !Array.isArray(pages) || pages.length === 0) {
|
|
22
|
-
logger.debug('No pages defined in page builder');
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
logger.info(`📄 Page Builder: Generating ${pages.length} page(s)...`);
|
|
27
|
-
|
|
28
|
-
// Ensure pages directory exists
|
|
29
|
-
const generatedDir = join(pagesDir, 'generated');
|
|
30
|
-
if (!existsSync(generatedDir)) {
|
|
31
|
-
mkdirSync(generatedDir, { recursive: true });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
for (const page of pages) {
|
|
35
|
-
try {
|
|
36
|
-
await generatePage(page, generatedDir);
|
|
37
|
-
logger.success(`✅ Generated: ${page.name}`);
|
|
38
|
-
} catch (error) {
|
|
39
|
-
logger.error(`❌ Failed to generate ${page.name}: ${error.message}`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Generate a single page from configuration
|
|
46
|
-
* @param {Object} pageConfig - Page configuration
|
|
47
|
-
* @param {string} outputDir - Output directory
|
|
48
|
-
*/
|
|
49
|
-
async function generatePage(pageConfig, outputDir) {
|
|
50
|
-
const { name, type, data } = pageConfig;
|
|
51
|
-
|
|
52
|
-
if (!name) {
|
|
53
|
-
throw new Error('Page name is required');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
let pageContent = '';
|
|
57
|
-
|
|
58
|
-
switch (type) {
|
|
59
|
-
case 'markdown':
|
|
60
|
-
pageContent = generateMarkdownPage(name, data);
|
|
61
|
-
break;
|
|
62
|
-
|
|
63
|
-
case 'json':
|
|
64
|
-
pageContent = generateJsonPage(name, data);
|
|
65
|
-
break;
|
|
66
|
-
|
|
67
|
-
case 'custom':
|
|
68
|
-
pageContent = data.template || generateDefaultPage(name, data);
|
|
69
|
-
break;
|
|
70
|
-
|
|
71
|
-
default:
|
|
72
|
-
pageContent = generateDefaultPage(name, data);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Write the generated page
|
|
76
|
-
const filename = name.toLowerCase().replace(/\s+/g, '-') + '.jsx';
|
|
77
|
-
const filepath = join(outputDir, filename);
|
|
78
|
-
|
|
79
|
-
await Bun.write(filepath, pageContent);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Generate a default React page
|
|
84
|
-
*/
|
|
85
|
-
function generateDefaultPage(name, data) {
|
|
86
|
-
const title = data?.title || name;
|
|
87
|
-
const content = data?.content || `<p>Welcome to ${name}</p>`;
|
|
88
|
-
|
|
89
|
-
return `// Auto-generated page: ${name}
|
|
90
|
-
import React from 'react';
|
|
91
|
-
|
|
92
|
-
export const title = "${title}";
|
|
93
|
-
export const description = "${data?.description || `${name} page`}";
|
|
94
|
-
|
|
95
|
-
export default function ${sanitizeComponentName(name)}() {
|
|
96
|
-
return (
|
|
97
|
-
<div>
|
|
98
|
-
<h1>${title}</h1>
|
|
99
|
-
${content}
|
|
100
|
-
</div>
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
`;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Generate a page from Markdown data
|
|
108
|
-
*/
|
|
109
|
-
function generateMarkdownPage(name, data) {
|
|
110
|
-
const title = data?.title || name;
|
|
111
|
-
const markdown = data?.markdown || '';
|
|
112
|
-
|
|
113
|
-
// Simple markdown to JSX conversion
|
|
114
|
-
const jsxContent = convertMarkdownToJSX(markdown);
|
|
115
|
-
|
|
116
|
-
return `// Auto-generated markdown page: ${name}
|
|
117
|
-
import React from 'react';
|
|
118
|
-
|
|
119
|
-
export const title = "${title}";
|
|
120
|
-
export const description = "${data?.description || `${name} page`}";
|
|
121
|
-
|
|
122
|
-
export default function ${sanitizeComponentName(name)}() {
|
|
123
|
-
return (
|
|
124
|
-
<div className="markdown-content">
|
|
125
|
-
${jsxContent}
|
|
126
|
-
</div>
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
`;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Generate a page from JSON data
|
|
134
|
-
*/
|
|
135
|
-
function generateJsonPage(name, data) {
|
|
136
|
-
const title = data?.title || name;
|
|
137
|
-
const items = data?.items || [];
|
|
138
|
-
|
|
139
|
-
return `// Auto-generated JSON page: ${name}
|
|
140
|
-
import React from 'react';
|
|
141
|
-
|
|
142
|
-
export const title = "${title}";
|
|
143
|
-
export const description = "${data?.description || `${name} page`}";
|
|
144
|
-
|
|
145
|
-
const items = ${JSON.stringify(items, null, 2)};
|
|
146
|
-
|
|
147
|
-
export default function ${sanitizeComponentName(name)}() {
|
|
148
|
-
return (
|
|
149
|
-
<div>
|
|
150
|
-
<h1>${title}</h1>
|
|
151
|
-
<ul>
|
|
152
|
-
{items.map((item, index) => (
|
|
153
|
-
<li key={index}>{item.title || item.name || item}</li>
|
|
154
|
-
))}
|
|
155
|
-
</ul>
|
|
156
|
-
</div>
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
`;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Convert markdown to JSX (basic implementation)
|
|
164
|
-
*/
|
|
165
|
-
function convertMarkdownToJSX(markdown) {
|
|
166
|
-
let jsx = markdown
|
|
167
|
-
// Headers
|
|
168
|
-
.replace(/^### (.*$)/gm, '<h3>$1</h3>')
|
|
169
|
-
.replace(/^## (.*$)/gm, '<h2>$1</h2>')
|
|
170
|
-
.replace(/^# (.*$)/gm, '<h1>$1</h1>')
|
|
171
|
-
// Bold
|
|
172
|
-
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
|
173
|
-
// Italic
|
|
174
|
-
.replace(/\*(.+?)\*/g, '<em>$1</em>')
|
|
175
|
-
// Paragraphs
|
|
176
|
-
.split('\n\n')
|
|
177
|
-
.map(para => para.trim() ? `<p>${para}</p>` : '')
|
|
178
|
-
.join('\n ');
|
|
179
|
-
|
|
180
|
-
return jsx;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Sanitize component name (must be valid React component name)
|
|
185
|
-
*/
|
|
186
|
-
function sanitizeComponentName(name) {
|
|
187
|
-
return name
|
|
188
|
-
.replace(/[^a-zA-Z0-9]/g, '')
|
|
189
|
-
.replace(/^[0-9]/, 'Page$&')
|
|
190
|
-
.replace(/^./, c => c.toUpperCase());
|
|
191
|
-
}
|