frontend-hamroun 1.2.27 → 1.2.29
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 +7 -0
- package/bin/banner.js +0 -0
- package/bin/cli-utils.js +0 -0
- package/bin/cli.js +536 -598
- package/package.json +1 -1
- package/templates/fullstack-app/README.md +37 -0
- package/templates/fullstack-app/build/main.css +664 -0
- package/templates/fullstack-app/build/main.css.map +7 -0
- package/templates/fullstack-app/build/main.js +682 -0
- package/templates/fullstack-app/build/main.js.map +7 -0
- package/templates/fullstack-app/build.ts +211 -0
- package/templates/fullstack-app/index.html +26 -3
- package/templates/fullstack-app/package-lock.json +2402 -438
- package/templates/fullstack-app/package.json +24 -9
- package/templates/fullstack-app/postcss.config.js +6 -0
- package/templates/fullstack-app/process-tailwind.js +45 -0
- package/templates/fullstack-app/public/_redirects +1 -0
- package/templates/fullstack-app/public/route-handler.js +47 -0
- package/templates/fullstack-app/public/spa-fix.html +17 -0
- package/templates/fullstack-app/public/styles.css +768 -0
- package/templates/fullstack-app/public/tailwind.css +15 -0
- package/templates/fullstack-app/server.js +101 -44
- package/templates/fullstack-app/server.ts +402 -39
- package/templates/fullstack-app/src/README.md +55 -0
- package/templates/fullstack-app/src/client.js +83 -16
- package/templates/fullstack-app/src/components/Layout.tsx +45 -0
- package/templates/fullstack-app/src/components/UserList.tsx +27 -0
- package/templates/fullstack-app/src/config.ts +42 -0
- package/templates/fullstack-app/src/data/api.ts +71 -0
- package/templates/fullstack-app/src/main.tsx +219 -7
- package/templates/fullstack-app/src/pages/about/index.tsx +67 -0
- package/templates/fullstack-app/src/pages/index.tsx +30 -60
- package/templates/fullstack-app/src/pages/users.tsx +60 -0
- package/templates/fullstack-app/src/router.ts +255 -0
- package/templates/fullstack-app/src/styles.css +5 -0
- package/templates/fullstack-app/tailwind.config.js +11 -0
- package/templates/fullstack-app/tsconfig.json +18 -0
- package/templates/fullstack-app/vite.config.js +53 -6
- package/templates/ssr-template/readme.md +50 -0
- package/templates/ssr-template/src/client.ts +46 -14
- package/templates/ssr-template/src/server.ts +190 -18
@@ -0,0 +1,682 @@
|
|
1
|
+
var __defProp = Object.defineProperty;
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
3
|
+
var __glob = (map) => (path) => {
|
4
|
+
var fn = map[path];
|
5
|
+
if (fn)
|
6
|
+
return fn();
|
7
|
+
throw new Error("Module not found in bundle: " + path);
|
8
|
+
};
|
9
|
+
var __esm = (fn, res) => function __init() {
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
11
|
+
};
|
12
|
+
var __export = (target, all) => {
|
13
|
+
for (var name in all)
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
15
|
+
};
|
16
|
+
|
17
|
+
// node_modules/frontend-hamroun/dist/index.mjs
|
18
|
+
function batchUpdates(fn) {
|
19
|
+
if (isBatching) {
|
20
|
+
queue.push(fn);
|
21
|
+
return;
|
22
|
+
}
|
23
|
+
isBatching = true;
|
24
|
+
try {
|
25
|
+
fn();
|
26
|
+
while (queue.length > 0) {
|
27
|
+
const nextFn = queue.shift();
|
28
|
+
nextFn == null ? void 0 : nextFn();
|
29
|
+
}
|
30
|
+
} finally {
|
31
|
+
isBatching = false;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
function setRenderCallback(callback, element, container) {
|
35
|
+
globalRenderCallback = callback;
|
36
|
+
globalContainer = container;
|
37
|
+
currentElement = element;
|
38
|
+
}
|
39
|
+
function prepareRender() {
|
40
|
+
currentRender++;
|
41
|
+
stateIndices.set(currentRender, 0);
|
42
|
+
return currentRender;
|
43
|
+
}
|
44
|
+
function finishRender() {
|
45
|
+
if (isServer) {
|
46
|
+
serverStates.delete(currentRender);
|
47
|
+
}
|
48
|
+
currentRender = 0;
|
49
|
+
}
|
50
|
+
function jsx(type, props) {
|
51
|
+
console.log("JSX Transform:", { type, props });
|
52
|
+
const processedProps = { ...props };
|
53
|
+
if (arguments.length > 2) {
|
54
|
+
processedProps.children = Array.prototype.slice.call(arguments, 2);
|
55
|
+
}
|
56
|
+
return { type, props: processedProps };
|
57
|
+
}
|
58
|
+
async function createElement(vnode) {
|
59
|
+
var _a;
|
60
|
+
console.log("Creating element from:", vnode);
|
61
|
+
if (vnode == null) {
|
62
|
+
return document.createTextNode("");
|
63
|
+
}
|
64
|
+
if (typeof vnode === "boolean") {
|
65
|
+
return document.createTextNode("");
|
66
|
+
}
|
67
|
+
if (typeof vnode === "number" || typeof vnode === "string") {
|
68
|
+
return document.createTextNode(String(vnode));
|
69
|
+
}
|
70
|
+
if (Array.isArray(vnode)) {
|
71
|
+
const fragment = document.createDocumentFragment();
|
72
|
+
for (const child of vnode) {
|
73
|
+
const node = await createElement(child);
|
74
|
+
fragment.appendChild(node);
|
75
|
+
}
|
76
|
+
return fragment;
|
77
|
+
}
|
78
|
+
if ("type" in vnode && vnode.props !== void 0) {
|
79
|
+
const { type, props } = vnode;
|
80
|
+
if (typeof type === "function") {
|
81
|
+
try {
|
82
|
+
const result = await type(props || {});
|
83
|
+
const node = await createElement(result);
|
84
|
+
if (node instanceof Element) {
|
85
|
+
node.setAttribute("data-component-id", type.name || type.toString());
|
86
|
+
}
|
87
|
+
return node;
|
88
|
+
} catch (error) {
|
89
|
+
console.error("Error rendering component:", error);
|
90
|
+
return document.createTextNode("");
|
91
|
+
}
|
92
|
+
}
|
93
|
+
const element = document.createElement(type);
|
94
|
+
for (const [key, value] of Object.entries(props || {})) {
|
95
|
+
if (key === "children")
|
96
|
+
continue;
|
97
|
+
if (key.startsWith("on") && typeof value === "function") {
|
98
|
+
const eventName = key.toLowerCase().slice(2);
|
99
|
+
const existingHandler = (_a = element.__events) == null ? void 0 : _a[eventName];
|
100
|
+
if (existingHandler) {
|
101
|
+
element.removeEventListener(eventName, existingHandler);
|
102
|
+
}
|
103
|
+
element.addEventListener(eventName, value);
|
104
|
+
if (!element.__events) {
|
105
|
+
element.__events = {};
|
106
|
+
}
|
107
|
+
element.__events[eventName] = value;
|
108
|
+
} else if (key === "style" && typeof value === "object") {
|
109
|
+
Object.assign(element.style, value);
|
110
|
+
} else if (key === "className") {
|
111
|
+
element.setAttribute("class", String(value));
|
112
|
+
} else if (key !== "key" && key !== "ref") {
|
113
|
+
element.setAttribute(key, String(value));
|
114
|
+
}
|
115
|
+
}
|
116
|
+
const children = props == null ? void 0 : props.children;
|
117
|
+
if (children != null) {
|
118
|
+
const childArray = Array.isArray(children) ? children.flat() : [children];
|
119
|
+
for (const child of childArray) {
|
120
|
+
const childNode = await createElement(child);
|
121
|
+
element.appendChild(childNode);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
return element;
|
125
|
+
}
|
126
|
+
return document.createTextNode(String(vnode));
|
127
|
+
}
|
128
|
+
async function hydrate(element, container) {
|
129
|
+
isHydrating = true;
|
130
|
+
try {
|
131
|
+
await render(element, container);
|
132
|
+
} finally {
|
133
|
+
isHydrating = false;
|
134
|
+
}
|
135
|
+
}
|
136
|
+
async function render(element, container) {
|
137
|
+
console.log("Rendering to:", container.id);
|
138
|
+
batchUpdates(async () => {
|
139
|
+
const rendererId = prepareRender();
|
140
|
+
try {
|
141
|
+
setRenderCallback(render, element, container);
|
142
|
+
const domNode = await createElement(element);
|
143
|
+
if (!isHydrating) {
|
144
|
+
container.innerHTML = "";
|
145
|
+
}
|
146
|
+
container.appendChild(domNode);
|
147
|
+
} finally {
|
148
|
+
finishRender();
|
149
|
+
}
|
150
|
+
});
|
151
|
+
}
|
152
|
+
var isBatching, queue, currentRender, stateIndices, globalRenderCallback, globalContainer, currentElement, isServer, serverStates, isHydrating;
|
153
|
+
var init_dist = __esm({
|
154
|
+
"node_modules/frontend-hamroun/dist/index.mjs"() {
|
155
|
+
isBatching = false;
|
156
|
+
queue = [];
|
157
|
+
currentRender = 0;
|
158
|
+
stateIndices = /* @__PURE__ */ new Map();
|
159
|
+
globalRenderCallback = null;
|
160
|
+
globalContainer = null;
|
161
|
+
currentElement = null;
|
162
|
+
isServer = typeof window === "undefined";
|
163
|
+
serverStates = /* @__PURE__ */ new Map();
|
164
|
+
isHydrating = false;
|
165
|
+
}
|
166
|
+
});
|
167
|
+
|
168
|
+
// src/config.ts
|
169
|
+
var AppConfig, config_default;
|
170
|
+
var init_config = __esm({
|
171
|
+
"src/config.ts"() {
|
172
|
+
"use strict";
|
173
|
+
AppConfig = {
|
174
|
+
// App information
|
175
|
+
title: "Frontend Hamroun App",
|
176
|
+
description: "A full-stack application built with Frontend Hamroun",
|
177
|
+
// Navigation
|
178
|
+
navigation: [
|
179
|
+
{ path: "/", label: "Home" },
|
180
|
+
{ path: "/about", label: "About" },
|
181
|
+
{ path: "/users", label: "Users" }
|
182
|
+
],
|
183
|
+
// API endpoints
|
184
|
+
api: {
|
185
|
+
baseUrl: "/api",
|
186
|
+
endpoints: {
|
187
|
+
users: "/users",
|
188
|
+
posts: "/posts"
|
189
|
+
}
|
190
|
+
},
|
191
|
+
// Default meta tags
|
192
|
+
meta: {
|
193
|
+
viewport: "width=device-width, initial-scale=1.0",
|
194
|
+
charset: "UTF-8",
|
195
|
+
author: "Your Name",
|
196
|
+
keywords: "frontend-hamroun, fullstack, template"
|
197
|
+
},
|
198
|
+
// Style customization
|
199
|
+
theme: {
|
200
|
+
primaryColor: "#0066cc",
|
201
|
+
backgroundColor: "#ffffff",
|
202
|
+
textColor: "#333333",
|
203
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif'
|
204
|
+
}
|
205
|
+
};
|
206
|
+
config_default = AppConfig;
|
207
|
+
}
|
208
|
+
});
|
209
|
+
|
210
|
+
// src/components/Layout.tsx
|
211
|
+
function Layout({ children, title = config_default.title, showNavigation = true }) {
|
212
|
+
const { navigation } = config_default;
|
213
|
+
return /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4 py-8 max-w-5xl" }, /* @__PURE__ */ jsx("header", { className: "mb-8" }, /* @__PURE__ */ jsx("h1", { className: "text-4xl font-bold text-gray-800 mb-4" }, title), showNavigation && /* @__PURE__ */ jsx("nav", { className: "mb-6" }, /* @__PURE__ */ jsx("ul", { className: "flex space-x-6" }, navigation.map((item) => /* @__PURE__ */ jsx("li", { key: item.path }, /* @__PURE__ */ jsx(
|
214
|
+
"a",
|
215
|
+
{
|
216
|
+
href: item.path,
|
217
|
+
className: "text-blue-600 hover:text-blue-800 hover:underline transition-colors font-medium"
|
218
|
+
},
|
219
|
+
item.label
|
220
|
+
)))))), /* @__PURE__ */ jsx("main", { className: "min-h-[50vh]" }, children), /* @__PURE__ */ jsx("footer", { className: "mt-12 pt-6 border-t border-gray-200 text-gray-600 text-sm" }, /* @__PURE__ */ jsx("p", null, config_default.title, " \xA9 ", (/* @__PURE__ */ new Date()).getFullYear())));
|
221
|
+
}
|
222
|
+
var init_Layout = __esm({
|
223
|
+
"src/components/Layout.tsx"() {
|
224
|
+
"use strict";
|
225
|
+
init_dist();
|
226
|
+
init_config();
|
227
|
+
}
|
228
|
+
});
|
229
|
+
|
230
|
+
// src/pages/about/index.tsx
|
231
|
+
var about_exports = {};
|
232
|
+
__export(about_exports, {
|
233
|
+
default: () => about_default
|
234
|
+
});
|
235
|
+
var AboutPage, about_default;
|
236
|
+
var init_about = __esm({
|
237
|
+
"src/pages/about/index.tsx"() {
|
238
|
+
"use strict";
|
239
|
+
init_dist();
|
240
|
+
init_Layout();
|
241
|
+
AboutPage = ({ initialState: initialState2 }) => {
|
242
|
+
return /* @__PURE__ */ jsx(Layout, { title: "About This App" }, /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto bg-white shadow-lg rounded-lg overflow-hidden" }, /* @__PURE__ */ jsx("div", { className: "p-8" }, /* @__PURE__ */ jsx("p", { className: "text-lg text-gray-700 mb-6" }, "This is a frontend application built with Frontend Hamroun framework and styled with Tailwind CSS."), /* @__PURE__ */ jsx("p", { className: "text-gray-600 mb-8" }, "It features server-side rendering, client-side navigation, and websocket-based live reloading during development."), /* @__PURE__ */ jsx("div", { className: "bg-gray-50 p-6 rounded-lg border border-gray-200 mb-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "Key Features"), /* @__PURE__ */ jsx("ul", { className: "space-y-2 text-gray-700" }, /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Server-side rendering"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Client-side navigation"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Component-based architecture"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Integrated API backend"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Live reload during development"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Tailwind CSS for styling"))), /* @__PURE__ */ jsx("a", { href: "/", className: "inline-block px-6 py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors" }, "Back to Home"))));
|
243
|
+
};
|
244
|
+
about_default = AboutPage;
|
245
|
+
}
|
246
|
+
});
|
247
|
+
|
248
|
+
// src/components/UserList.tsx
|
249
|
+
var UserList, UserList_default;
|
250
|
+
var init_UserList = __esm({
|
251
|
+
"src/components/UserList.tsx"() {
|
252
|
+
"use strict";
|
253
|
+
init_dist();
|
254
|
+
UserList = ({ users }) => {
|
255
|
+
if (!users || users.length === 0) {
|
256
|
+
return /* @__PURE__ */ jsx("div", { className: "p-4 bg-gray-50 rounded-lg border border-gray-200 my-4" }, /* @__PURE__ */ jsx("p", { className: "text-gray-500 italic" }, "No users found or still loading..."));
|
257
|
+
}
|
258
|
+
return /* @__PURE__ */ jsx("div", { className: "rounded-lg overflow-hidden my-4" }, /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium mb-3" }, "Users (", users.length, ")"), /* @__PURE__ */ jsx("ul", { className: "divide-y divide-gray-200 border border-gray-200 rounded-lg overflow-hidden" }, users.map((user) => /* @__PURE__ */ jsx("li", { key: user.id, className: "flex justify-between items-center p-4 hover:bg-gray-50" }, /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-800" }, user.name), /* @__PURE__ */ jsx("span", { className: "text-gray-500 text-sm" }, user.email)))));
|
259
|
+
};
|
260
|
+
UserList_default = UserList;
|
261
|
+
}
|
262
|
+
});
|
263
|
+
|
264
|
+
// src/data/api.ts
|
265
|
+
async function fetchApi(endpoint, options = {}) {
|
266
|
+
const url = endpoint.startsWith("/") ? `/api${endpoint}` : `/api/${endpoint}`;
|
267
|
+
try {
|
268
|
+
console.log(`[API] Fetching data from: ${url}`);
|
269
|
+
const response = await fetch(url, {
|
270
|
+
headers: {
|
271
|
+
"Content-Type": "application/json",
|
272
|
+
"Accept": "application/json"
|
273
|
+
},
|
274
|
+
...options
|
275
|
+
});
|
276
|
+
if (!response.ok) {
|
277
|
+
throw new Error(`API request failed: ${response.status} ${response.statusText}`);
|
278
|
+
}
|
279
|
+
const data = await response.json();
|
280
|
+
console.log(`[API] Successfully fetched data from: ${url}`);
|
281
|
+
return data;
|
282
|
+
} catch (error) {
|
283
|
+
console.error(`[API] Error fetching from ${url}:`, error);
|
284
|
+
return null;
|
285
|
+
}
|
286
|
+
}
|
287
|
+
var UserApi;
|
288
|
+
var init_api = __esm({
|
289
|
+
"src/data/api.ts"() {
|
290
|
+
"use strict";
|
291
|
+
UserApi = {
|
292
|
+
getAll: () => fetchApi("/users"),
|
293
|
+
getById: (id) => fetchApi(`/users/${id}`),
|
294
|
+
create: (data) => fetchApi("/users", {
|
295
|
+
method: "POST",
|
296
|
+
body: JSON.stringify(data)
|
297
|
+
}),
|
298
|
+
update: (id, data) => fetchApi(`/users/${id}`, {
|
299
|
+
method: "PUT",
|
300
|
+
body: JSON.stringify(data)
|
301
|
+
}),
|
302
|
+
delete: (id) => fetchApi(`/users/${id}`, {
|
303
|
+
method: "DELETE"
|
304
|
+
})
|
305
|
+
};
|
306
|
+
}
|
307
|
+
});
|
308
|
+
|
309
|
+
// src/pages/index.tsx
|
310
|
+
var pages_exports = {};
|
311
|
+
__export(pages_exports, {
|
312
|
+
default: () => pages_default
|
313
|
+
});
|
314
|
+
var HomePage, pages_default;
|
315
|
+
var init_pages = __esm({
|
316
|
+
"src/pages/index.tsx"() {
|
317
|
+
"use strict";
|
318
|
+
init_dist();
|
319
|
+
init_Layout();
|
320
|
+
init_UserList();
|
321
|
+
init_api();
|
322
|
+
HomePage = ({ initialState: initialState2 }) => /* @__PURE__ */ jsx(Layout, { title: "Home" }, /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto py-8" }, /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-blue-600 mb-6" }, "Welcome to your Frontend Hamroun application!"), /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6 mb-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "User List"), /* @__PURE__ */ jsx(UserList_default, { users: initialState2.data?.users || [] })), /* @__PURE__ */ jsx("div", { className: "bg-gray-50 rounded-lg p-6 border border-gray-200" }, /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-gray-700 mb-3" }, "Application State"), /* @__PURE__ */ jsx("pre", { className: "overflow-auto p-4 bg-gray-100 rounded-md text-sm text-gray-800" }, JSON.stringify(initialState2, null, 2)))));
|
323
|
+
HomePage.getInitialData = async () => {
|
324
|
+
return {
|
325
|
+
users: await UserApi.getAll()
|
326
|
+
};
|
327
|
+
};
|
328
|
+
pages_default = HomePage;
|
329
|
+
}
|
330
|
+
});
|
331
|
+
|
332
|
+
// src/pages/users.tsx
|
333
|
+
var users_exports = {};
|
334
|
+
__export(users_exports, {
|
335
|
+
default: () => users_default
|
336
|
+
});
|
337
|
+
var UsersPage, users_default;
|
338
|
+
var init_users = __esm({
|
339
|
+
"src/pages/users.tsx"() {
|
340
|
+
"use strict";
|
341
|
+
init_dist();
|
342
|
+
init_Layout();
|
343
|
+
init_api();
|
344
|
+
UsersPage = ({ initialState: initialState2 }) => {
|
345
|
+
const users = initialState2.data?.users || [];
|
346
|
+
return /* @__PURE__ */ jsx(Layout, { title: "User Management" }, /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto" }, /* @__PURE__ */ jsx("div", { className: "bg-blue-50 p-6 rounded-lg mb-8 border border-blue-100" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-blue-800 mb-2" }, "Data Fetching Demo"), /* @__PURE__ */ jsx("p", { className: "text-blue-700" }, "This page demonstrates dynamic data fetching with the Users API.")), /* @__PURE__ */ jsx("div", { className: "bg-white shadow-md rounded-lg overflow-hidden" }, /* @__PURE__ */ jsx("div", { className: "px-6 py-4 border-b border-gray-200" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800" }, "User List")), users.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-6 text-center text-gray-500" }, /* @__PURE__ */ jsx("p", null, "No users found.")) : /* @__PURE__ */ jsx("div", { className: "overflow-x-auto" }, /* @__PURE__ */ jsx("table", { className: "w-full" }, /* @__PURE__ */ jsx("thead", null, /* @__PURE__ */ jsx("tr", { className: "bg-gray-50" }, /* @__PURE__ */ jsx("th", { className: "text-left py-3 px-6 font-medium text-gray-600 text-sm uppercase tracking-wider border-b" }, "ID"), /* @__PURE__ */ jsx("th", { className: "text-left py-3 px-6 font-medium text-gray-600 text-sm uppercase tracking-wider border-b" }, "Name"), /* @__PURE__ */ jsx("th", { className: "text-left py-3 px-6 font-medium text-gray-600 text-sm uppercase tracking-wider border-b" }, "Email"))), /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-gray-200" }, users.map((user) => /* @__PURE__ */ jsx("tr", { key: user.id, className: "hover:bg-gray-50" }, /* @__PURE__ */ jsx("td", { className: "py-4 px-6 text-sm text-gray-900" }, user.id), /* @__PURE__ */ jsx("td", { className: "py-4 px-6 text-sm font-medium text-gray-900" }, user.name), /* @__PURE__ */ jsx("td", { className: "py-4 px-6 text-sm text-gray-500" }, user.email)))))))));
|
347
|
+
};
|
348
|
+
UsersPage.getInitialData = async () => {
|
349
|
+
return {
|
350
|
+
users: await UserApi.getAll()
|
351
|
+
};
|
352
|
+
};
|
353
|
+
users_default = UsersPage;
|
354
|
+
}
|
355
|
+
});
|
356
|
+
|
357
|
+
// src/main.tsx
|
358
|
+
init_dist();
|
359
|
+
|
360
|
+
// src/router.ts
|
361
|
+
init_dist();
|
362
|
+
|
363
|
+
// import("./pages/**/*.tsx") in src/router.ts
|
364
|
+
var globImport_pages_tsx = __glob({
|
365
|
+
"./pages/about/index.tsx": () => Promise.resolve().then(() => (init_about(), about_exports)),
|
366
|
+
"./pages/index.tsx": () => Promise.resolve().then(() => (init_pages(), pages_exports)),
|
367
|
+
"./pages/users.tsx": () => Promise.resolve().then(() => (init_users(), users_exports))
|
368
|
+
});
|
369
|
+
|
370
|
+
// import("./pages/**/*/index.tsx") in src/router.ts
|
371
|
+
var globImport_pages_index_tsx = __glob({
|
372
|
+
"./pages/about/index.tsx": () => Promise.resolve().then(() => (init_about(), about_exports))
|
373
|
+
});
|
374
|
+
|
375
|
+
// src/router.ts
|
376
|
+
var Router = class {
|
377
|
+
constructor() {
|
378
|
+
this.routes = {};
|
379
|
+
this.notFoundComponent = null;
|
380
|
+
}
|
381
|
+
// Register a component for a specific route
|
382
|
+
register(path, component) {
|
383
|
+
const normalizedPath = path === "/" ? "index" : path.replace(/^\//, "");
|
384
|
+
this.routes[normalizedPath] = component;
|
385
|
+
console.log(`[Router] Registered component for path: ${normalizedPath}`);
|
386
|
+
return this;
|
387
|
+
}
|
388
|
+
// Set the not found component
|
389
|
+
setNotFound(component) {
|
390
|
+
this.notFoundComponent = component;
|
391
|
+
return this;
|
392
|
+
}
|
393
|
+
// Get the not found component
|
394
|
+
getNotFound() {
|
395
|
+
return this.notFoundComponent;
|
396
|
+
}
|
397
|
+
// Get all registered routes
|
398
|
+
getAllRoutes() {
|
399
|
+
return this.routes;
|
400
|
+
}
|
401
|
+
// Find component for a given path
|
402
|
+
async resolve(path) {
|
403
|
+
const normalizedPath = path === "/" ? "index" : path.replace(/^\//, "");
|
404
|
+
console.log(`[Router] Resolving component for path: ${normalizedPath}`);
|
405
|
+
if (this.routes[normalizedPath]) {
|
406
|
+
return this.routes[normalizedPath];
|
407
|
+
}
|
408
|
+
const pathSegments = normalizedPath.split("/");
|
409
|
+
const registeredRoutes = Object.keys(this.routes);
|
410
|
+
for (const route of registeredRoutes) {
|
411
|
+
const routeSegments = route.split("/");
|
412
|
+
if (routeSegments.length !== pathSegments.length)
|
413
|
+
continue;
|
414
|
+
let isMatch = true;
|
415
|
+
const params = {};
|
416
|
+
for (let i = 0; i < routeSegments.length; i++) {
|
417
|
+
const routeSegment = routeSegments[i];
|
418
|
+
const pathSegment = pathSegments[i];
|
419
|
+
if (routeSegment.startsWith("[") && routeSegment.endsWith("]")) {
|
420
|
+
const paramName = routeSegment.slice(1, -1);
|
421
|
+
params[paramName] = pathSegment;
|
422
|
+
} else if (routeSegment !== pathSegment) {
|
423
|
+
isMatch = false;
|
424
|
+
break;
|
425
|
+
}
|
426
|
+
}
|
427
|
+
if (isMatch) {
|
428
|
+
console.log(`[Router] Found dynamic route match: ${route}`);
|
429
|
+
return this.routes[route];
|
430
|
+
}
|
431
|
+
}
|
432
|
+
try {
|
433
|
+
let component = null;
|
434
|
+
let resolvedPath = normalizedPath;
|
435
|
+
try {
|
436
|
+
try {
|
437
|
+
console.log(`[Router] Trying direct import: ./pages/${resolvedPath}.tsx`);
|
438
|
+
const directModule = await /* @vite-ignore */
|
439
|
+
globImport_pages_tsx(`./pages/${resolvedPath}.tsx`).catch(() => null);
|
440
|
+
if (directModule) {
|
441
|
+
component = directModule.default || directModule;
|
442
|
+
}
|
443
|
+
} catch (e) {
|
444
|
+
console.warn(`[Router] Error importing ./pages/${resolvedPath}.tsx:`, e);
|
445
|
+
}
|
446
|
+
if (!component && !resolvedPath.endsWith("index")) {
|
447
|
+
try {
|
448
|
+
console.log(`[Router] Trying index file: ./pages/${resolvedPath}/index.tsx`);
|
449
|
+
const indexModule = await /* @vite-ignore */
|
450
|
+
globImport_pages_index_tsx(`./pages/${resolvedPath}/index.tsx`).catch(() => null);
|
451
|
+
if (indexModule) {
|
452
|
+
component = indexModule.default || indexModule;
|
453
|
+
}
|
454
|
+
} catch (e) {
|
455
|
+
console.warn(`[Router] Error importing ./pages/${resolvedPath}/index.tsx:`, e);
|
456
|
+
}
|
457
|
+
}
|
458
|
+
} catch (routeError) {
|
459
|
+
console.warn(`[Router] Error resolving Next.js style route:`, routeError);
|
460
|
+
}
|
461
|
+
if (component) {
|
462
|
+
this.routes[normalizedPath] = component;
|
463
|
+
return component;
|
464
|
+
}
|
465
|
+
} catch (error) {
|
466
|
+
console.warn(`[Router] Error importing component for ${normalizedPath}:`, error);
|
467
|
+
}
|
468
|
+
console.warn(`[Router] No component found for path: ${normalizedPath}`);
|
469
|
+
return this.notFoundComponent;
|
470
|
+
}
|
471
|
+
// Auto-discover components in the pages directory
|
472
|
+
async discoverRoutes() {
|
473
|
+
console.log("[Router] Auto-discovering routes from pages directory...");
|
474
|
+
try {
|
475
|
+
await this.tryLoadCoreRoutes();
|
476
|
+
console.log("[Router] Route discovery complete. Available routes:", Object.keys(this.routes));
|
477
|
+
return this.routes;
|
478
|
+
} catch (error) {
|
479
|
+
console.error("[Router] Error discovering routes:", error);
|
480
|
+
await this.tryLoadCoreRoutes();
|
481
|
+
return this.routes;
|
482
|
+
}
|
483
|
+
}
|
484
|
+
// Fallback method to load core routes
|
485
|
+
async tryLoadCoreRoutes() {
|
486
|
+
const pageModules = [
|
487
|
+
{ path: "./pages/index", route: "index" },
|
488
|
+
{ path: "./pages/about/index", route: "about" },
|
489
|
+
{ path: "./pages/users", route: "users" }
|
490
|
+
];
|
491
|
+
for (const { path, route } of pageModules) {
|
492
|
+
if (!this.routes[route]) {
|
493
|
+
try {
|
494
|
+
console.log(`[Router] Attempting to load route: ${route}`);
|
495
|
+
const module = await import(
|
496
|
+
/* @vite-ignore */
|
497
|
+
`${path}.tsx`
|
498
|
+
).catch(() => null);
|
499
|
+
if (module && module.default) {
|
500
|
+
this.routes[route] = module.default;
|
501
|
+
console.log(`[Router] Registered route: ${route}`);
|
502
|
+
}
|
503
|
+
} catch (error) {
|
504
|
+
console.warn(`[Router] Could not load route: ${route}`, error);
|
505
|
+
}
|
506
|
+
}
|
507
|
+
}
|
508
|
+
}
|
509
|
+
};
|
510
|
+
var router = new Router();
|
511
|
+
var NotFound = ({ initialState: initialState2 }) => {
|
512
|
+
return jsx("div", { className: "container mx-auto px-4 py-12 max-w-4xl" }, [
|
513
|
+
jsx("div", { className: "bg-white shadow-lg rounded-lg overflow-hidden p-8" }, [
|
514
|
+
jsx("h1", { className: "text-3xl font-bold text-gray-800 mb-4" }, ["Page Not Found"]),
|
515
|
+
jsx("p", { className: "text-gray-600 mb-6" }, [`No component found for path: ${initialState2?.route || "unknown"}`]),
|
516
|
+
jsx("a", { href: "/", className: "text-blue-600 hover:text-blue-800 hover:underline transition-colors" }, ["Go to Home"]),
|
517
|
+
jsx("div", { className: "mt-8 p-6 bg-gray-50 rounded-lg border border-gray-200" }, [
|
518
|
+
jsx("h3", { className: "text-lg font-medium text-gray-700 mb-3" }, ["Available Routes"]),
|
519
|
+
jsx("ul", { className: "space-y-2" }, [
|
520
|
+
jsx("li", {}, [jsx("a", { href: "/", className: "text-blue-600 hover:text-blue-800 hover:underline" }, ["Home"])]),
|
521
|
+
jsx("li", {}, [jsx("a", { href: "/about", className: "text-blue-600 hover:text-blue-800 hover:underline" }, ["About"])]),
|
522
|
+
jsx("li", {}, [jsx("a", { href: "/users", className: "text-blue-600 hover:text-blue-800 hover:underline" }, ["Users"])])
|
523
|
+
])
|
524
|
+
])
|
525
|
+
])
|
526
|
+
]);
|
527
|
+
};
|
528
|
+
router.setNotFound(NotFound);
|
529
|
+
|
530
|
+
// src/main.tsx
|
531
|
+
init_pages();
|
532
|
+
init_about();
|
533
|
+
init_users();
|
534
|
+
var isHydrating2 = document.getElementById("root")?.innerHTML.trim() !== "";
|
535
|
+
console.log("[Client] Running client-side code. Hydration state:", isHydrating2);
|
536
|
+
var initialState = window.__INITIAL_STATE__ || {
|
537
|
+
route: window.location.pathname,
|
538
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
539
|
+
serverRendered: false,
|
540
|
+
data: {
|
541
|
+
users: null,
|
542
|
+
posts: null
|
543
|
+
}
|
544
|
+
};
|
545
|
+
console.log("[Client] Initial state:", initialState);
|
546
|
+
async function fetchData(path) {
|
547
|
+
try {
|
548
|
+
console.log(`[Client] Fetching data from API: ${path}`);
|
549
|
+
const response = await fetch(`/api${path}`);
|
550
|
+
if (!response.ok) {
|
551
|
+
throw new Error(`API request failed: ${response.status}`);
|
552
|
+
}
|
553
|
+
const data = await response.json();
|
554
|
+
console.log(`[Client] Received data:`, data);
|
555
|
+
return data;
|
556
|
+
} catch (error) {
|
557
|
+
console.error(`[Client] Error fetching data from ${path}:`, error);
|
558
|
+
return null;
|
559
|
+
}
|
560
|
+
}
|
561
|
+
function initializeRouter() {
|
562
|
+
console.log("[Client] Initializing router with known pages");
|
563
|
+
router.register("index", pages_default);
|
564
|
+
router.register("about", about_default);
|
565
|
+
router.register("users", users_default);
|
566
|
+
}
|
567
|
+
initializeRouter();
|
568
|
+
async function renderApp() {
|
569
|
+
try {
|
570
|
+
const currentPath = window.location.pathname;
|
571
|
+
console.log(`[Client] Rendering for path: ${currentPath}`);
|
572
|
+
const rootElement = document.getElementById("root");
|
573
|
+
if (!rootElement) {
|
574
|
+
console.error("[Client] Root element not found");
|
575
|
+
return;
|
576
|
+
}
|
577
|
+
console.log(`[Client] Fetching users data for ${currentPath}`);
|
578
|
+
const users = await fetchData("/users");
|
579
|
+
if (users) {
|
580
|
+
initialState.data = {
|
581
|
+
...initialState.data,
|
582
|
+
users
|
583
|
+
};
|
584
|
+
console.log(`[Client] Updated state with ${users.length} users`);
|
585
|
+
}
|
586
|
+
let PageComponent = null;
|
587
|
+
if (currentPath === "/about") {
|
588
|
+
try {
|
589
|
+
const AboutPage2 = await Promise.resolve().then(() => (init_about(), about_exports));
|
590
|
+
PageComponent = AboutPage2.default;
|
591
|
+
} catch (err) {
|
592
|
+
console.error("[Client] Failed to load about page:", err);
|
593
|
+
}
|
594
|
+
} else if (currentPath === "/users") {
|
595
|
+
try {
|
596
|
+
const UsersPage2 = await Promise.resolve().then(() => (init_users(), users_exports));
|
597
|
+
PageComponent = UsersPage2.default;
|
598
|
+
} catch (err) {
|
599
|
+
console.error("[Client] Failed to load users page:", err);
|
600
|
+
}
|
601
|
+
} else {
|
602
|
+
PageComponent = await router.resolve(currentPath);
|
603
|
+
}
|
604
|
+
if (!PageComponent) {
|
605
|
+
console.warn(`[Client] Page component not found for ${currentPath}, checking special cases`);
|
606
|
+
if (currentPath === "/users") {
|
607
|
+
try {
|
608
|
+
console.log("[Client] Attempting direct import of Users page");
|
609
|
+
const UsersModule = await Promise.resolve().then(() => (init_users(), users_exports));
|
610
|
+
if (UsersModule.default) {
|
611
|
+
PageComponent = UsersModule.default;
|
612
|
+
}
|
613
|
+
} catch (err) {
|
614
|
+
console.error("[Client] Failed to import Users page:", err);
|
615
|
+
}
|
616
|
+
}
|
617
|
+
}
|
618
|
+
if (!PageComponent) {
|
619
|
+
PageComponent = ({ initialState: initialState2 }) => jsx("div", {
|
620
|
+
style: "padding: 20px; max-width: 800px; margin: 0 auto;"
|
621
|
+
}, [
|
622
|
+
jsx("h1", {}, ["Page Not Found"]),
|
623
|
+
jsx("p", {}, [`No component found for path: ${initialState2.route}`]),
|
624
|
+
jsx("a", { href: "/", style: "color: #0066cc;" }, ["Go to Home"])
|
625
|
+
]);
|
626
|
+
}
|
627
|
+
initialState.route = currentPath;
|
628
|
+
initialState.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
629
|
+
initialState.serverRendered = false;
|
630
|
+
if (isHydrating2) {
|
631
|
+
console.log("[Client] Hydrating server-rendered content");
|
632
|
+
hydrate(/* @__PURE__ */ jsx(PageComponent, { initialState }), rootElement);
|
633
|
+
isHydrating2 = false;
|
634
|
+
} else {
|
635
|
+
console.log("[Client] Rendering client-side");
|
636
|
+
render(/* @__PURE__ */ jsx(PageComponent, { initialState }), rootElement);
|
637
|
+
}
|
638
|
+
} catch (error) {
|
639
|
+
console.error("[Client] Error rendering app:", error);
|
640
|
+
const rootElement = document.getElementById("root");
|
641
|
+
if (rootElement) {
|
642
|
+
rootElement.innerHTML = `
|
643
|
+
<div style="padding: 20px; color: red;">
|
644
|
+
<h1>Error</h1>
|
645
|
+
<p>${error.message}</p>
|
646
|
+
<pre>${error.stack}</pre>
|
647
|
+
</div>
|
648
|
+
`;
|
649
|
+
}
|
650
|
+
}
|
651
|
+
}
|
652
|
+
renderApp();
|
653
|
+
document.addEventListener("click", (e) => {
|
654
|
+
let target = e.target;
|
655
|
+
while (target && target.tagName !== "A") {
|
656
|
+
target = target.parentElement;
|
657
|
+
if (!target)
|
658
|
+
break;
|
659
|
+
}
|
660
|
+
if (target && target.tagName === "A" && target.getAttribute("href") && target.getAttribute("href").startsWith("/") && !target.getAttribute("href").startsWith("//") && !target.getAttribute("target")) {
|
661
|
+
e.preventDefault();
|
662
|
+
const href = target.getAttribute("href");
|
663
|
+
window.history.pushState(null, "", href);
|
664
|
+
isHydrating2 = false;
|
665
|
+
renderApp();
|
666
|
+
}
|
667
|
+
});
|
668
|
+
window.addEventListener("popstate", () => {
|
669
|
+
isHydrating2 = false;
|
670
|
+
renderApp();
|
671
|
+
});
|
672
|
+
if (typeof io !== "undefined") {
|
673
|
+
const socket = io();
|
674
|
+
socket.on("reload", () => {
|
675
|
+
console.log("[Dev] Reloading page due to file changes");
|
676
|
+
window.location.reload();
|
677
|
+
});
|
678
|
+
socket.on("welcome", (data) => {
|
679
|
+
console.log("[Dev] Connected to development server:", data);
|
680
|
+
});
|
681
|
+
}
|
682
|
+
//# sourceMappingURL=main.js.map
|