free-framework 4.8.1 → 4.8.3
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/compiler/generator.js
CHANGED
|
@@ -166,14 +166,22 @@ if (server.namedMiddlewares['auth']) server.namedMiddlewares['AuthGuard'] = serv
|
|
|
166
166
|
handlerCode = node.handler || "";
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
const stylesRegistry = {};
|
|
170
|
+
ast.filter(n => n.type === 'component').forEach(comp => {
|
|
171
|
+
const styleNode = comp.body.find(b => b.type === 'style');
|
|
172
|
+
stylesRegistry[comp.name] = styleNode ? styleNode.content.trim() : "";
|
|
173
|
+
});
|
|
174
|
+
|
|
169
175
|
output += `\nserver.route("${node.method.toLowerCase()}", "${node.path}", ${JSON.stringify(middlewares)}, async (req, res) => {
|
|
170
176
|
const user = (res.context && res.context.user) ? res.context.user : null;
|
|
171
177
|
let body = {};
|
|
172
178
|
try {
|
|
173
|
-
if (req.headers['content-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
179
|
+
if (req.headers['content-length'] > 0) {
|
|
180
|
+
if (req.headers['content-type'] && req.headers['content-type'].includes('application/json')) {
|
|
181
|
+
body = await req.json().catch(() => ({}));
|
|
182
|
+
} else {
|
|
183
|
+
body = await req.urlencoded().catch(() => ({}));
|
|
184
|
+
}
|
|
177
185
|
}
|
|
178
186
|
} catch(e) {}
|
|
179
187
|
|
|
@@ -184,18 +192,23 @@ if (server.namedMiddlewares['auth']) server.namedMiddlewares['AuthGuard'] = serv
|
|
|
184
192
|
"\n" +
|
|
185
193
|
" // If it's a PAGE route (has a view), render HTML\n" +
|
|
186
194
|
" if (" + (node.view ? 'true' : 'false') + ") {\n" +
|
|
195
|
+
" const stylesRegistry = " + JSON.stringify(stylesRegistry) + ";\n" +
|
|
187
196
|
" const helpers = {\n" +
|
|
188
197
|
" renderComponent: (name, props = {}) => {\n" +
|
|
189
198
|
" server.renderRegistry = server.renderRegistry || {\n" +
|
|
190
199
|
" " + Object.keys(components).map(name => `${name}: render${name}`).join(',\n ') + "\n" +
|
|
191
200
|
" };\n" +
|
|
192
201
|
" return server.renderRegistry[name] ? server.renderRegistry[name](props, helpers) : '<!-- Component ' + name + ' not found -->';\n" +
|
|
202
|
+
" },\n" +
|
|
203
|
+
" getScopedCSS: (used = []) => {\n" +
|
|
204
|
+
" return used.map(name => stylesRegistry[name] || '').join('\\n');\n" +
|
|
193
205
|
" }\n" +
|
|
194
206
|
" };\n" +
|
|
195
207
|
" const props = result || (res.context && res.context.props ? res.context.props : {});\n" +
|
|
196
208
|
" const pageHtml = helpers.renderComponent('" + viewName + "', props);\n" +
|
|
209
|
+
" const scopedCSS = helpers.getScopedCSS(['" + viewName + "', 'Header']);\n" +
|
|
197
210
|
" if (req.headers['x-free-partial']) {\n" +
|
|
198
|
-
" return res.json({ title: 'Free Ultra | " + viewName + "', content: pageHtml, url: req.url });\n" +
|
|
211
|
+
" return res.json({ title: 'Free Ultra | " + viewName + "', content: pageHtml, url: req.url, css: scopedCSS });\n" +
|
|
199
212
|
" }\n" +
|
|
200
213
|
" const headerHtml = helpers.renderComponent('Header', props);\n" +
|
|
201
214
|
" const fullHTML = `<!DOCTYPE html>\n" +
|
|
@@ -210,7 +223,7 @@ if (server.namedMiddlewares['auth']) server.namedMiddlewares['AuthGuard'] = serv
|
|
|
210
223
|
" <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;900&display=swap\" rel=\"stylesheet\">\n" +
|
|
211
224
|
" <link rel=\"stylesheet\" href=\"/css/app.css\">\n" +
|
|
212
225
|
" <style>\n" +
|
|
213
|
-
" :root { --primary:#fff; --bg:#000; --border:#
|
|
226
|
+
" :root { --primary:#fff; --bg:#000; --border:#27272a; }\n" +
|
|
214
227
|
" body { margin:0; font-family:'Inter', system-ui, sans-serif; background:var(--bg); color:#fff; -webkit-font-smoothing:antialiased; }\n" +
|
|
215
228
|
" ${scopedCSS}\n" +
|
|
216
229
|
" </style>\n" +
|
package/package.json
CHANGED
package/runtime/server.js
CHANGED
|
@@ -15,7 +15,7 @@ const { LRUCache } = require('lru-cache');
|
|
|
15
15
|
|
|
16
16
|
class FreeServer {
|
|
17
17
|
constructor() {
|
|
18
|
-
console.log(`[Free Engine] ⚙️ Runtime Core v4.
|
|
18
|
+
console.log(`[Free Engine] ⚙️ Runtime Core v4.8.3 initializing...`);
|
|
19
19
|
this.app = new HyperExpress.Server();
|
|
20
20
|
this.viewsPath = process.env.VIEWS_PATH || nodePath.join(process.cwd(), 'views');
|
|
21
21
|
this.namedMiddlewares = {};
|
|
@@ -43,22 +43,32 @@ class FreeServer {
|
|
|
43
43
|
this.handleError(req, res, error);
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
// 3. Static Asset Serving (Simplified & Safe)
|
|
47
46
|
const publicPath = nodePath.join(process.cwd(), 'public');
|
|
48
47
|
this.app.use((req, res, next) => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
// If it looks like a file request (has a dot)
|
|
49
|
+
if (req.path.includes('.')) {
|
|
50
|
+
const lookupPath = req.path.startsWith('/') ? req.path.substring(1) : req.path;
|
|
51
|
+
const fullPath = nodePath.join(publicPath, lookupPath);
|
|
52
|
+
|
|
53
|
+
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
|
|
54
|
+
const ext = nodePath.extname(fullPath).toLowerCase();
|
|
55
|
+
const mimes = {
|
|
56
|
+
'.js': 'application/javascript',
|
|
57
|
+
'.css': 'text/css',
|
|
58
|
+
'.png': 'image/png',
|
|
59
|
+
'.jpg': 'image/jpeg',
|
|
60
|
+
'.jpeg': 'image/jpeg',
|
|
61
|
+
'.svg': 'image/svg+xml',
|
|
62
|
+
'.ico': 'image/x-icon',
|
|
63
|
+
'.json': 'application/json'
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
res.setHeader('Content-Type', mimes[ext] || 'text/plain');
|
|
67
|
+
return res.send(fs.readFileSync(fullPath));
|
|
68
|
+
}
|
|
55
69
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const ext = nodePath.extname(fullPath);
|
|
59
|
-
const mimes = { '.js': 'application/javascript', '.css': 'text/css', '.png': 'image/png', '.jpg': 'image/jpeg', '.svg': 'image/svg+xml' };
|
|
60
|
-
res.type(mimes[ext] || 'text/plain');
|
|
61
|
-
return res.send(fs.readFileSync(fullPath));
|
|
70
|
+
// If file not found but has extension, 404 immediately
|
|
71
|
+
return res.status(404).send('Not Found');
|
|
62
72
|
}
|
|
63
73
|
|
|
64
74
|
if (typeof next === 'function') next();
|
|
@@ -4,58 +4,59 @@
|
|
|
4
4
|
|
|
5
5
|
:root {
|
|
6
6
|
--primary: #fff;
|
|
7
|
-
--secondary: #
|
|
7
|
+
--secondary: #a1a1aa;
|
|
8
8
|
--bg: #000;
|
|
9
|
-
--surface: #
|
|
10
|
-
--border: #
|
|
11
|
-
--text-main: #
|
|
12
|
-
--text-muted: #
|
|
9
|
+
--surface: #09090b;
|
|
10
|
+
--border: #27272a;
|
|
11
|
+
--text-main: #fafafa;
|
|
12
|
+
--text-muted: #71717a;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
body {
|
|
16
|
-
@apply bg-
|
|
16
|
+
@apply bg-[#000] text-zinc-50 selection:bg-white selection:text-black;
|
|
17
17
|
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
|
18
18
|
-webkit-font-smoothing: antialiased;
|
|
19
|
+
background-image:
|
|
20
|
+
linear-gradient(to bottom, transparent, var(--bg)),
|
|
21
|
+
radial-gradient(circle at 2px 2px, rgba(255, 255, 255, 0.05) 1px, transparent 0);
|
|
22
|
+
background-size: 100% 100%, 40px 40px;
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
.container-pro {
|
|
22
|
-
@apply max-w-
|
|
26
|
+
@apply max-w-6xl mx-auto px-8;
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
.btn-pro {
|
|
26
|
-
@apply px-6 py-2 rounded-
|
|
27
|
-
background:
|
|
30
|
+
@apply px-6 py-2.5 rounded-lg font-semibold transition-all duration-300 flex items-center gap-2;
|
|
31
|
+
background: #fff;
|
|
28
32
|
color: #000;
|
|
33
|
+
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1), 0 4px 12px rgba(0, 0, 0, 0.4);
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
.btn-pro:hover {
|
|
32
|
-
@apply opacity-90
|
|
37
|
+
@apply opacity-90 -translate-y-0.5 shadow-xl;
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
.btn-outline {
|
|
36
|
-
@apply px-6 py-2 rounded-
|
|
41
|
+
@apply px-6 py-2.5 rounded-lg border border-border font-semibold text-zinc-300 transition-all hover:bg-zinc-900 hover:text-white;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
.card-pro {
|
|
40
|
-
@apply p-8 rounded-
|
|
45
|
+
@apply p-8 rounded-2xl border border-border bg-[#09090b]/50 backdrop-blur-sm transition-all duration-300 hover:border-zinc-700 hover:bg-[#09090b];
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
.hero-title {
|
|
44
|
-
@apply text-
|
|
49
|
+
@apply text-6xl md:text-8xl font-extrabold tracking-tight text-white mb-8 leading-[1.1];
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
.nav-link {
|
|
48
|
-
@apply text-sm
|
|
53
|
+
@apply text-sm font-medium text-zinc-500 transition-colors hover:text-white;
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
.badge-pro {
|
|
52
|
-
@apply px-2 py-
|
|
57
|
+
@apply px-2.5 py-1 rounded-full border border-border bg-zinc-900/50 text-[10px] font-bold tracking-tighter uppercase text-zinc-400;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
pre {
|
|
56
|
-
@apply bg-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
code {
|
|
60
|
-
@apply font-mono;
|
|
61
|
+
@apply bg-zinc-950 border border-border rounded-xl p-6 font-mono text-sm overflow-x-auto text-zinc-300;
|
|
61
62
|
}
|
|
@@ -1,47 +1,65 @@
|
|
|
1
1
|
component Home {
|
|
2
|
-
main class="pt-32 pb-
|
|
2
|
+
main class="pt-32 pb-40 overflow-hidden" {
|
|
3
3
|
// Hero
|
|
4
|
-
section class="container-pro text-center pt-
|
|
4
|
+
section class="container-pro text-center pt-24 pb-20" {
|
|
5
|
+
div class="inline-flex items-center gap-2 px-3 py-1 rounded-full border border-border bg-zinc-900/50 text-[11px] font-bold text-zinc-500 mb-8" {
|
|
6
|
+
span class="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" { }
|
|
7
|
+
text "VERSION 4.8.2 IS NOW LIVE"
|
|
8
|
+
}
|
|
9
|
+
|
|
5
10
|
h1 class="hero-title" {
|
|
6
|
-
text "The
|
|
11
|
+
text "The Engine for"
|
|
7
12
|
br { }
|
|
8
|
-
span class="text-
|
|
13
|
+
span class="text-zinc-600" { text "High-Performance." }
|
|
9
14
|
}
|
|
10
15
|
|
|
11
|
-
p class="text-xl text-text-
|
|
12
|
-
text "
|
|
16
|
+
p class="text-xl md:text-2xl text-zinc-500 max-w-3xl mx-auto mb-12 leading-relaxed font-medium" {
|
|
17
|
+
text "Experience the future of SSR with Islands Architecture, built-in Reactive state, and Enterprise-grade security. Small footprint, infinite power."
|
|
13
18
|
}
|
|
14
19
|
|
|
15
|
-
div class="flex flex-wrap justify-center gap-
|
|
20
|
+
div class="flex flex-wrap justify-center gap-5" {
|
|
16
21
|
a href="/docs" class="btn-pro" {
|
|
17
22
|
text "Get Started"
|
|
23
|
+
svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" {
|
|
24
|
+
path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" { }
|
|
25
|
+
}
|
|
18
26
|
}
|
|
19
27
|
a href="https://github.com/dev-omartolba" class="btn-outline" {
|
|
20
|
-
text "
|
|
28
|
+
text "View Source"
|
|
21
29
|
}
|
|
22
30
|
}
|
|
23
31
|
|
|
24
|
-
div class="mt-
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
div class="mt-24 max-w-4xl mx-auto relative" {
|
|
33
|
+
div class="absolute -inset-1 bg-gradient-to-r from-zinc-800 to-zinc-900 rounded-2xl blur opacity-20" { }
|
|
34
|
+
pre class="relative" {
|
|
35
|
+
code { text "$ npx free-framework@latest new my-project" }
|
|
27
36
|
}
|
|
28
37
|
}
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
// Features
|
|
32
|
-
section class="container-pro pt-
|
|
33
|
-
div class="grid md:grid-cols-3 gap-
|
|
41
|
+
section class="container-pro pt-32" {
|
|
42
|
+
div class="grid md:grid-cols-3 gap-8" {
|
|
34
43
|
div class="card-pro" {
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
div class="w-10 h-10 rounded-lg bg-zinc-900 border border-border flex items-center justify-center mb-6" {
|
|
45
|
+
text "⚡"
|
|
46
|
+
}
|
|
47
|
+
h3 class="text-xl font-bold mb-3" { text "Speed" }
|
|
48
|
+
p class="text-base text-zinc-500 leading-relaxed" { text "Zero-overhead runtime powered by HyperExpress for sub-millisecond responses." }
|
|
37
49
|
}
|
|
38
50
|
div class="card-pro" {
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
div class="w-10 h-10 rounded-lg bg-zinc-900 border border-border flex items-center justify-center mb-6" {
|
|
52
|
+
text "🏝️"
|
|
53
|
+
}
|
|
54
|
+
h3 class="text-xl font-bold mb-3" { text "Islands" }
|
|
55
|
+
p class="text-base text-zinc-500 leading-relaxed" { text "Partial hydration logic that ships minimal JavaScript for maximum SEO benefits." }
|
|
41
56
|
}
|
|
42
57
|
div class="card-pro" {
|
|
43
|
-
|
|
44
|
-
|
|
58
|
+
div class="w-10 h-10 rounded-lg bg-zinc-900 border border-border flex items-center justify-center mb-6" {
|
|
59
|
+
text "🛡️"
|
|
60
|
+
}
|
|
61
|
+
h3 class="text-xl font-bold mb-3" { text "Security" }
|
|
62
|
+
p class="text-base text-zinc-500 leading-relaxed" { text "Built-in DDoS protection, CSRF guards, and secure-by-default environment." }
|
|
45
63
|
}
|
|
46
64
|
}
|
|
47
65
|
}
|