bertui 1.2.8 → 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.
- package/README.md +45 -196
- package/TYPES_PATCH.md +17 -0
- package/bin/bertui.js +2 -7
- package/package.json +32 -98
- package/src/config.ts +4 -0
- package/src/index.ts +32 -0
- package/src/optional.ts +49 -0
- package/src/router.ts +3 -0
- package/tsconfig.json +29 -0
- package/LICENSE +0 -21
- package/index.js +0 -103
- package/src/analyzer/index.js +0 -370
- package/src/build/compiler/file-transpiler.js +0 -216
- package/src/build/compiler/index.js +0 -31
- package/src/build/compiler/route-discoverer.js +0 -49
- package/src/build/compiler/router-generator.js +0 -105
- package/src/build/css-builder.js +0 -81
- package/src/build/generators/html-generator.js +0 -151
- package/src/build/generators/robots-generator.js +0 -58
- package/src/build/generators/sitemap-generator.js +0 -63
- package/src/build/image-optimizer.js +0 -137
- package/src/build/processors/asset-processor.js +0 -19
- package/src/build/processors/css-builder.js +0 -142
- package/src/build/server-island-validator.js +0 -12
- package/src/build.js +0 -266
- package/src/cli.js +0 -131
- package/src/client/compiler.js +0 -522
- package/src/client/fast-refresh.js +0 -72
- package/src/client/hmr-runtime.js +0 -59
- package/src/compiler/index.js +0 -25
- package/src/compiler/router-generator-pure.js +0 -104
- package/src/compiler/transform.js +0 -149
- package/src/config/defaultConfig.js +0 -37
- package/src/config/index.js +0 -2
- package/src/config/loadConfig.js +0 -64
- package/src/config/og-image.png +0 -0
- package/src/css/index.js +0 -46
- package/src/css/processor.js +0 -172
- package/src/dev.js +0 -68
- package/src/hydration/index.js +0 -151
- package/src/image-optimizer/index.js +0 -103
- package/src/images/index.js +0 -102
- package/src/images/processor.js +0 -169
- package/src/layouts/index.js +0 -165
- package/src/loading/index.js +0 -210
- package/src/logger/logger.js +0 -320
- package/src/logger/notes.md +0 -20
- package/src/middleware/index.js +0 -182
- package/src/router/Router.js +0 -150
- package/src/router/SSRRouter.js +0 -156
- package/src/router/index.js +0 -3
- package/src/scaffolder/index.js +0 -310
- package/src/serve.js +0 -193
- package/src/server/dev-handler.js +0 -195
- package/src/server/dev-server-utils.js +0 -406
- package/src/server/dev-server.js +0 -15
- package/src/server/hmr-handler.js +0 -148
- package/src/server/index.js +0 -3
- package/src/server/notes.md +0 -1
- package/src/server/request-handler.js +0 -36
- package/src/server-islands/extractor.js +0 -198
- package/src/server-islands/index.js +0 -59
- package/src/styles/bertui.css +0 -210
- package/src/utils/cache.js +0 -297
- package/src/utils/env.js +0 -87
- package/src/utils/importhow.js +0 -52
- package/src/utils/index.js +0 -11
- package/src/utils/meta-extractor.js +0 -127
- package/types/bin/bertui.d.ts +0 -3
- package/types/bin/bertui.d.ts.map +0 -1
- package/types/error-overlay.d.ts +0 -2
- package/types/error-overlay.d.ts.map +0 -1
- package/types/index.d.ts +0 -26
- package/types/index.d.ts.map +0 -1
- package/types/scripts/fix-wasm-exports.d.ts +0 -2
- package/types/scripts/fix-wasm-exports.d.ts.map +0 -1
- package/types/src/analyzer/index.d.ts +0 -8
- package/types/src/analyzer/index.d.ts.map +0 -1
- package/types/src/build/compiler/file-transpiler.d.ts +0 -5
- package/types/src/build/compiler/file-transpiler.d.ts.map +0 -1
- package/types/src/build/compiler/index.d.ts +0 -12
- package/types/src/build/compiler/index.d.ts.map +0 -1
- package/types/src/build/compiler/route-discoverer.d.ts +0 -2
- package/types/src/build/compiler/route-discoverer.d.ts.map +0 -1
- package/types/src/build/compiler/router-generator.d.ts +0 -2
- package/types/src/build/compiler/router-generator.d.ts.map +0 -1
- package/types/src/build/css-builder.d.ts +0 -18
- package/types/src/build/css-builder.d.ts.map +0 -1
- package/types/src/build/generators/html-generator.d.ts +0 -2
- package/types/src/build/generators/html-generator.d.ts.map +0 -1
- package/types/src/build/generators/robots-generator.d.ts +0 -11
- package/types/src/build/generators/robots-generator.d.ts.map +0 -1
- package/types/src/build/generators/sitemap-generator.d.ts +0 -5
- package/types/src/build/generators/sitemap-generator.d.ts.map +0 -1
- package/types/src/build/image-optimizer.d.ts +0 -11
- package/types/src/build/image-optimizer.d.ts.map +0 -1
- package/types/src/build/processors/asset-processor.d.ts +0 -2
- package/types/src/build/processors/asset-processor.d.ts.map +0 -1
- package/types/src/build/processors/css-builder.d.ts +0 -2
- package/types/src/build/processors/css-builder.d.ts.map +0 -1
- package/types/src/build/server-island-validator.d.ts +0 -27
- package/types/src/build/server-island-validator.d.ts.map +0 -1
- package/types/src/build.d.ts +0 -5
- package/types/src/build.d.ts.map +0 -1
- package/types/src/cli.d.ts +0 -2
- package/types/src/cli.d.ts.map +0 -1
- package/types/src/client/compiler.d.ts +0 -16
- package/types/src/client/compiler.d.ts.map +0 -1
- package/types/src/client/fast-refresh.d.ts +0 -3
- package/types/src/client/fast-refresh.d.ts.map +0 -1
- package/types/src/client/hmr-runtime.d.ts +0 -4
- package/types/src/client/hmr-runtime.d.ts.map +0 -1
- package/types/src/compiler/index.d.ts +0 -8
- package/types/src/compiler/index.d.ts.map +0 -1
- package/types/src/compiler/router-generator-pure.d.ts +0 -2
- package/types/src/compiler/router-generator-pure.d.ts.map +0 -1
- package/types/src/compiler/transform.d.ts +0 -36
- package/types/src/compiler/transform.d.ts.map +0 -1
- package/types/src/config/defaultConfig.d.ts +0 -26
- package/types/src/config/defaultConfig.d.ts.map +0 -1
- package/types/src/config/index.d.ts +0 -3
- package/types/src/config/index.d.ts.map +0 -1
- package/types/src/config/loadConfig.d.ts +0 -2
- package/types/src/config/loadConfig.d.ts.map +0 -1
- package/types/src/css/index.d.ts +0 -6
- package/types/src/css/index.d.ts.map +0 -1
- package/types/src/css/processor.d.ts +0 -23
- package/types/src/css/processor.d.ts.map +0 -1
- package/types/src/dev.d.ts +0 -2
- package/types/src/dev.d.ts.map +0 -1
- package/types/src/hydration/index.d.ts +0 -33
- package/types/src/hydration/index.d.ts.map +0 -1
- package/types/src/image-optimizer/index.d.ts +0 -24
- package/types/src/image-optimizer/index.d.ts.map +0 -1
- package/types/src/images/index.d.ts +0 -12
- package/types/src/images/index.d.ts.map +0 -1
- package/types/src/images/processor.d.ts +0 -30
- package/types/src/images/processor.d.ts.map +0 -1
- package/types/src/layouts/index.d.ts +0 -28
- package/types/src/layouts/index.d.ts.map +0 -1
- package/types/src/loading/index.d.ts +0 -28
- package/types/src/loading/index.d.ts.map +0 -1
- package/types/src/logger/logger.d.ts +0 -30
- package/types/src/logger/logger.d.ts.map +0 -1
- package/types/src/middleware/index.d.ts +0 -61
- package/types/src/middleware/index.d.ts.map +0 -1
- package/types/src/router/Router.d.ts +0 -16
- package/types/src/router/Router.d.ts.map +0 -1
- package/types/src/router/SSRRouter.d.ts +0 -20
- package/types/src/router/SSRRouter.d.ts.map +0 -1
- package/types/src/router/index.d.ts +0 -3
- package/types/src/router/index.d.ts.map +0 -1
- package/types/src/scaffolder/index.d.ts +0 -14
- package/types/src/scaffolder/index.d.ts.map +0 -1
- package/types/src/serve.d.ts +0 -3
- package/types/src/serve.d.ts.map +0 -1
- package/types/src/server/dev-handler.d.ts +0 -13
- package/types/src/server/dev-handler.d.ts.map +0 -1
- package/types/src/server/dev-server-utils.d.ts +0 -6
- package/types/src/server/dev-server-utils.d.ts.map +0 -1
- package/types/src/server/dev-server.d.ts +0 -18
- package/types/src/server/dev-server.d.ts.map +0 -1
- package/types/src/server/hmr-handler.d.ts +0 -19
- package/types/src/server/hmr-handler.d.ts.map +0 -1
- package/types/src/server/index.d.ts +0 -4
- package/types/src/server/index.d.ts.map +0 -1
- package/types/src/server/request-handler.d.ts +0 -19
- package/types/src/server/request-handler.d.ts.map +0 -1
- package/types/src/server-islands/extractor.d.ts +0 -16
- package/types/src/server-islands/extractor.d.ts.map +0 -1
- package/types/src/server-islands/index.d.ts +0 -3
- package/types/src/server-islands/index.d.ts.map +0 -1
- package/types/src/utils/cache.d.ts +0 -52
- package/types/src/utils/cache.d.ts.map +0 -1
- package/types/src/utils/env.d.ts +0 -20
- package/types/src/utils/env.d.ts.map +0 -1
- package/types/src/utils/importhow.d.ts +0 -15
- package/types/src/utils/importhow.d.ts.map +0 -1
- package/types/src/utils/index.d.ts +0 -3
- package/types/src/utils/index.d.ts.map +0 -1
- package/types/src/utils/meta-extractor.d.ts +0 -13
- package/types/src/utils/meta-extractor.d.ts.map +0 -1
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
// bertui/src/compiler/router-generator-pure.js - NEW FILE
|
|
2
|
-
// PURE function - no file system, no server
|
|
3
|
-
|
|
4
|
-
export function generateRouterCode(routes) {
|
|
5
|
-
const imports = routes.map((route, i) => {
|
|
6
|
-
const componentName = `Page${i}`;
|
|
7
|
-
const importPath = route.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
|
-
return `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
|
-
// Static routes
|
|
39
|
-
for (const route of routes) {
|
|
40
|
-
if (route.type === 'static' && route.path === pathname) {
|
|
41
|
-
setCurrentRoute(route);
|
|
42
|
-
setParams({});
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
// Dynamic routes
|
|
47
|
-
for (const route of routes) {
|
|
48
|
-
if (route.type === 'dynamic') {
|
|
49
|
-
const pattern = route.path.replace(/\\[([^\\]]+)\\]/g, '([^/]+)');
|
|
50
|
-
const regex = new RegExp('^' + pattern + '$');
|
|
51
|
-
const match = pathname.match(regex);
|
|
52
|
-
if (match) {
|
|
53
|
-
const paramNames = [...route.path.matchAll(/\\[([^\\]]+)\\]/g)].map(m => m[1]);
|
|
54
|
-
const extractedParams = {};
|
|
55
|
-
paramNames.forEach((name, i) => { extractedParams[name] = match[i + 1]; });
|
|
56
|
-
setCurrentRoute(route);
|
|
57
|
-
setParams(extractedParams);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
setCurrentRoute(null);
|
|
63
|
-
setParams({});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function navigate(path) {
|
|
67
|
-
window.history.pushState({}, '', path);
|
|
68
|
-
matchAndSetRoute(path);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const Component = currentRoute?.component;
|
|
72
|
-
return React.createElement(
|
|
73
|
-
RouterContext.Provider,
|
|
74
|
-
{ value: { currentRoute, params, navigate, pathname: window.location.pathname } },
|
|
75
|
-
Component ? React.createElement(Component, { params }) : React.createElement(NotFound)
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function Link({ to, children, ...props }) {
|
|
80
|
-
const { navigate } = useRouter();
|
|
81
|
-
return React.createElement('a', {
|
|
82
|
-
href: to,
|
|
83
|
-
onClick: (e) => { e.preventDefault(); navigate(to); },
|
|
84
|
-
...props
|
|
85
|
-
}, children);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function NotFound() {
|
|
89
|
-
return React.createElement('div', {
|
|
90
|
-
style: { display: 'flex', flexDirection: 'column', alignItems: 'center',
|
|
91
|
-
justifyContent: 'center', minHeight: '100vh', fontFamily: 'system-ui' }
|
|
92
|
-
},
|
|
93
|
-
React.createElement('h1', { style: { fontSize: '6rem', margin: 0 } }, '404'),
|
|
94
|
-
React.createElement('p', { style: { fontSize: '1.5rem', color: '#666' } }, 'Page not found'),
|
|
95
|
-
React.createElement('a', { href: '/', style: { color: '#10b981', textDecoration: 'none' } }, 'Go home')
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
${imports}
|
|
100
|
-
|
|
101
|
-
export const routes = [
|
|
102
|
-
${routeConfigs}
|
|
103
|
-
];`;
|
|
104
|
-
}
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
// bertui/src/compiler/transform.js - NEW FILE
|
|
2
|
-
// PURE JSX/TSX transformation function - NO FILE SYSTEM
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Transform JSX/TSX code to JavaScript
|
|
6
|
-
* @param {string} sourceCode - The source code to transform
|
|
7
|
-
* @param {Object} options - Transformation options
|
|
8
|
-
* @param {string} options.loader - 'jsx', 'tsx', 'ts', 'js' (default: 'tsx')
|
|
9
|
-
* @param {string} options.env - 'development' or 'production' (default: 'development')
|
|
10
|
-
* @param {boolean} options.addReactImport - Automatically add React import if missing (default: true)
|
|
11
|
-
* @returns {Promise<string>} Transformed JavaScript code
|
|
12
|
-
*/
|
|
13
|
-
export async function transformJSX(sourceCode, options = {}) {
|
|
14
|
-
const {
|
|
15
|
-
loader = 'tsx',
|
|
16
|
-
env = 'development',
|
|
17
|
-
addReactImport = true
|
|
18
|
-
} = options;
|
|
19
|
-
|
|
20
|
-
// Skip transformation if it's plain JS without JSX
|
|
21
|
-
if (loader === 'js' && !sourceCode.includes('React.createElement') && !/<[A-Z]/.test(sourceCode)) {
|
|
22
|
-
return sourceCode;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
// Create Bun transpiler instance
|
|
27
|
-
const transpiler = new Bun.Transpiler({
|
|
28
|
-
loader,
|
|
29
|
-
target: 'browser',
|
|
30
|
-
define: {
|
|
31
|
-
'process.env.NODE_ENV': JSON.stringify(env)
|
|
32
|
-
},
|
|
33
|
-
tsconfig: {
|
|
34
|
-
compilerOptions: {
|
|
35
|
-
jsx: 'react',
|
|
36
|
-
jsxFactory: 'React.createElement',
|
|
37
|
-
jsxFragmentFactory: 'React.Fragment',
|
|
38
|
-
target: 'ES2020',
|
|
39
|
-
module: 'ESNext'
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
let transformed = await transpiler.transform(sourceCode);
|
|
45
|
-
|
|
46
|
-
// Add React import if needed and not already present
|
|
47
|
-
if (addReactImport &&
|
|
48
|
-
!transformed.includes('import React') &&
|
|
49
|
-
!transformed.includes('import * as React') &&
|
|
50
|
-
(transformed.includes('React.createElement') || transformed.includes('jsx(') || transformed.includes('jsxs('))) {
|
|
51
|
-
transformed = `import React from 'react';\n${transformed}`;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Clean up any dev JSX references
|
|
55
|
-
if (env === 'production') {
|
|
56
|
-
transformed = transformed.replace(/jsxDEV/g, 'jsx');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return transformed;
|
|
60
|
-
|
|
61
|
-
} catch (error) {
|
|
62
|
-
throw new Error(`JSX transformation failed: ${error.message}`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Synchronous version of transformJSX
|
|
68
|
-
* Use only when you know the code is small and you need sync execution
|
|
69
|
-
*/
|
|
70
|
-
export function transformJSXSync(sourceCode, options = {}) {
|
|
71
|
-
const {
|
|
72
|
-
loader = 'tsx',
|
|
73
|
-
env = 'development',
|
|
74
|
-
addReactImport = true
|
|
75
|
-
} = options;
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
const transpiler = new Bun.Transpiler({
|
|
79
|
-
loader,
|
|
80
|
-
target: 'browser',
|
|
81
|
-
define: {
|
|
82
|
-
'process.env.NODE_ENV': JSON.stringify(env)
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
let transformed = transpiler.transformSync(sourceCode);
|
|
87
|
-
|
|
88
|
-
if (addReactImport &&
|
|
89
|
-
!transformed.includes('import React') &&
|
|
90
|
-
!transformed.includes('import * as React') &&
|
|
91
|
-
(transformed.includes('React.createElement') || transformed.includes('jsx('))) {
|
|
92
|
-
transformed = `import React from 'react';\n${transformed}`;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (env === 'production') {
|
|
96
|
-
transformed = transformed.replace(/jsxDEV/g, 'jsx');
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return transformed;
|
|
100
|
-
|
|
101
|
-
} catch (error) {
|
|
102
|
-
throw new Error(`JSX transformation failed: ${error.message}`);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Check if code contains JSX syntax
|
|
108
|
-
*/
|
|
109
|
-
export function containsJSX(code) {
|
|
110
|
-
return code.includes('React.createElement') ||
|
|
111
|
-
code.includes('React.Fragment') ||
|
|
112
|
-
/<[A-Z]/.test(code) ||
|
|
113
|
-
code.includes('jsx(') ||
|
|
114
|
-
code.includes('jsxs(') ||
|
|
115
|
-
/<[a-z][a-z0-9]*\s/.test(code);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Remove CSS imports from code (for production builds)
|
|
120
|
-
*/
|
|
121
|
-
export function removeCSSImports(code) {
|
|
122
|
-
return code
|
|
123
|
-
.replace(/import\s+['"][^'"]*\.css['"];?\s*/g, '')
|
|
124
|
-
.replace(/import\s+['"]bertui\/styles['"]\s*;?\s*/g, '');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Remove dotenv imports (for browser)
|
|
129
|
-
*/
|
|
130
|
-
export function removeDotenvImports(code) {
|
|
131
|
-
return code
|
|
132
|
-
.replace(/import\s+\w+\s+from\s+['"]dotenv['"]\s*;?\s*/g, '')
|
|
133
|
-
.replace(/import\s+\{[^}]+\}\s+from\s+['"]dotenv['"]\s*;?\s*/g, '')
|
|
134
|
-
.replace(/\w+\.config\(\s*\)\s*;?\s*/g, '');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Fix relative imports to include .js extension
|
|
139
|
-
*/
|
|
140
|
-
export function fixRelativeImports(code) {
|
|
141
|
-
const importRegex = /from\s+['"](\.\.?\/[^'"]+?)(?<!\.js|\.jsx|\.ts|\.tsx|\.json)['"]/g;
|
|
142
|
-
|
|
143
|
-
return code.replace(importRegex, (match, path) => {
|
|
144
|
-
if (path.endsWith('/') || /\.\w+$/.test(path)) {
|
|
145
|
-
return match;
|
|
146
|
-
}
|
|
147
|
-
return `from '${path}.js'`;
|
|
148
|
-
});
|
|
149
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// bertui/src/config/defaultConfig.js
|
|
2
|
-
export const defaultConfig = {
|
|
3
|
-
siteName: "BertUI App",
|
|
4
|
-
baseUrl: "http://localhost:3000",
|
|
5
|
-
|
|
6
|
-
// importhow: alias → relative path from project root
|
|
7
|
-
// Example:
|
|
8
|
-
// importhow: {
|
|
9
|
-
// amani: '../../components',
|
|
10
|
-
// ui: '../../components/ui',
|
|
11
|
-
// text: '../../utils/text',
|
|
12
|
-
// }
|
|
13
|
-
importhow: {},
|
|
14
|
-
|
|
15
|
-
meta: {
|
|
16
|
-
title: "BertUI - Lightning Fast React",
|
|
17
|
-
description: "Build lightning-fast React applications with file-based routing powered by Bun",
|
|
18
|
-
keywords: "react, bun, bertui, fast, file-based routing",
|
|
19
|
-
author: "Pease Ernest",
|
|
20
|
-
themeColor: "#667eea",
|
|
21
|
-
lang: "en",
|
|
22
|
-
ogTitle: "BertUI - Lightning Fast React Framework",
|
|
23
|
-
ogDescription: "Build lightning-fast React apps with zero config",
|
|
24
|
-
ogImage: "/og-image.png"
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
appShell: {
|
|
28
|
-
loading: true,
|
|
29
|
-
loadingText: "Loading...",
|
|
30
|
-
backgroundColor: "#ffffff"
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
robots: {
|
|
34
|
-
disallow: [],
|
|
35
|
-
crawlDelay: null
|
|
36
|
-
}
|
|
37
|
-
};
|
package/src/config/index.js
DELETED
package/src/config/loadConfig.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
// bertui/src/config/loadConfig.js
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { existsSync } from 'fs';
|
|
4
|
-
import { defaultConfig } from './defaultConfig.js';
|
|
5
|
-
import logger from '../logger/logger.js';
|
|
6
|
-
|
|
7
|
-
export async function loadConfig(root) {
|
|
8
|
-
const configPath = join(root, 'bertui.config.js');
|
|
9
|
-
|
|
10
|
-
if (!existsSync(configPath)) {
|
|
11
|
-
logger.info('No config found, using defaults');
|
|
12
|
-
return defaultConfig;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
// Read and transpile the config file manually —
|
|
17
|
-
// avoids Bun's dynamic import() build step which errors on plain JS configs
|
|
18
|
-
const source = await Bun.file(configPath).text();
|
|
19
|
-
|
|
20
|
-
const transpiler = new Bun.Transpiler({
|
|
21
|
-
loader: 'js',
|
|
22
|
-
target: 'bun',
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
let code = await transpiler.transform(source);
|
|
26
|
-
|
|
27
|
-
// Strip any leftover 'export default' so we can eval it
|
|
28
|
-
// and grab the value directly
|
|
29
|
-
code = code.replace(/export\s+default\s+/, 'globalThis.__bertuiConfig = ');
|
|
30
|
-
|
|
31
|
-
// Run it in the current context
|
|
32
|
-
const fn = new Function('globalThis', code);
|
|
33
|
-
fn(globalThis);
|
|
34
|
-
|
|
35
|
-
const userConfig = globalThis.__bertuiConfig;
|
|
36
|
-
delete globalThis.__bertuiConfig;
|
|
37
|
-
|
|
38
|
-
if (!userConfig) {
|
|
39
|
-
logger.warn('bertui.config.js did not export a default value, using defaults');
|
|
40
|
-
return defaultConfig;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
logger.success('Loaded bertui.config.js');
|
|
44
|
-
|
|
45
|
-
logger.info(`📋 Config: importhow=${JSON.stringify(Object.keys(userConfig.importhow || {}))}`);
|
|
46
|
-
|
|
47
|
-
return mergeConfig(defaultConfig, userConfig);
|
|
48
|
-
|
|
49
|
-
} catch (error) {
|
|
50
|
-
logger.error(`Failed to load bertui.config.js: ${error.message}`);
|
|
51
|
-
return defaultConfig;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function mergeConfig(defaults, user) {
|
|
56
|
-
const merged = { ...user };
|
|
57
|
-
merged.meta = { ...defaults.meta, ...(user.meta || {}) };
|
|
58
|
-
merged.appShell = { ...defaults.appShell, ...(user.appShell || {}) };
|
|
59
|
-
merged.robots = { ...defaults.robots, ...(user.robots || {}) };
|
|
60
|
-
merged.importhow = { ...(defaults.importhow || {}), ...(user.importhow || {}) };
|
|
61
|
-
if (!merged.siteName) merged.siteName = defaults.siteName;
|
|
62
|
-
if (!merged.baseUrl) merged.baseUrl = defaults.baseUrl;
|
|
63
|
-
return merged;
|
|
64
|
-
}
|
package/src/config/og-image.png
DELETED
|
Binary file
|
package/src/css/index.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
// bertui/src/css/index.js - NEW FILE
|
|
2
|
-
// PURE CSS processing - no server
|
|
3
|
-
|
|
4
|
-
import { transform } from 'lightningcss';
|
|
5
|
-
import logger from '../logger/logger.js';
|
|
6
|
-
|
|
7
|
-
export async function minifyCSS(css, options = {}) {
|
|
8
|
-
try {
|
|
9
|
-
const { code } = transform({
|
|
10
|
-
filename: options.filename || 'style.css',
|
|
11
|
-
code: Buffer.from(css),
|
|
12
|
-
minify: true,
|
|
13
|
-
sourceMap: false,
|
|
14
|
-
targets: {
|
|
15
|
-
chrome: 90 << 16,
|
|
16
|
-
firefox: 88 << 16,
|
|
17
|
-
safari: 14 << 16,
|
|
18
|
-
edge: 90 << 16
|
|
19
|
-
},
|
|
20
|
-
drafts: {
|
|
21
|
-
nesting: true
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
return code.toString();
|
|
25
|
-
} catch (error) {
|
|
26
|
-
logger.warn(`CSS minification failed: ${error.message}`);
|
|
27
|
-
// Fallback minification
|
|
28
|
-
return css
|
|
29
|
-
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
30
|
-
.replace(/\s+/g, ' ')
|
|
31
|
-
.replace(/\s*([{}:;,])\s*/g, '$1')
|
|
32
|
-
.replace(/;}/g, '}')
|
|
33
|
-
.trim();
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function combineCSS(files) {
|
|
38
|
-
return files.map(({ filename, content }) =>
|
|
39
|
-
`/* ${filename} */\n${content}`
|
|
40
|
-
).join('\n\n');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
export { minifyCSS, minifyCSSSync, combineCSS, extractCSSImports, isCSSFile } from './processor.js';
|
|
45
|
-
export { buildAllCSS } from '../build/processors/css-builder.js';
|
|
46
|
-
export { buildCSS, copyCSS } from '../build/css-builder.js';
|
package/src/css/processor.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
// bertui/src/css/processor.js - PURE CSS PROCESSING
|
|
2
|
-
import { transform } from 'lightningcss';
|
|
3
|
-
import logger from '../logger/logger.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Minify CSS using Lightning CSS with fallback
|
|
7
|
-
*/
|
|
8
|
-
export async function minifyCSS(css, options = {}) {
|
|
9
|
-
const {
|
|
10
|
-
filename = 'style.css',
|
|
11
|
-
minify = true,
|
|
12
|
-
sourceMap = false,
|
|
13
|
-
targets = {
|
|
14
|
-
chrome: 90 << 16,
|
|
15
|
-
firefox: 88 << 16,
|
|
16
|
-
safari: 14 << 16,
|
|
17
|
-
edge: 90 << 16
|
|
18
|
-
}
|
|
19
|
-
} = options;
|
|
20
|
-
|
|
21
|
-
// Empty CSS
|
|
22
|
-
if (!css || css.trim() === '') {
|
|
23
|
-
return '/* Empty CSS */';
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
const { code } = transform({
|
|
28
|
-
filename,
|
|
29
|
-
code: Buffer.from(css),
|
|
30
|
-
minify,
|
|
31
|
-
sourceMap,
|
|
32
|
-
targets,
|
|
33
|
-
drafts: {
|
|
34
|
-
nesting: true
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return code.toString();
|
|
39
|
-
} catch (error) {
|
|
40
|
-
logger.warn(`Lightning CSS failed: ${error.message}, using fallback minifier`);
|
|
41
|
-
return fallbackMinifyCSS(css);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Synchronous version for build scripts
|
|
47
|
-
*/
|
|
48
|
-
export function minifyCSSSync(css, options = {}) {
|
|
49
|
-
const {
|
|
50
|
-
filename = 'style.css',
|
|
51
|
-
minify = true,
|
|
52
|
-
sourceMap = false
|
|
53
|
-
} = options;
|
|
54
|
-
|
|
55
|
-
if (!css || css.trim() === '') {
|
|
56
|
-
return '/* Empty CSS */';
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
const { code } = transform({
|
|
61
|
-
filename,
|
|
62
|
-
code: Buffer.from(css),
|
|
63
|
-
minify,
|
|
64
|
-
sourceMap,
|
|
65
|
-
drafts: {
|
|
66
|
-
nesting: true
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
return code.toString();
|
|
70
|
-
} catch (error) {
|
|
71
|
-
return fallbackMinifyCSS(css);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Combine multiple CSS files into one
|
|
77
|
-
*/
|
|
78
|
-
export function combineCSS(files) {
|
|
79
|
-
if (!Array.isArray(files)) {
|
|
80
|
-
throw new Error('combineCSS expects an array of {filename, content}');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return files.map(({ filename, content }) => {
|
|
84
|
-
// Add file comment for debugging
|
|
85
|
-
const header = `/* ${filename} */\n`;
|
|
86
|
-
return header + content;
|
|
87
|
-
}).join('\n\n');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Fallback CSS minifier (simple but works)
|
|
92
|
-
*/
|
|
93
|
-
function fallbackMinifyCSS(css) {
|
|
94
|
-
return css
|
|
95
|
-
// Remove comments
|
|
96
|
-
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
97
|
-
// Remove whitespace
|
|
98
|
-
.replace(/\s+/g, ' ')
|
|
99
|
-
// Remove space around { } : ; ,
|
|
100
|
-
.replace(/\s*([{}:;,])\s*/g, '$1')
|
|
101
|
-
// Remove last semicolon before }
|
|
102
|
-
.replace(/;}/g, '}')
|
|
103
|
-
// Remove leading/trailing space
|
|
104
|
-
.trim();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Extract CSS imports from JavaScript
|
|
109
|
-
*/
|
|
110
|
-
export function extractCSSImports(code) {
|
|
111
|
-
const imports = [];
|
|
112
|
-
const regex = /import\s+['"]([^'"]*\.css)['"];?/g;
|
|
113
|
-
let match;
|
|
114
|
-
|
|
115
|
-
while ((match = regex.exec(code)) !== null) {
|
|
116
|
-
imports.push(match[1]);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return imports;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Check if file is CSS
|
|
124
|
-
*/
|
|
125
|
-
export function isCSSFile(filename) {
|
|
126
|
-
return filename.toLowerCase().endsWith('.css');
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// ============================================
|
|
130
|
-
// OPTIONAL SCSS SUPPORT - COMMENTED OUT BY DEFAULT
|
|
131
|
-
// Uncomment only if you install 'sass' package
|
|
132
|
-
// ============================================
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
export async function processSCSS(scssCode, options = {}) {
|
|
136
|
-
try {
|
|
137
|
-
// Dynamic import so it doesn't fail if sass isn't installed
|
|
138
|
-
const sass = await import('sass').catch(() => {
|
|
139
|
-
throw new Error('sass package not installed. Run: bun add sass');
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
const result = sass.compileString(scssCode, {
|
|
143
|
-
style: options.compressed ? 'compressed' : 'expanded',
|
|
144
|
-
sourceMap: false,
|
|
145
|
-
loadPaths: options.loadPaths || []
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
return result.css;
|
|
149
|
-
} catch (error) {
|
|
150
|
-
logger.error(`SCSS compilation failed: ${error.message}`);
|
|
151
|
-
throw error;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export async function compileSCSSFile(filePath, options = {}) {
|
|
156
|
-
try {
|
|
157
|
-
const sass = await import('sass').catch(() => {
|
|
158
|
-
throw new Error('sass package not installed. Run: bun add sass');
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
const result = sass.compile(filePath, {
|
|
162
|
-
style: options.compressed ? 'compressed' : 'expanded',
|
|
163
|
-
sourceMap: false,
|
|
164
|
-
loadPaths: options.loadPaths || [require('path').dirname(filePath)]
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
return result.css;
|
|
168
|
-
} catch (error) {
|
|
169
|
-
logger.error(`SCSS file compilation failed: ${error.message}`);
|
|
170
|
-
throw error;
|
|
171
|
-
}
|
|
172
|
-
}
|
package/src/dev.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// bertui/src/dev.js
|
|
2
|
-
import { compileProject } from './client/compiler.js';
|
|
3
|
-
import { startDevServer } from './server/dev-server.js';
|
|
4
|
-
import { MiddlewareManager } from './middleware/index.js';
|
|
5
|
-
import { compileLayouts } from './layouts/index.js';
|
|
6
|
-
import { compileLoadingComponents } from './loading/index.js';
|
|
7
|
-
import { analyzeRoutes, logHydrationReport } from './hydration/index.js';
|
|
8
|
-
import logger from './logger/logger.js';
|
|
9
|
-
import { loadConfig } from './config/loadConfig.js';
|
|
10
|
-
|
|
11
|
-
const TOTAL_STEPS = 6;
|
|
12
|
-
|
|
13
|
-
export async function startDev(options = {}) {
|
|
14
|
-
const root = options.root || process.cwd();
|
|
15
|
-
const port = options.port || 3000;
|
|
16
|
-
|
|
17
|
-
logger.printHeader('DEV');
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
const config = await loadConfig(root);
|
|
21
|
-
|
|
22
|
-
// ── Step 1: Compile ──────────────────────────────────────────────────────
|
|
23
|
-
logger.step(1, TOTAL_STEPS, 'Compiling');
|
|
24
|
-
const { routes, outDir } = await compileProject(root);
|
|
25
|
-
logger.stepDone('Compiling', `${routes.length} routes`);
|
|
26
|
-
|
|
27
|
-
// ── Step 2: Layouts ──────────────────────────────────────────────────────
|
|
28
|
-
logger.step(2, TOTAL_STEPS, 'Layouts');
|
|
29
|
-
const layouts = await compileLayouts(root, outDir);
|
|
30
|
-
const layoutCount = Object.keys(layouts).length;
|
|
31
|
-
logger.stepDone('Layouts', layoutCount > 0 ? `${layoutCount} found` : 'none');
|
|
32
|
-
|
|
33
|
-
// ── Step 3: Loading states ───────────────────────────────────────────────
|
|
34
|
-
logger.step(3, TOTAL_STEPS, 'Loading states');
|
|
35
|
-
const loadingComponents = await compileLoadingComponents(root, outDir);
|
|
36
|
-
logger.stepDone('Loading states');
|
|
37
|
-
|
|
38
|
-
// ── Step 4: Hydration analysis ───────────────────────────────────────────
|
|
39
|
-
logger.step(4, TOTAL_STEPS, 'Hydration analysis');
|
|
40
|
-
if (routes && routes.length > 0) {
|
|
41
|
-
const analyzedRoutes = await analyzeRoutes(routes);
|
|
42
|
-
logger.stepDone('Hydration analysis',
|
|
43
|
-
`${analyzedRoutes.interactive.length} interactive · ${analyzedRoutes.static.length} static`);
|
|
44
|
-
} else {
|
|
45
|
-
logger.stepDone('Hydration analysis', 'no routes');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// ── Step 5: Middleware ───────────────────────────────────────────────────
|
|
49
|
-
logger.step(5, TOTAL_STEPS, 'Middleware');
|
|
50
|
-
const middlewareManager = new MiddlewareManager(root);
|
|
51
|
-
await middlewareManager.load();
|
|
52
|
-
middlewareManager.watch();
|
|
53
|
-
logger.stepDone('Middleware');
|
|
54
|
-
|
|
55
|
-
// ── Step 6: Dev server ───────────────────────────────────────────────────
|
|
56
|
-
logger.step(6, TOTAL_STEPS, 'Starting server');
|
|
57
|
-
await startDevServer({ root, port, middleware: middlewareManager, layouts, loadingComponents });
|
|
58
|
-
logger.stepDone('Starting server', `http://localhost:${port}`);
|
|
59
|
-
|
|
60
|
-
// ── Ready ────────────────────────────────────────────────────────────────
|
|
61
|
-
process.stdout.write(`\n ${'\x1b[1m'}\x1b[32m▶ Ready on http://localhost:${port}\x1b[0m\n\n`);
|
|
62
|
-
|
|
63
|
-
} catch (error) {
|
|
64
|
-
logger.stepFail('Dev server', error.message);
|
|
65
|
-
logger.error(error.stack || error.message);
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
68
|
-
}
|