frontend-hamroun 1.2.79 → 1.2.82

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 (259) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +129 -1513
  3. package/bin/cli.js +506 -145
  4. package/dist/index.cjs +2 -0
  5. package/dist/index.cjs.map +1 -0
  6. package/dist/index.client.cjs +2 -0
  7. package/dist/index.client.cjs.map +1 -0
  8. package/dist/index.client.js +26 -0
  9. package/dist/index.client.js.map +1 -0
  10. package/dist/index.js +299 -1
  11. package/dist/index.js.map +1 -0
  12. package/dist/jsx-runtime.cjs +2 -0
  13. package/dist/jsx-runtime.cjs.map +1 -0
  14. package/dist/jsx-runtime.js +93 -1
  15. package/dist/jsx-runtime.js.map +1 -0
  16. package/dist/renderer-Bo9zkUZ_.js +52 -0
  17. package/dist/renderer-Bo9zkUZ_.js.map +1 -0
  18. package/dist/renderer-Din1y3YM.cjs +2 -0
  19. package/dist/renderer-Din1y3YM.cjs.map +1 -0
  20. package/dist/server-renderer-CqIpQ-od.cjs +2 -0
  21. package/dist/server-renderer-CqIpQ-od.cjs.map +1 -0
  22. package/dist/server-renderer-QHt45Ip2.js +255 -0
  23. package/dist/server-renderer-QHt45Ip2.js.map +1 -0
  24. package/dist/server-renderer.cjs +2 -0
  25. package/dist/server-renderer.cjs.map +1 -0
  26. package/dist/server-renderer.js +5 -1
  27. package/dist/server-renderer.js.map +1 -0
  28. package/package.json +77 -120
  29. package/templates/basic-app/build.js +22 -0
  30. package/templates/basic-app/dev.js +27 -0
  31. package/templates/basic-app/esbuild.config.js +28 -0
  32. package/templates/basic-app/index.html +1 -1
  33. package/templates/basic-app/package.json +29 -28
  34. package/templates/basic-app/server.js +24 -0
  35. package/templates/basic-app/src/App.jsx +16 -0
  36. package/templates/basic-app/src/App.tsx +26 -0
  37. package/templates/basic-app/src/client.jsx +5 -0
  38. package/templates/basic-app/src/client.tsx +11 -0
  39. package/templates/basic-app/src/components/Counter.jsx +13 -0
  40. package/templates/basic-app/src/components/Counter.tsx +18 -0
  41. package/templates/basic-app/src/jsx-shim.js +3 -0
  42. package/templates/basic-app/src/jsx-shim.ts +11 -0
  43. package/templates/basic-app/src/main.jsx +98 -0
  44. package/templates/basic-app/src/main.tsx +0 -1
  45. package/templates/basic-app/src/server.js +47 -0
  46. package/templates/basic-app/src/server.ts +52 -0
  47. package/templates/basic-app/tsconfig.server.json +11 -0
  48. package/templates/complete-app/lib/frontend-hamroun.js +182 -0
  49. package/templates/complete-app/package.json +2 -1
  50. package/templates/complete-app/pages/about.jsx +0 -0
  51. package/templates/complete-app/pages/index.jsx +0 -0
  52. package/templates/complete-app/pages/wasm-demo.jsx +0 -0
  53. package/templates/complete-app/public/client.js +58 -49
  54. package/templates/complete-app/public/index.html +88 -17
  55. package/templates/complete-app/public/styles.css +30 -533
  56. package/templates/complete-app/server.js +31 -222
  57. package/templates/complete-app/wasm/build.bat +0 -0
  58. package/templates/complete-app/wasm/build.sh +0 -0
  59. package/templates/complete-app/wasm/example.go +0 -0
  60. package/templates/fullstack-app/build/main.js +130 -101
  61. package/templates/fullstack-app/build/main.js.map +4 -4
  62. package/templates/fullstack-app/package-lock.json +1773 -566
  63. package/templates/ssr-template/esbuild.config.js +33 -0
  64. package/templates/ssr-template/jsx-shim.js +1 -0
  65. package/templates/ssr-template/package.json +22 -16
  66. package/templates/ssr-template/src/App.tsx +12 -52
  67. package/templates/ssr-template/src/client.tsx +3 -17
  68. package/templates/ssr-template/src/server.ts +21 -204
  69. package/templates/ssr-template/tsconfig.json +10 -13
  70. package/templates/ssr-template/tsconfig.server.json +6 -14
  71. package/templates/wasm/build-wasm.js +228 -0
  72. package/templates/wasm/esbuild.config.js +63 -0
  73. package/templates/wasm/go/main.go +256 -0
  74. package/templates/wasm/go/wasm_exec.js +0 -0
  75. package/templates/wasm/index.html +97 -0
  76. package/templates/wasm/jsx-shim.js +9 -0
  77. package/templates/{go-wasm-app → wasm}/package-lock.json +5307 -3732
  78. package/templates/wasm/package.json +42 -0
  79. package/templates/wasm/public/example.wasm +0 -0
  80. package/templates/wasm/src/App.tsx +564 -0
  81. package/templates/wasm/src/client.tsx +220 -0
  82. package/templates/wasm/src/index.tsx +21 -0
  83. package/templates/wasm/src/server.ts +145 -0
  84. package/templates/wasm/tsconfig.json +21 -0
  85. package/templates/wasm/tsconfig.node.json +13 -0
  86. package/templates/wasm/tsconfig.server.json +23 -0
  87. package/templates/wasm/vite.config.ts +56 -0
  88. package/templates/wasm/wasm-loader.js +103 -0
  89. package/dist/batch/package.json +0 -16
  90. package/dist/client-router/package.json +0 -16
  91. package/dist/component/package.json +0 -16
  92. package/dist/context/package.json +0 -16
  93. package/dist/event-bus/package.json +0 -16
  94. package/dist/forms/package.json +0 -16
  95. package/dist/hooks/package.json +0 -16
  96. package/dist/hooks-0728361a.cjs +0 -1
  97. package/dist/hooks-b58f947c.js +0 -133
  98. package/dist/hooks.js +0 -1
  99. package/dist/hooks.mjs +0 -13
  100. package/dist/index.mjs +0 -137
  101. package/dist/jsx-runtime/package.json +0 -16
  102. package/dist/jsx-runtime.mjs +0 -64
  103. package/dist/lifecycle-events/package.json +0 -16
  104. package/dist/package.json +0 -71
  105. package/dist/render-component/package.json +0 -16
  106. package/dist/renderer/package.json +0 -16
  107. package/dist/renderer.js +0 -1
  108. package/dist/renderer.mjs +0 -27
  109. package/dist/router/package.json +0 -16
  110. package/dist/server/package.json +0 -17
  111. package/dist/server/src/batch.d.ts +0 -3
  112. package/dist/server/src/batch.js +0 -23
  113. package/dist/server/src/batch.js.map +0 -1
  114. package/dist/server/src/client-router.d.ts +0 -60
  115. package/dist/server/src/client-router.js +0 -210
  116. package/dist/server/src/client-router.js.map +0 -1
  117. package/dist/server/src/component.d.ts +0 -14
  118. package/dist/server/src/component.js +0 -106
  119. package/dist/server/src/component.js.map +0 -1
  120. package/dist/server/src/context.d.ts +0 -13
  121. package/dist/server/src/context.js +0 -21
  122. package/dist/server/src/context.js.map +0 -1
  123. package/dist/server/src/event-bus.d.ts +0 -23
  124. package/dist/server/src/event-bus.js +0 -75
  125. package/dist/server/src/event-bus.js.map +0 -1
  126. package/dist/server/src/forms.d.ts +0 -40
  127. package/dist/server/src/forms.js +0 -148
  128. package/dist/server/src/forms.js.map +0 -1
  129. package/dist/server/src/hooks.d.ts +0 -12
  130. package/dist/server/src/hooks.js +0 -170
  131. package/dist/server/src/hooks.js.map +0 -1
  132. package/dist/server/src/index.client.d.ts +0 -12
  133. package/dist/server/src/index.client.js +0 -14
  134. package/dist/server/src/index.client.js.map +0 -1
  135. package/dist/server/src/index.d.ts +0 -88
  136. package/dist/server/src/index.js +0 -79
  137. package/dist/server/src/index.js.map +0 -1
  138. package/dist/server/src/jsx-runtime/jsx-dev-runtime.d.ts +0 -1
  139. package/dist/server/src/jsx-runtime/jsx-dev-runtime.js +0 -2
  140. package/dist/server/src/jsx-runtime/jsx-dev-runtime.js.map +0 -1
  141. package/dist/server/src/jsx-runtime/jsx-runtime.d.ts +0 -4
  142. package/dist/server/src/jsx-runtime/jsx-runtime.js +0 -41
  143. package/dist/server/src/jsx-runtime/jsx-runtime.js.map +0 -1
  144. package/dist/server/src/jsx-runtime.d.ts +0 -20
  145. package/dist/server/src/jsx-runtime.js +0 -105
  146. package/dist/server/src/jsx-runtime.js.map +0 -1
  147. package/dist/server/src/lifecycle-events.d.ts +0 -108
  148. package/dist/server/src/lifecycle-events.js +0 -177
  149. package/dist/server/src/lifecycle-events.js.map +0 -1
  150. package/dist/server/src/renderComponent.d.ts +0 -13
  151. package/dist/server/src/renderComponent.js +0 -30
  152. package/dist/server/src/renderComponent.js.map +0 -1
  153. package/dist/server/src/renderer.d.ts +0 -2
  154. package/dist/server/src/renderer.js +0 -31
  155. package/dist/server/src/renderer.js.map +0 -1
  156. package/dist/server/src/router.d.ts +0 -55
  157. package/dist/server/src/router.js +0 -166
  158. package/dist/server/src/router.js.map +0 -1
  159. package/dist/server/src/server/api-router.d.ts +0 -15
  160. package/dist/server/src/server/api-router.js +0 -111
  161. package/dist/server/src/server/api-router.js.map +0 -1
  162. package/dist/server/src/server/auth.d.ts +0 -32
  163. package/dist/server/src/server/auth.js +0 -80
  164. package/dist/server/src/server/auth.js.map +0 -1
  165. package/dist/server/src/server/database.d.ts +0 -24
  166. package/dist/server/src/server/database.js +0 -135
  167. package/dist/server/src/server/database.js.map +0 -1
  168. package/dist/server/src/server/index.d.ts +0 -116
  169. package/dist/server/src/server/index.js +0 -508
  170. package/dist/server/src/server/index.js.map +0 -1
  171. package/dist/server/src/server/middleware.d.ts +0 -11
  172. package/dist/server/src/server/middleware.js +0 -46
  173. package/dist/server/src/server/middleware.js.map +0 -1
  174. package/dist/server/src/server/server.d.ts +0 -9
  175. package/dist/server/src/server/server.js +0 -87
  176. package/dist/server/src/server/server.js.map +0 -1
  177. package/dist/server/src/server/templates.d.ts +0 -30
  178. package/dist/server/src/server/templates.js +0 -208
  179. package/dist/server/src/server/templates.js.map +0 -1
  180. package/dist/server/src/server/types.d.ts +0 -38
  181. package/dist/server/src/server/types.js +0 -4
  182. package/dist/server/src/server/types.js.map +0 -1
  183. package/dist/server/src/server/utils.d.ts +0 -70
  184. package/dist/server/src/server/utils.js +0 -156
  185. package/dist/server/src/server/utils.js.map +0 -1
  186. package/dist/server/src/server/wasm.d.ts +0 -9
  187. package/dist/server/src/server/wasm.js +0 -117
  188. package/dist/server/src/server/wasm.js.map +0 -1
  189. package/dist/server/src/server-renderer.d.ts +0 -5
  190. package/dist/server/src/server-renderer.js +0 -106
  191. package/dist/server/src/server-renderer.js.map +0 -1
  192. package/dist/server/src/server-types.d.ts +0 -42
  193. package/dist/server/src/server-types.js +0 -6
  194. package/dist/server/src/server-types.js.map +0 -1
  195. package/dist/server/src/store.d.ts +0 -41
  196. package/dist/server/src/store.js +0 -99
  197. package/dist/server/src/store.js.map +0 -1
  198. package/dist/server/src/types.d.ts +0 -19
  199. package/dist/server/src/types.js +0 -2
  200. package/dist/server/src/types.js.map +0 -1
  201. package/dist/server/src/utils.d.ts +0 -46
  202. package/dist/server/src/utils.js +0 -144
  203. package/dist/server/src/utils.js.map +0 -1
  204. package/dist/server/src/vdom.d.ts +0 -8
  205. package/dist/server/src/vdom.js +0 -22
  206. package/dist/server/src/vdom.js.map +0 -1
  207. package/dist/server/src/wasm.d.ts +0 -36
  208. package/dist/server/src/wasm.js +0 -159
  209. package/dist/server/src/wasm.js.map +0 -1
  210. package/dist/server/tsconfig.server.tsbuildinfo +0 -1
  211. package/dist/server-renderer/package.json +0 -16
  212. package/dist/server-renderer.mjs +0 -64
  213. package/dist/store/package.json +0 -16
  214. package/dist/types/package.json +0 -16
  215. package/dist/utils/package.json +0 -16
  216. package/dist/vdom/package.json +0 -16
  217. package/dist/wasm/package.json +0 -16
  218. package/dist/wasm.js +0 -1
  219. package/dist/wasm.mjs +0 -103
  220. package/templates/basic-app/docs/rapport_pfe.aux +0 -27
  221. package/templates/basic-app/docs/rapport_pfe.log +0 -399
  222. package/templates/basic-app/docs/rapport_pfe.out +0 -10
  223. package/templates/basic-app/docs/rapport_pfe.pdf +0 -0
  224. package/templates/basic-app/docs/rapport_pfe.tex +0 -68
  225. package/templates/basic-app/docs/rapport_pfe.toc +0 -14
  226. package/templates/complete-app/package-lock.json +0 -2536
  227. package/templates/go-wasm-app/README.md +0 -38
  228. package/templates/go-wasm-app/babel.config.js +0 -21
  229. package/templates/go-wasm-app/build-client.js +0 -49
  230. package/templates/go-wasm-app/build-wasm.js +0 -237
  231. package/templates/go-wasm-app/build.config.js +0 -62
  232. package/templates/go-wasm-app/build.js +0 -218
  233. package/templates/go-wasm-app/package.json +0 -32
  234. package/templates/go-wasm-app/public/index.html +0 -128
  235. package/templates/go-wasm-app/public/styles.css +0 -197
  236. package/templates/go-wasm-app/public/wasm/example.wasm +0 -0
  237. package/templates/go-wasm-app/public/wasm/wasm_exec_node.js +0 -39
  238. package/templates/go-wasm-app/server.js +0 -70
  239. package/templates/go-wasm-app/src/App.jsx +0 -38
  240. package/templates/go-wasm-app/src/app.js +0 -173
  241. package/templates/go-wasm-app/src/client.js +0 -57
  242. package/templates/go-wasm-app/src/components/Footer.jsx +0 -13
  243. package/templates/go-wasm-app/src/components/Header.jsx +0 -19
  244. package/templates/go-wasm-app/src/components/WasmDemo.jsx +0 -120
  245. package/templates/go-wasm-app/src/main.jsx +0 -12
  246. package/templates/go-wasm-app/src/wasm/example.go +0 -75
  247. package/templates/go-wasm-app/tsconfig.server.json +0 -18
  248. package/templates/go-wasm-app/vite.config.js +0 -45
  249. package/templates/ssr-template/client.js +0 -58
  250. package/templates/ssr-template/package-lock.json +0 -2478
  251. package/templates/ssr-template/public/index.html +0 -47
  252. package/templates/ssr-template/readme.md +0 -188
  253. package/templates/ssr-template/server.js +0 -369
  254. package/templates/ssr-template/server.ts +0 -275
  255. package/templates/ssr-template/src/client.ts +0 -61
  256. package/templates/ssr-template/src/pages/index.tsx +0 -51
  257. package/templates/ssr-template/vite.config.js +0 -57
  258. /package/{dist/Counter.d.ts → templates/complete-app/api/hello.js} +0 -0
  259. /package/templates/{go-wasm-app/public/wasm → wasm/public}/wasm_exec.js +0 -0
