frontend-hamroun 1.2.24 → 1.2.25
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 +3 -0
- package/package.json +1 -1
- package/templates/fullstack-app/api/hello.js +11 -0
- package/templates/fullstack-app/index.html +13 -0
- package/templates/fullstack-app/package-lock.json +3130 -0
- package/templates/fullstack-app/package.json +8 -19
- package/templates/fullstack-app/server.js +68 -0
- package/templates/fullstack-app/server.ts +70 -31
- package/templates/fullstack-app/src/client.js +20 -0
- package/templates/fullstack-app/src/main.tsx +9 -0
- package/templates/fullstack-app/src/pages/index.tsx +40 -36
- package/templates/fullstack-app/vite.config.js +40 -0
- package/templates/ssr-template/package-lock.json +95 -1161
- package/templates/ssr-template/package.json +6 -4
- package/templates/ssr-template/readme.md +17 -39
- package/templates/ssr-template/server.js +364 -549
- package/templates/ssr-template/tsconfig.json +2 -3
@@ -3,29 +3,18 @@
|
|
3
3
|
"version": "0.1.0",
|
4
4
|
"type": "module",
|
5
5
|
"scripts": {
|
6
|
-
"dev": "
|
7
|
-
"
|
8
|
-
"
|
6
|
+
"dev": "concurrently \"npm run dev:server\" \"npm run dev:client\"",
|
7
|
+
"dev:server": "node server.js",
|
8
|
+
"dev:client": "vite",
|
9
|
+
"build": "vite build",
|
10
|
+
"start": "node server.js"
|
9
11
|
},
|
10
12
|
"dependencies": {
|
11
|
-
"bcryptjs": "^2.4.3",
|
12
|
-
"cors": "^2.8.5",
|
13
13
|
"express": "^4.18.2",
|
14
|
-
"frontend-hamroun": "latest"
|
15
|
-
"jsonwebtoken": "^9.0.2",
|
16
|
-
"mongodb": "^5.7.0"
|
14
|
+
"frontend-hamroun": "latest"
|
17
15
|
},
|
18
16
|
"devDependencies": {
|
19
|
-
"
|
20
|
-
"
|
21
|
-
"@types/express": "^4.17.18",
|
22
|
-
"@types/jsonwebtoken": "^9.0.3",
|
23
|
-
"@types/node": "^18.16.19",
|
24
|
-
"autoprefixer": "^10.4.15",
|
25
|
-
"postcss": "^8.4.29",
|
26
|
-
"tailwindcss": "^3.3.3",
|
27
|
-
"ts-node": "^10.9.1",
|
28
|
-
"typescript": "^5.2.2",
|
29
|
-
"vite": "^4.4.9"
|
17
|
+
"concurrently": "^8.0.1",
|
18
|
+
"vite": "^4.3.9"
|
30
19
|
}
|
31
20
|
}
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import express from 'express';
|
2
|
+
import path from 'path';
|
3
|
+
import { fileURLToPath } from 'url';
|
4
|
+
import fs from 'fs';
|
5
|
+
|
6
|
+
// Get __dirname equivalent in ESM
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
8
|
+
const __dirname = path.dirname(__filename);
|
9
|
+
|
10
|
+
// Create Express app
|
11
|
+
const app = express();
|
12
|
+
const PORT = process.env.PORT || 3000;
|
13
|
+
|
14
|
+
// Middleware
|
15
|
+
app.use(express.json());
|
16
|
+
|
17
|
+
// For production, serve the built files
|
18
|
+
if (process.env.NODE_ENV === 'production') {
|
19
|
+
app.use(express.static(path.join(__dirname, 'dist')));
|
20
|
+
} else {
|
21
|
+
// In development, we'll let Vite handle the frontend
|
22
|
+
console.log('Running in development mode - Vite handles the frontend');
|
23
|
+
}
|
24
|
+
|
25
|
+
// API endpoints
|
26
|
+
app.get('/api/hello', (req, res) => {
|
27
|
+
res.json({
|
28
|
+
message: "Hello from the API!",
|
29
|
+
time: new Date().toISOString(),
|
30
|
+
features: [
|
31
|
+
"Server-side rendering",
|
32
|
+
"API routes",
|
33
|
+
"Component-based UI",
|
34
|
+
"React-like development experience"
|
35
|
+
]
|
36
|
+
});
|
37
|
+
});
|
38
|
+
|
39
|
+
// In production or if using SSR, handle all requests
|
40
|
+
app.get('*', (req, res, next) => {
|
41
|
+
// Skip API routes
|
42
|
+
if (req.path.startsWith('/api/')) {
|
43
|
+
return next();
|
44
|
+
}
|
45
|
+
|
46
|
+
// In production, serve the index.html
|
47
|
+
if (process.env.NODE_ENV === 'production') {
|
48
|
+
const indexPath = path.join(__dirname, 'dist', 'index.html');
|
49
|
+
if (fs.existsSync(indexPath)) {
|
50
|
+
res.sendFile(indexPath);
|
51
|
+
} else {
|
52
|
+
res.status(404).send('Not found');
|
53
|
+
}
|
54
|
+
} else {
|
55
|
+
// In development, redirect to Vite dev server
|
56
|
+
res.redirect(`http://localhost:5173${req.path}`);
|
57
|
+
}
|
58
|
+
});
|
59
|
+
|
60
|
+
// Start server
|
61
|
+
app.listen(PORT, () => {
|
62
|
+
console.log(`API Server running on http://localhost:${PORT}`);
|
63
|
+
|
64
|
+
if (process.env.NODE_ENV !== 'production') {
|
65
|
+
console.log(`Frontend development server will run on http://localhost:5173`);
|
66
|
+
console.log(`Run 'npm run dev' to start both servers`);
|
67
|
+
}
|
68
|
+
});
|
@@ -1,38 +1,77 @@
|
|
1
|
-
import
|
1
|
+
import express from 'express';
|
2
|
+
import path from 'path';
|
3
|
+
import { fileURLToPath } from 'url';
|
4
|
+
import fs from 'fs';
|
2
5
|
|
3
|
-
|
6
|
+
// Get __dirname equivalent in ESM
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
8
|
+
const __dirname = path.dirname(__filename);
|
9
|
+
|
10
|
+
// Create Express app
|
11
|
+
const app = express();
|
12
|
+
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3000;
|
13
|
+
|
14
|
+
// Serve static files from current directory
|
15
|
+
app.use(express.static(__dirname));
|
16
|
+
|
17
|
+
// Parse JSON and URL-encoded data
|
18
|
+
app.use(express.json());
|
19
|
+
app.use(express.urlencoded({ extended: true }));
|
20
|
+
|
21
|
+
// Basic API endpoint
|
22
|
+
app.get('/api/hello', (req, res) => {
|
23
|
+
res.json({
|
24
|
+
message: 'Hello from the API!',
|
25
|
+
time: new Date().toISOString(),
|
26
|
+
environment: process.env.NODE_ENV || 'development'
|
27
|
+
});
|
28
|
+
});
|
29
|
+
|
30
|
+
// Serve index.html for all other routes
|
31
|
+
app.get('*', (req, res) => {
|
4
32
|
try {
|
5
|
-
//
|
6
|
-
const
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
});
|
33
|
+
// Read index.html
|
34
|
+
const indexPath = path.join(__dirname, 'index.html');
|
35
|
+
const html = fs.readFileSync(indexPath, 'utf8');
|
36
|
+
|
37
|
+
// Add server-rendered content
|
38
|
+
const serverContent = `
|
39
|
+
<div class="server-content">
|
40
|
+
<h1>Frontend Hamroun Fullstack</h1>
|
41
|
+
<p>Server-side rendered content</p>
|
42
|
+
<div class="timestamp">Rendered at: ${new Date().toISOString()}</div>
|
43
|
+
<div class="api-container"></div>
|
44
|
+
</div>
|
45
|
+
`;
|
19
46
|
|
20
|
-
//
|
21
|
-
|
47
|
+
// Replace placeholder with server content
|
48
|
+
const modifiedHtml = html.replace(
|
49
|
+
/<div class="placeholder">[\s\S]*?<\/div>/,
|
50
|
+
serverContent
|
51
|
+
);
|
22
52
|
|
23
|
-
|
24
|
-
(process.env.PORT || 3000));
|
25
|
-
|
26
|
-
// Handle graceful shutdown
|
27
|
-
process.on('SIGINT', async () => {
|
28
|
-
console.log('Shutting down server...');
|
29
|
-
await app.stop();
|
30
|
-
process.exit(0);
|
31
|
-
});
|
53
|
+
res.send(modifiedHtml);
|
32
54
|
} catch (error) {
|
33
|
-
console.error('
|
34
|
-
|
55
|
+
console.error('Error serving HTML:', error);
|
56
|
+
res.status(500).send(`
|
57
|
+
<html>
|
58
|
+
<head><title>Server Error</title></head>
|
59
|
+
<body>
|
60
|
+
<h1>500 - Server Error</h1>
|
61
|
+
<p>${error.message}</p>
|
62
|
+
</body>
|
63
|
+
</html>
|
64
|
+
`);
|
35
65
|
}
|
36
|
-
}
|
66
|
+
});
|
67
|
+
|
68
|
+
// Start the server
|
69
|
+
app.listen(PORT, () => {
|
70
|
+
console.log(`Server running at http://localhost:${PORT}`);
|
71
|
+
});
|
37
72
|
|
38
|
-
|
73
|
+
// Handle graceful shutdown
|
74
|
+
process.on('SIGINT', () => {
|
75
|
+
console.log('Shutting down server...');
|
76
|
+
process.exit(0);
|
77
|
+
});
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { hydrate, createElement } from 'frontend-hamroun';
|
2
|
+
|
3
|
+
// Simple component for testing
|
4
|
+
function App() {
|
5
|
+
return createElement('div', null, [
|
6
|
+
createElement('h1', null, 'Hello from Frontend Hamroun'),
|
7
|
+
createElement('p', null, 'This is a fullstack app with SSR')
|
8
|
+
]);
|
9
|
+
}
|
10
|
+
|
11
|
+
// Wait for DOM to be ready
|
12
|
+
document.addEventListener('DOMContentLoaded', () => {
|
13
|
+
const root = document.getElementById('root');
|
14
|
+
|
15
|
+
// Hydrate the application
|
16
|
+
if (root) {
|
17
|
+
hydrate(createElement(App), root);
|
18
|
+
console.log('App hydrated successfully');
|
19
|
+
}
|
20
|
+
});
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { jsx, render } from 'frontend-hamroun';
|
2
|
+
import HomePage from './pages/index.tsx';
|
3
|
+
|
4
|
+
// Add global jsx for Vite to use
|
5
|
+
window.jsx = jsx;
|
6
|
+
|
7
|
+
// Fix: Pass the component properly to render
|
8
|
+
// Don't call HomePage() directly - pass it as a component
|
9
|
+
render(jsx(HomePage, {}, null), document.getElementById('root'));
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { useState, useEffect } from 'frontend-hamroun';
|
1
|
+
import { jsx, useState, useEffect } from 'frontend-hamroun';
|
2
2
|
|
3
3
|
export default function HomePage() {
|
4
4
|
const [apiData, setApiData] = useState(null);
|
@@ -21,39 +21,43 @@ export default function HomePage() {
|
|
21
21
|
fetchData();
|
22
22
|
}, []);
|
23
23
|
|
24
|
-
return (
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
24
|
+
return jsx('div', { className: "container mx-auto p-4" }, [
|
25
|
+
jsx('h1', { className: "text-3xl font-bold mb-4" }, "Frontend Hamroun Full Stack"),
|
26
|
+
|
27
|
+
jsx('div', { className: "mb-6" }, [
|
28
|
+
jsx('h2', { className: "text-xl font-semibold mb-2" }, "API Response:"),
|
29
|
+
loading
|
30
|
+
? jsx('p', {}, "Loading...")
|
31
|
+
: error
|
32
|
+
? jsx('p', { className: "text-red-500" }, `Error: ${error}`)
|
33
|
+
: jsx('pre', { className: "bg-gray-100 p-4 rounded" },
|
34
|
+
JSON.stringify(apiData, null, 2)
|
35
|
+
)
|
36
|
+
]),
|
37
|
+
|
38
|
+
jsx('div', { className: "mb-6" }, [
|
39
|
+
jsx('h2', { className: "text-xl font-semibold mb-2" }, "Features:"),
|
40
|
+
jsx('ul', { className: "list-disc pl-6" }, [
|
41
|
+
jsx('li', {}, "Server-side rendering"),
|
42
|
+
jsx('li', {}, "API routes with Express"),
|
43
|
+
jsx('li', {}, "Database integration"),
|
44
|
+
jsx('li', {}, "Authentication and authorization"),
|
45
|
+
jsx('li', {}, "File-based routing")
|
46
|
+
])
|
47
|
+
]),
|
48
|
+
|
49
|
+
jsx('div', {}, [
|
50
|
+
jsx('h2', { className: "text-xl font-semibold mb-2" }, "Get Started:"),
|
51
|
+
jsx('p', {}, [
|
52
|
+
"Edit ",
|
53
|
+
jsx('code', { className: "bg-gray-100 px-2 py-1 rounded" }, "src/pages/index.tsx"),
|
54
|
+
" to customize this page"
|
55
|
+
]),
|
56
|
+
jsx('p', {}, [
|
57
|
+
"API routes are in the ",
|
58
|
+
jsx('code', { className: "bg-gray-100 px-2 py-1 rounded" }, "api"),
|
59
|
+
" directory"
|
60
|
+
])
|
61
|
+
])
|
62
|
+
]);
|
59
63
|
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import { defineConfig } from 'vite';
|
2
|
+
import { resolve } from 'path';
|
3
|
+
|
4
|
+
export default defineConfig({
|
5
|
+
// Server configuration
|
6
|
+
server: {
|
7
|
+
port: 5173,
|
8
|
+
proxy: {
|
9
|
+
'/api': 'http://localhost:3000'
|
10
|
+
}
|
11
|
+
},
|
12
|
+
|
13
|
+
// Using jsx transform with a different configuration
|
14
|
+
esbuild: {
|
15
|
+
jsxFactory: 'jsx',
|
16
|
+
jsxFragment: 'Fragment'
|
17
|
+
},
|
18
|
+
|
19
|
+
// Build configuration
|
20
|
+
build: {
|
21
|
+
outDir: 'dist',
|
22
|
+
rollupOptions: {
|
23
|
+
input: {
|
24
|
+
main: resolve(__dirname, 'index.html')
|
25
|
+
}
|
26
|
+
}
|
27
|
+
},
|
28
|
+
|
29
|
+
// Resolve aliases
|
30
|
+
resolve: {
|
31
|
+
alias: {
|
32
|
+
'@': resolve(__dirname, 'src')
|
33
|
+
}
|
34
|
+
},
|
35
|
+
|
36
|
+
// Optimize dependencies
|
37
|
+
optimizeDeps: {
|
38
|
+
include: ['frontend-hamroun']
|
39
|
+
}
|
40
|
+
});
|