@@ -1,47 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Static Fallback</title>
7
- <!-- Import Tailwind-like styles for quick styling -->
8
- <link href="https://cdn.jsdelivr.net/npm/daisyui@3.7.4/dist/full.css" rel="stylesheet" type="text/css" />
9
- <script src="https://cdn.tailwindcss.com"></script>
10
- <!-- Client-side script for hydration -->
11
- <script type="module" src="/src/client.tsx"></script>
12
- <style>
13
- body {
14
- font-family: sans-serif;
15
- max-width: 800px;
16
- margin: 0 auto;
17
- padding: 2rem;
18
- line-height: 1.6;
19
- }
20
- .warning {
21
- background-color: #fff3cd;
22
- border: 1px solid #ffecb5;
23
- color: #856404;
24
- padding: 1rem;
25
- border-radius: 4px;
26
- margin-bottom: 1rem;
27
- }
28
- code {
29
- background-color: #f5f5f5;
30
- padding: 0.2rem 0.4rem;
31
- border-radius: 3px;
32
- }
33
- </style>
34
- </head>
35
- <body>
36
- <!-- App will be rendered here by SSR -->
37
- <div id="app">
38
- <div class="warning">
39
- <h2>STATIC INDEX.HTML FILE</h2>
40
- <p>You should NOT be seeing this page if the server is running correctly.</p>
41
- <p>This is a static file that should only be used as a fallback when the server is not running.</p>
42
- <p>If you're seeing this while running <code>npm run dev</code>, there's likely an issue with the Express route handling.</p>
43
- <p>Try clearing your browser cache and refreshing the page.</p>
44
- </div>
45
- </div>
46
- </body>
47
- </html>
@@ -1,188 +0,0 @@
1
- # Frontend Hamroun SSR Template
2
-
3
- This is a comprehensive server-side rendering (SSR) example using Frontend Hamroun.
4
-
5
- ## Getting Started
6
-
7
- 1. Install dependencies:
8
- ```
9
- npm install
10
- ```
11
-
12
- 2. Start the server:
13
- ```
14
- npm start
15
- ```
16
-
17
- 3. Open your browser at http://localhost:3000
18
-
19
- ## Core Features
20
-
21
- This template demonstrates:
22
-
23
- ### Server-Side Rendering
24
- - Pre-rendering of components on the server
25
- - Hydration of server-rendered content on the client
26
- - Data fetching during server rendering
27
- - AI-powered meta tag generation
28
-
29
- ### Automatic File-Based Routing
30
- - Pages are automatically rendered based on their file path in the `pages` directory
31
- - For example:
32
- - `/pages/index.js` → `/` route
33
- - `/pages/about.js` → `/about` route
34
- - `/pages/blog/index.js` → `/blog` route
35
- - `/pages/users/[id].js` → `/users/:id` dynamic route
36
-
37
- ### API Integration
38
- - RESTful API endpoints
39
- - Dynamic API routing
40
- - API middleware for validation and security
41
- - File-based API structure
42
-
43
- ### Database Integration
44
- - MongoDB, MySQL, and PostgreSQL support
45
- - ORM-like query interface
46
- - Connection pooling
47
- - Transaction support
48
-
49
- ### Authentication & Authorization
50
- - JWT-based authentication
51
- - Role-based access control
52
- - Password hashing and validation
53
- - Token refresh mechanism
54
-
55
- ### Performance Optimization
56
- - Caching strategies
57
- - Response compression
58
- - Static asset optimization
59
- - Efficient metadata handling
60
-
61
- ## Implementation Examples
62
-
63
- ### Creating Components
64
-
65
- Use the `jsx` or `createElement` function from 'frontend-hamroun':
66
-
67
- ```jsx
68
- import { jsx } from 'frontend-hamroun';
69
-
70
- export default function MyComponent(props) {
71
- return jsx('div', { className: "container" }, [
72
- jsx('h1', {}, "Hello World"),
73
- jsx('p', {}, `Props value: ${props.value}`)
74
- ]);
75
- }
76
- ```
77
-
78
- ### Creating API Routes
79
-
80
- Create files in the `api` directory following this pattern:
81
-
82
- ```typescript
83
- // api/users/index.ts
84
- import { Request, Response } from 'express';
85
-
86
- export const get = (req: Request, res: Response) => {
87
- res.json({ users: [...] });
88
- };
89
-
90
- export const post = (req: Request, res: Response) => {
91
- // Create user
92
- res.status(201).json({ success: true });
93
- };
94
- ```
95
-
96
- ### Database Usage
97
-
98
- ```typescript
99
- import { Server } from 'frontend-hamroun/server';
100
-
101
- const server = new Server({
102
- db: {
103
- url: process.env.DATABASE_URL,
104
- type: 'mongodb' // or 'mysql', 'postgres'
105
- }
106
- });
107
-
108
- // Get typed database instance
109
- const db = server.getDatabase();
110
- const users = await db.query('SELECT * FROM users'); // For SQL
111
- const docs = await db.getMongoDb().collection('users').find().toArray(); // For MongoDB
112
- ```
113
-
114
- ### Authentication
115
-
116
- ```typescript
117
- import { AuthService } from 'frontend-hamroun/server';
118
-
119
- const auth = new AuthService({
120
- secret: process.env.JWT_SECRET,
121
- expiresIn: '24h'
122
- });
123
-
124
- // Protect routes
125
- app.get('/api/protected', auth.requireAuth(), (req, res) => {
126
- res.json({ message: "Authenticated!" });
127
- });
128
-
129
- // Create user & login
130
- const hashedPassword = await auth.hashPassword(password);
131
- const token = auth.generateToken(user);
132
- ```
133
-
134
- ### Advanced Middleware
135
-
136
- ```typescript
137
- import { rateLimit, requestLogger, errorHandler } from 'frontend-hamroun/server';
138
-
139
- app.use(requestLogger);
140
- app.use('/api', rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));
141
- app.use(errorHandler);
142
- ```
143
-
144
- ## File-Based Routing Examples
145
-
146
- ### Static Routes
147
- Create files in the `pages` directory:
148
-
149
- ```jsx
150
- // pages/index.js - Maps to "/"
151
- export default function HomePage() {
152
- return <h1>Home Page</h1>;
153
- }
154
-
155
- // pages/about.js - Maps to "/about"
156
- export default function AboutPage() {
157
- return <h1>About Us</h1>;
158
- }
159
-
160
- // pages/contact/index.js - Maps to "/contact"
161
- export default function ContactPage() {
162
- return <h1>Contact Us</h1>;
163
- }
164
- ```
165
-
166
- ### Dynamic Routes
167
- Use brackets in filenames to define dynamic parameters:
168
-
169
- ```jsx
170
- // pages/users/[id].js - Maps to "/users/:id"
171
- export default function UserPage({ params }) {
172
- return <h1>User Profile: {params.id}</h1>;
173
- }
174
-
175
- // pages/blog/[category]/[slug].js - Maps to "/blog/:category/:slug"
176
- export default function BlogPost({ params }) {
177
- return (
178
- <div>
179
- <h1>Blog Post: {params.slug}</h1>
180
- <p>Category: {params.category}</p>
181
- </div>
182
- );
183
- }
184
- ```
185
-
186
- ## Next Steps
187
-
188
- Explore the full API documentation for more advanced features and customization options.
@@ -1,369 +0,0 @@
1
- import express from 'express';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import fetch from 'node-fetch';
5
- import dotenv from 'dotenv';
6
- import fs from 'fs';
7
- import { renderToString } from 'frontend-hamroun/ssr';
8
-
9
- // Load environment variables
10
- dotenv.config();
11
-
12
- // Get __dirname equivalent in ESM
13
- const __filename = fileURLToPath(import.meta.url);
14
- const __dirname = path.dirname(__filename);
15
-
16
- // Initialize express app
17
- const app = express();
18
- const PORT = process.env.PORT || 3000;
19
-
20
- // Simple API endpoint
21
- app.get('/api/hello', (req, res) => {
22
- res.json({
23
- message: 'Hello from Server-Side API',
24
- time: new Date().toISOString()
25
- });
26
- });
27
-
28
- // Function to generate meta tags locally without requiring OpenAI
29
- function generateMetaTagsLocally(pageContent) {
30
- // Simple keyword extraction - get common meaningful words
31
- const keywordExtraction = (text) => {
32
- // Remove common words and extract potential keywords
33
- const commonWords = ['a', 'an', 'the', 'and', 'or', 'but', 'is', 'are', 'was', 'were',
34
- 'has', 'have', 'had', 'be', 'been', 'being', 'to', 'of', 'for', 'with', 'about', 'at'];
35
-
36
- const words = text.toLowerCase()
37
- .replace(/[^\w\s]/g, '') // Remove punctuation
38
- .split(/\s+/) // Split by whitespace
39
- .filter(word => word.length > 3 && !commonWords.includes(word)); // Filter short and common words
40
-
41
- // Count word frequency
42
- const wordCount = {};
43
- words.forEach(word => {
44
- wordCount[word] = (wordCount[word] || 0) + 1;
45
- });
46
-
47
- // Sort by frequency and get top keywords
48
- return Object.entries(wordCount)
49
- .sort((a, b) => b[1] - a[1])
50
- .slice(0, 5)
51
- .map(entry => entry[0])
52
- .join(', ');
53
- };
54
-
55
- // Extract main topic (first heading or first sentence)
56
- const getMainTopic = (text) => {
57
- const headingMatch = text.match(/<h1[^>]*>(.*?)<\/h1>/i) ||
58
- text.match(/<h2[^>]*>(.*?)<\/h2>/i);
59
-
60
- if (headingMatch) {
61
- return headingMatch[1].trim();
62
- }
63
-
64
- // If no heading, use first sentence
65
- const firstSentence = text.split(/[.!?]/).filter(s => s.trim().length > 0)[0];
66
- return firstSentence ? firstSentence.trim() : "Frontend Hamroun SSR Page";
67
- };
68
-
69
- // Generate description (first few sentences, truncated)
70
- const getDescription = (text) => {
71
- const plainText = text.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
72
- const sentences = plainText.split(/[.!?]/).filter(s => s.trim().length > 0);
73
- const description = sentences.slice(0, 2).join('. ');
74
-
75
- return description.length > 160
76
- ? description.substring(0, 157) + '...'
77
- : description;
78
- };
79
-
80
- // Generate the meta tags
81
- const title = getMainTopic(pageContent);
82
- const description = getDescription(pageContent);
83
- const keywords = keywordExtraction(pageContent);
84
-
85
- return {
86
- title: title || 'Frontend Hamroun SSR App',
87
- description: description || 'A server-side rendered application using Frontend Hamroun framework',
88
- keywords: keywords || 'ssr, javascript, frontend, hamroun, web development'
89
- };
90
- }
91
-
92
- // Function to generate meta tags - using Gemini with local fallback
93
- async function generateMetaTags(pageContent) {
94
- // Remove forcing local generation
95
- process.env.USE_LOCAL_GENERATION = 'false';
96
-
97
- // Check if local generation is forced
98
- if (process.env.USE_LOCAL_GENERATION === 'true') {
99
- console.log('Using local meta tag generation (forced by config)');
100
- return generateMetaTagsLocally(pageContent);
101
- }
102
-
103
- try {
104
- console.log('Attempting to generate meta tags with Gemini AI...');
105
- return await generateMetaTagsWithGemini(pageContent);
106
- } catch (error) {
107
- console.error('Error generating meta tags with Gemini, falling back to local generation:', error);
108
- return generateMetaTagsLocally(pageContent);
109
- }
110
- }
111
-
112
- // Function to generate meta tags using Google's Gemini API
113
- async function generateMetaTagsWithGemini(pageContent) {
114
- if (!process.env.GEMINI_API_KEY) {
115
- console.log('Gemini API key not found. Using local meta tag generation.');
116
- return generateMetaTagsLocally(pageContent);
117
- }
118
-
119
- try {
120
- console.log('Connecting to Gemini AI...');
121
- // Use the correct model as indicated in the working curl example
122
- const endpoints = [
123
- 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent'
124
- ];
125
-
126
- let response = null;
127
- let responseData = null;
128
-
129
- // Try the endpoint
130
- for (const url of endpoints) {
131
- try {
132
- console.log(`Trying Gemini endpoint: ${url}`);
133
-
134
- const requestBody = {
135
- contents: [{
136
- parts: [{
137
- text: `Generate SEO-friendly meta tags as JSON with the following format:
138
- {
139
- "title": "A concise and engaging title",
140
- "description": "A compelling description under 160 characters",
141
- "keywords": "keyword1, keyword2, keyword3, keyword4, keyword5"
142
- }
143
-
144
- The meta tags should be based on this content: ${pageContent}`
145
- }]
146
- }]
147
- };
148
-
149
- // Log the exact request for debugging
150
- console.log('Sending request to Gemini:', JSON.stringify(requestBody, null, 2).substring(0, 150) + '...');
151
-
152
- response = await fetch(`${url}?key=${process.env.GEMINI_API_KEY}`, {
153
- method: 'POST',
154
- headers: {
155
- 'Content-Type': 'application/json'
156
- },
157
- body: JSON.stringify(requestBody)
158
- });
159
-
160
- // Get the response data
161
- responseData = await response.text();
162
-
163
- // Try to parse it as JSON
164
- try {
165
- responseData = JSON.parse(responseData);
166
-
167
- if (response.ok) {
168
- console.log('Successfully received response from Gemini');
169
- break;
170
- } else {
171
- console.error('Gemini API error response:', responseData);
172
- }
173
- } catch (parseError) {
174
- console.error('Failed to parse Gemini response as JSON:', responseData.substring(0, 150));
175
- throw parseError;
176
- }
177
- } catch (err) {
178
- console.log(`Endpoint ${url} failed:`, err.message);
179
- }
180
- }
181
-
182
- if (!response || !response.ok) {
183
- throw new Error('Failed to get valid response from Gemini API');
184
- }
185
-
186
- // Extract the text response - using the correct response format for gemini-2.0-flash
187
- const textResponse = responseData.candidates[0].content.parts[0].text;
188
-
189
- // Extract the JSON object from the text response
190
- const jsonMatch = textResponse.match(/\{[\s\S]*\}/);
191
- if (!jsonMatch) {
192
- console.error('Could not find JSON in response:', textResponse);
193
- throw new Error('Could not parse JSON from Gemini response');
194
- }
195
-
196
- try {
197
- const metaTagsJson = jsonMatch[0];
198
- const metaTags = JSON.parse(metaTagsJson);
199
- console.log('Generated meta tags using Gemini:', metaTags);
200
-
201
- return metaTags;
202
- } catch (jsonError) {
203
- console.error('Failed to parse extracted JSON:', jsonMatch[0]);
204
- throw jsonError;
205
- }
206
- } catch (error) {
207
- console.error('Error generating meta tags with Gemini:', error);
208
- throw error;
209
- }
210
- }
211
-
212
- // Basic server-side rendering implementation
213
- app.get('/', async (req, res) => {
214
- console.log('Handling root route for SSR');
215
- try {
216
- // Create a simple virtual DOM tree
217
- const vnode = {
218
- type: 'div',
219
- props: {
220
- id: 'app',
221
- children: [
222
- {
223
- type: 'h1',
224
- props: {
225
- children: 'Hello from Server-Side Rendering!'
226
- }
227
- },
228
- {
229
- type: 'p',
230
- props: {
231
- children: `This page was rendered at ${new Date().toISOString()}`
232
- }
233
- },
234
- {
235
- type: 'button',
236
- props: {
237
- id: 'counter-btn',
238
- className: 'btn',
239
- children: 'Click me (0)'
240
- }
241
- }
242
- ]
243
- }
244
- };
245
-
246
- // Generate content for meta tag creation
247
- const contentForMetaTags = 'Server-side rendered page using Frontend Hamroun framework. ' +
248
- 'This demonstrates SSR capabilities with dynamic content generation and client-side hydration.';
249
-
250
- console.log('Fetching meta tags for the page...');
251
- const metaTags = await generateMetaTags(contentForMetaTags);
252
-
253
- // Generate HTML from our virtual node directly using imported renderToString
254
- const content = renderToString(vnode);
255
-
256
- // Send complete HTML document with explicit content type
257
- res.setHeader('Content-Type', 'text/html');
258
- res.send(`
259
- <!DOCTYPE html>
260
- <html>
261
- <head>
262
- <meta charset="UTF-8">
263
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
264
-
265
- <!-- AI Generated Meta Tags -->
266
- <title>${metaTags.title}</title>
267
- <meta name="description" content="${metaTags.description}">
268
- <meta name="keywords" content="${metaTags.keywords}">
269
-
270
- <!-- Open Graph tags -->
271
- <meta property="og:title" content="${metaTags.title}">
272
- <meta property="og:description" content="${metaTags.description}">
273
- <meta property="og:type" content="website">
274
- <meta property="og:url" content="${req.protocol}://${req.get('host')}${req.originalUrl}">
275
-
276
- <!-- Twitter Card tags -->
277
- <meta name="twitter:card" content="summary_large_image">
278
- <meta name="twitter:title" content="${metaTags.title}">
279
- <meta name="twitter:description" content="${metaTags.description}">
280
-
281
- <style>
282
- body {
283
- font-family: sans-serif;
284
- max-width: 800px;
285
- margin: 0 auto;
286
- padding: 2rem;
287
- }
288
- .btn {
289
- background-color: #4CAF50;
290
- border: none;
291
- color: white;
292
- padding: 10px 20px;
293
- cursor: pointer;
294
- border-radius: 4px;
295
- margin-top: 1rem;
296
- }
297
- </style>
298
- <script>
299
- // Simple client-side interactivity
300
- document.addEventListener('DOMContentLoaded', () => {
301
- const btn = document.getElementById('counter-btn');
302
- if (btn) {
303
- let count = 0;
304
- btn.addEventListener('click', () => {
305
- count++;
306
- btn.textContent = \`Click me (\${count})\`;
307
- });
308
- console.log('Button click handler attached');
309
- }
310
- });
311
- </script>
312
- </head>
313
- <body>${content || '<div>Error: No content generated</div>'}</body>
314
- </html>
315
- `);
316
- } catch (error) {
317
- console.error('SSR Error:', error);
318
-
319
- // Fallback HTML with error details
320
- res.status(500).send(`
321
- <!DOCTYPE html>
322
- <html>
323
- <head>
324
- <title>SSR Error</title>
325
- <style>
326
- body { font-family: sans-serif; padding: 2rem; }
327
- pre { background: #f5f5f5; padding: 1rem; overflow: auto; }
328
- </style>
329
- </head>
330
- <body>
331
- <h1>Server-Side Rendering Error</h1>
332
- <p>There was a problem rendering the page.</p>
333
- <pre>${error.stack}</pre>
334
- <p>Try refreshing the page or contact the administrator if the problem persists.</p>
335
- </body>
336
- </html>
337
- `);
338
- }
339
- });
340
-
341
- // Serve static files AFTER routes that need SSR
342
- app.use(express.static(path.join(__dirname, 'public')));
343
-
344
- // A catch-all route for any other requests
345
- app.get('*', (req, res) => {
346
- console.log(`Handling catch-all route: ${req.path}`);
347
- res.status(404).send(`
348
- <!DOCTYPE html>
349
- <html>
350
- <head>
351
- <title>Page Not Found</title>
352
- <style>
353
- body { font-family: sans-serif; padding: 2rem; }
354
- </style>
355
- </head>
356
- <body>
357
- <h1>Page Not Found</h1>
358
- <p>The page you requested does not exist.</p>
359
- <p><a href="/">Go to home page</a></p>
360
- </body>
361
- </html>
362
- `);
363
- });
364
-
365
- // Start the server
366
- app.listen(PORT, () => {
367
- console.log(`Server running at http://localhost:${PORT}`);
368
- console.log(`Open your browser and navigate to http://localhost:${PORT}`);
369
- });