@ressjs/vite-router 0.4.1 → 0.4.2

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.
@@ -7,6 +7,7 @@ export interface HTMLGenerationContext {
7
7
  platform: string;
8
8
  isProduction: boolean;
9
9
  platformInfo: PlatformInfo | null;
10
+ serverSideResult?: any;
10
11
  }
11
12
  export declare function generateClientScript(pageFile: string, platformInfo: PlatformInfo | null, manifest: any, isProduction: boolean): Promise<string | null>;
12
13
  export declare function generateClientCSS(pageFile: string, platformInfo: PlatformInfo | null, manifest: any, isProduction: boolean): string;
@@ -90,12 +90,40 @@ function generateClientCSS(pageFile, platformInfo, manifest, isProduction) {
90
90
  return '';
91
91
  }
92
92
  async function generateCompleteHTML(context) {
93
- const { template, rendered, page, manifest, isProduction, platformInfo } = context;
93
+ const { template, rendered, page, manifest, isProduction, platformInfo, serverSideResult } = context;
94
94
  const scriptSrc = await generateClientScript(page.file, platformInfo, manifest, isProduction);
95
95
  const scriptTag = scriptSrc ? `<script type="module" src="${scriptSrc}"></script>` : '';
96
96
  const cssLinks = page?.file ? generateClientCSS(page.file, platformInfo, manifest, isProduction) : '';
97
- const html = template
98
- .replace('<!--app-head-->', cssLinks)
97
+ // Construir contenido HEAD extra y atributos desde serverSideResult
98
+ let headContent = cssLinks;
99
+ let htmlAttributes = '';
100
+ let bodyAttributes = '';
101
+ let pageTitle = '';
102
+ if (serverSideResult?.html) {
103
+ if (serverSideResult.html.head?.attributes) {
104
+ htmlAttributes = Object.entries(serverSideResult.html.head.attributes)
105
+ .map(([k, v]) => `${k}="${v}"`).join(' ');
106
+ }
107
+ if (serverSideResult.html.body?.attributes) {
108
+ bodyAttributes = Object.entries(serverSideResult.html.body.attributes)
109
+ .map(([k, v]) => `${k}="${v}"`).join(' ');
110
+ }
111
+ if (serverSideResult.html.head?.extraTags) {
112
+ headContent += '\n' + serverSideResult.html.head.extraTags.join('\n');
113
+ }
114
+ if (serverSideResult.title || serverSideResult.html.head?.title) {
115
+ pageTitle = `<title>${serverSideResult.title || serverSideResult.html.head?.title}</title>`;
116
+ }
117
+ }
118
+ let html = template;
119
+ if (htmlAttributes)
120
+ html = html.replace('<html', `<html ${htmlAttributes}`);
121
+ if (bodyAttributes)
122
+ html = html.replace('<body', `<body ${bodyAttributes}`);
123
+ if (pageTitle)
124
+ html = html.replace(/<title>.*?<\/title>/i, pageTitle);
125
+ html = html
126
+ .replace('<!--app-head-->', headContent)
99
127
  .replace('<!--app-html-->', rendered.html)
100
128
  .replace('</body>', `<script>
101
129
  window.__INITIAL_PROPS__=${JSON.stringify(rendered.props || {})};
@@ -0,0 +1,72 @@
1
+ import { Request, RequestHandler, Response } from 'express';
2
+ export interface MiddlewareInfo {
3
+ route: string;
4
+ file: string;
5
+ abs: string;
6
+ type: 'page-specific' | 'folder-global';
7
+ depth: number;
8
+ }
9
+ export interface ServerSideResult {
10
+ props?: Record<string, any>;
11
+ title?: string;
12
+ html?: {
13
+ head?: {
14
+ title?: string;
15
+ attributes?: Record<string, string>;
16
+ extraTags?: string[];
17
+ };
18
+ body?: {
19
+ attributes?: Record<string, string>;
20
+ };
21
+ };
22
+ }
23
+ export interface PageModule {
24
+ default?: React.ComponentType<any>;
25
+ getServerSideProps?: (req: Request, res: Response) => Promise<ServerSideResult> | ServerSideResult;
26
+ errorMiddleware?: (err: any, req: Request, res: Response, next: any) => void;
27
+ }
28
+ /**
29
+ * Busca archivos de middlewares tanto específicos por página como globales por carpeta
30
+ */
31
+ export declare function getMiddlewares(): MiddlewareInfo[];
32
+ /**
33
+ * Carga middlewares para una página específica y los convierte en middlewares de Express
34
+ */
35
+ export declare function loadPageMiddlewares(pageRoute: string, vite?: any): Promise<RequestHandler[]>;
36
+ /**
37
+ * Carga el módulo completo de una página
38
+ */
39
+ export declare function loadPageModule(pageFile: string, vite?: any): Promise<PageModule | null>;
40
+ /**
41
+ * Convierte getServerSideProps en un middleware de Express
42
+ */
43
+ export declare function createGetServerSidePropsMiddleware(pageModule: PageModule): RequestHandler;
44
+ /**
45
+ * Creates a unified error handler for a specific page route
46
+ * This replaces the old createPageErrorMiddleware with a more useful approach
47
+ */
48
+ export declare function createPageErrorHandler(pageFile: string, vite?: any): (err: any, req: any, res: any, next: any) => Promise<void>;
49
+ /**
50
+ * Creates a dynamic middleware handler that reloads middlewares on each request in development
51
+ * This enables HMR for middlewares
52
+ * I FUCKING HATE THIS FUNCTION BUT IT SEEMS TO WORK
53
+ */
54
+ export declare function createDynamicPageMiddlewares(pageRoute: string, pageFile: string, vite?: any): RequestHandler;
55
+ /**
56
+ * 1. Resuelve middlewares previos al getServerSideProps
57
+ */
58
+ export declare function getPagePrevMiddlewares(pageRoute: string, vite?: any): Promise<RequestHandler[]>;
59
+ /**
60
+ * 2. Convierte getServerSideProps a middleware
61
+ */
62
+ export declare function getServerSidePropsAsMiddleware(pageFile: string, vite?: any): Promise<RequestHandler>;
63
+ /**
64
+ * 3. Error middleware con fallback automático y jerarquía
65
+ * Orden de prioridad (el más específico gana):
66
+ * 1. errorMiddleware en page.tsx (más específico)
67
+ * 2. errorMiddleware en [page].middlewares.ts
68
+ * 3. errorMiddleware en carpeta/middlewares.ts
69
+ * 4. errorMiddleware en root middlewares.ts (más general)
70
+ * 5. defaultErrorMiddleware (fallback)
71
+ */
72
+ export declare function getErrorMiddleware(pageFile: string, vite?: any): Promise<any>;
@@ -0,0 +1,381 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.getMiddlewares = getMiddlewares;
40
+ exports.loadPageMiddlewares = loadPageMiddlewares;
41
+ exports.loadPageModule = loadPageModule;
42
+ exports.createGetServerSidePropsMiddleware = createGetServerSidePropsMiddleware;
43
+ exports.createPageErrorHandler = createPageErrorHandler;
44
+ exports.createDynamicPageMiddlewares = createDynamicPageMiddlewares;
45
+ exports.getPagePrevMiddlewares = getPagePrevMiddlewares;
46
+ exports.getServerSidePropsAsMiddleware = getServerSidePropsAsMiddleware;
47
+ exports.getErrorMiddleware = getErrorMiddleware;
48
+ const node_path_1 = __importDefault(require("node:path"));
49
+ const fast_glob_1 = __importDefault(require("fast-glob"));
50
+ const pages_1 = require("../pages");
51
+ /**
52
+ * Busca archivos de middlewares tanto específicos por página como globales por carpeta
53
+ */
54
+ function getMiddlewares() {
55
+ // Busca archivos .middlewares.ts y middlewares.ts
56
+ const files = fast_glob_1.default.sync('app/pages/**/*.middlewares.{ts,js}');
57
+ const globalFiles = fast_glob_1.default.sync('app/pages/**/middlewares.{ts,js}');
58
+ const middlewares = [];
59
+ // Procesar archivos específicos de página: page.middlewares.ts
60
+ for (const file of files) {
61
+ let route = file.replace(/^app\/pages/, '').replace(/\.middlewares\.(ts|js)$/, '');
62
+ route = route.replace(/\/index$/, '') || '/';
63
+ // Calcular depth: contar slashes en la ruta del archivo
64
+ const depth = (file.match(/\//g) || []).length;
65
+ middlewares.push({
66
+ route,
67
+ file,
68
+ abs: node_path_1.default.resolve(file),
69
+ type: 'page-specific',
70
+ depth
71
+ });
72
+ }
73
+ // Procesar archivos globales: middlewares.ts
74
+ for (const file of globalFiles) {
75
+ let route = file.replace(/^app\/pages/, '').replace(/\/middlewares\.(ts|js)$/, '');
76
+ route = route || '/';
77
+ // Calcular depth: contar slashes en la ruta del archivo
78
+ const depth = (file.match(/\//g) || []).length;
79
+ middlewares.push({
80
+ route,
81
+ file,
82
+ abs: node_path_1.default.resolve(file),
83
+ type: 'folder-global',
84
+ depth
85
+ });
86
+ }
87
+ return middlewares;
88
+ }
89
+ /**
90
+ * Carga middlewares para una página específica y los convierte en middlewares de Express
91
+ */
92
+ async function loadPageMiddlewares(pageRoute, vite) {
93
+ const allMiddlewares = getMiddlewares();
94
+ // Filtrar middlewares relevantes para esta página usando jerarquía
95
+ const relevantMiddlewares = allMiddlewares.filter(middleware => {
96
+ if (middleware.type === 'folder-global') {
97
+ // Un middleware global aplica si la página está dentro de su carpeta
98
+ // ej: middleware en "/pokedex" aplica a "/pokedex" y "/pokedex/detail"
99
+ return pageRoute.startsWith(middleware.route) || middleware.route === '/';
100
+ }
101
+ if (middleware.type === 'page-specific') {
102
+ // Un middleware específico aplica solo a esa página exacta por ruta
103
+ return middleware.route === pageRoute;
104
+ }
105
+ return false;
106
+ });
107
+ // Ordenar por jerarquía: depth menor primero, luego por tipo
108
+ relevantMiddlewares.sort((a, b) => {
109
+ // Primero por depth (carpetas más arriba en la jerarquía van primero)
110
+ if (a.depth !== b.depth) {
111
+ return a.depth - b.depth;
112
+ }
113
+ // Si están al mismo nivel, folder-global va antes que page-specific
114
+ if (a.type === 'folder-global' && b.type === 'page-specific')
115
+ return -1;
116
+ if (a.type === 'page-specific' && b.type === 'folder-global')
117
+ return 1;
118
+ return 0;
119
+ });
120
+ const expressMiddlewares = [];
121
+ // Cargar middlewares de archivos .middlewares.ts
122
+ for (const middlewareFile of relevantMiddlewares) {
123
+ try {
124
+ const moduleToLoad = await loadMiddlewareModule(middlewareFile, vite);
125
+ const handlers = moduleToLoad.default || [];
126
+ for (const handler of handlers) {
127
+ if (typeof handler === 'function') {
128
+ expressMiddlewares.push(handler);
129
+ }
130
+ }
131
+ }
132
+ catch (error) {
133
+ console.error(`Error loading middleware ${middlewareFile.file}:`, error);
134
+ }
135
+ }
136
+ return expressMiddlewares;
137
+ }
138
+ /**
139
+ * Carga el módulo completo de una página
140
+ */
141
+ async function loadPageModule(pageFile, vite) {
142
+ const isProduction = process.env.NODE_ENV === 'production';
143
+ const cacheKey = `${pageFile}-${process.env.NODE_ENV || 'development'}`;
144
+ // Only use cache in production mode to allow HMR in development
145
+ if (isProduction && pageModuleCache.has(cacheKey)) {
146
+ return pageModuleCache.get(cacheKey) || null;
147
+ }
148
+ try {
149
+ let pageModule;
150
+ if (vite) {
151
+ const modulePath = `/${pageFile}`;
152
+ pageModule = await vite.ssrLoadModule(modulePath);
153
+ }
154
+ else {
155
+ if (pageFile.endsWith('.tsx')) {
156
+ const moduleUrl = (0, pages_1.getCompiledProdPage)(pageFile);
157
+ pageModule = await Promise.resolve(`${moduleUrl}`).then(s => __importStar(require(s)));
158
+ }
159
+ else {
160
+ const moduleUrl = node_path_1.default.resolve(pageFile);
161
+ pageModule = await Promise.resolve(`${moduleUrl}`).then(s => __importStar(require(s)));
162
+ }
163
+ }
164
+ const result = pageModule;
165
+ // Only cache in production mode
166
+ if (isProduction) {
167
+ pageModuleCache.set(cacheKey, result);
168
+ }
169
+ return result;
170
+ }
171
+ catch (error) {
172
+ console.error(`Error loading page module ${pageFile}:`, error);
173
+ // Only cache null result in production mode
174
+ if (isProduction) {
175
+ pageModuleCache.set(cacheKey, null);
176
+ }
177
+ return null;
178
+ }
179
+ }
180
+ /**
181
+ * Convierte getServerSideProps en un middleware de Express
182
+ */
183
+ function createGetServerSidePropsMiddleware(pageModule) {
184
+ return async (req, res, next) => {
185
+ if (!pageModule.getServerSideProps) {
186
+ next();
187
+ return;
188
+ }
189
+ try {
190
+ const result = await pageModule.getServerSideProps(req, res);
191
+ // Manejar ServerSideResult
192
+ if (result && typeof result === 'object') {
193
+ // SEPARAR: Configuración HTML se queda en servidor, props van al cliente
194
+ // Configuración HTML → solo para el servidor (NO va al cliente)
195
+ if (result.title || result.html) {
196
+ res.locals.htmlConfig = {
197
+ title: result.title,
198
+ html: result.html
199
+ };
200
+ }
201
+ // Props → solo en un bucket claro (serverSideProps)
202
+ if (result.props) {
203
+ res.locals.serverSideProps = {
204
+ ...(res.locals.serverSideProps || {}),
205
+ ...result.props
206
+ };
207
+ }
208
+ }
209
+ next();
210
+ }
211
+ catch (error) {
212
+ next(error);
213
+ }
214
+ };
215
+ }
216
+ /**
217
+ * Creates a unified error handler for a specific page route
218
+ * This replaces the old createPageErrorMiddleware with a more useful approach
219
+ */
220
+ function createPageErrorHandler(pageFile, vite) {
221
+ return async (err, req, res, next) => {
222
+ const errorMiddleware = await getErrorMiddleware(pageFile, vite);
223
+ errorMiddleware(err, req, res, next);
224
+ };
225
+ }
226
+ /**
227
+ * Error middleware por defecto
228
+ */
229
+ const defaultErrorMiddleware = (err, _req, res, _next) => {
230
+ console.error(err);
231
+ if (process.env.NODE_ENV !== 'production') {
232
+ console.warn('No custom error handler configured. Add errorMiddleware export to your page or middleware file.');
233
+ }
234
+ res.status(500).send(err.message || 'Internal Server Error');
235
+ };
236
+ /**
237
+ * Creates a dynamic middleware handler that reloads middlewares on each request in development
238
+ * This enables HMR for middlewares
239
+ * I FUCKING HATE THIS FUNCTION BUT IT SEEMS TO WORK
240
+ */
241
+ function createDynamicPageMiddlewares(pageRoute, pageFile, vite) {
242
+ return async (req, res, next) => {
243
+ try {
244
+ const middlewares = [
245
+ ...(await loadPageMiddlewares(pageRoute, vite)),
246
+ await getServerSidePropsAsMiddleware(pageFile, vite)
247
+ ];
248
+ // Execute middlewares sequentially
249
+ let currentIndex = 0;
250
+ const executeNext = (err) => {
251
+ if (err)
252
+ return next(err);
253
+ const currentMiddleware = middlewares[currentIndex++];
254
+ if (!currentMiddleware)
255
+ return next();
256
+ currentMiddleware(req, res, executeNext);
257
+ };
258
+ executeNext();
259
+ }
260
+ catch (error) {
261
+ next(error);
262
+ }
263
+ };
264
+ }
265
+ /**
266
+ * 1. Resuelve middlewares previos al getServerSideProps
267
+ */
268
+ async function getPagePrevMiddlewares(pageRoute, vite) {
269
+ return await loadPageMiddlewares(pageRoute, vite);
270
+ }
271
+ /**
272
+ * 2. Convierte getServerSideProps a middleware
273
+ */
274
+ async function getServerSidePropsAsMiddleware(pageFile, vite) {
275
+ const pageModule = await loadPageModule(pageFile, vite);
276
+ return pageModule ? createGetServerSidePropsMiddleware(pageModule) : (_req, _res, next) => next();
277
+ }
278
+ /**
279
+ * 3. Error middleware con fallback automático y jerarquía
280
+ * Orden de prioridad (el más específico gana):
281
+ * 1. errorMiddleware en page.tsx (más específico)
282
+ * 2. errorMiddleware en [page].middlewares.ts
283
+ * 3. errorMiddleware en carpeta/middlewares.ts
284
+ * 4. errorMiddleware en root middlewares.ts (más general)
285
+ * 5. defaultErrorMiddleware (fallback)
286
+ */
287
+ async function getErrorMiddleware(pageFile, vite) {
288
+ const pageModule = await loadPageModule(pageFile, vite);
289
+ // 1. Prioridad máxima: errorMiddleware en la página
290
+ if (pageModule?.errorMiddleware) {
291
+ return pageModule.errorMiddleware;
292
+ }
293
+ // 2-4. Buscar errorMiddleware en middlewares siguiendo jerarquía
294
+ const errorMiddleware = await findErrorMiddlewareInHierarchy(pageFile, vite);
295
+ if (errorMiddleware) {
296
+ return errorMiddleware;
297
+ }
298
+ // 5. Fallback al default
299
+ return defaultErrorMiddleware;
300
+ }
301
+ /**
302
+ * Busca errorMiddleware en la jerarquía de middlewares
303
+ * Desde el más específico (página) hasta el más general (root)
304
+ */
305
+ async function findErrorMiddlewareInHierarchy(pageFile, vite) {
306
+ // Obtener todos los middlewares que podrían aplicar a esta página
307
+ const allMiddlewares = getMiddlewares();
308
+ // Convertir pageFile a route para matching
309
+ let pageRoute = pageFile.replace(/^app\/pages/, '').replace(/\.(tsx|ts|jsx|js)$/, '');
310
+ pageRoute = pageRoute.replace(/\/index$/, '') || '/';
311
+ // Filtrar middlewares relevantes para esta página
312
+ const relevantMiddlewares = allMiddlewares
313
+ .filter(mw => {
314
+ // Para page-specific middlewares: debe coincidir exactamente con la ruta
315
+ if (mw.type === 'page-specific') {
316
+ return mw.route === pageRoute;
317
+ }
318
+ // Para folder-global middlewares: la página debe estar en esa carpeta o subcarpeta
319
+ if (mw.route === '/')
320
+ return true; // root middleware applies to all
321
+ // Si el middleware está en una carpeta, debe aplicar a todas las páginas de esa carpeta
322
+ // Ejemplo: /error-test/middlewares.ts aplica a /error-test/index, /error-test/sub, etc.
323
+ return pageRoute.startsWith(mw.route + '/') || pageRoute === mw.route;
324
+ })
325
+ .sort((a, b) => {
326
+ // Ordenar por especificidad: mayor depth = más específico
327
+ if (a.depth !== b.depth)
328
+ return b.depth - a.depth;
329
+ // Si mismo depth, page-specific > folder-global
330
+ if (a.type === 'page-specific' && b.type === 'folder-global')
331
+ return -1;
332
+ if (a.type === 'folder-global' && b.type === 'page-specific')
333
+ return 1;
334
+ return 0;
335
+ });
336
+ // Buscar errorMiddleware en orden de especificidad
337
+ for (const middlewareInfo of relevantMiddlewares) {
338
+ try {
339
+ const middlewareModule = await loadMiddlewareModule(middlewareInfo, vite);
340
+ if (middlewareModule?.errorMiddleware) {
341
+ return middlewareModule.errorMiddleware;
342
+ }
343
+ }
344
+ catch (error) {
345
+ console.error(`Error loading middleware ${middlewareInfo.file}:`, error);
346
+ }
347
+ }
348
+ return null;
349
+ }
350
+ // Cache for loaded middleware modules to avoid multiple ssrLoadModule calls
351
+ const middlewareModuleCache = new Map();
352
+ // Cache for loaded page modules to avoid multiple ssrLoadModule calls
353
+ const pageModuleCache = new Map();
354
+ /**
355
+ * Cargar un módulo de middleware específico
356
+ */
357
+ async function loadMiddlewareModule(middlewareInfo, vite) {
358
+ const isProduction = process.env.NODE_ENV === 'production';
359
+ const cacheKey = `${middlewareInfo.file}-${process.env.NODE_ENV || 'development'}`;
360
+ // Only use cache in production mode to allow HMR in development
361
+ if (isProduction && middlewareModuleCache.has(cacheKey)) {
362
+ return middlewareModuleCache.get(cacheKey);
363
+ }
364
+ let moduleToLoad;
365
+ if (!isProduction && vite) {
366
+ moduleToLoad = await vite.ssrLoadModule(middlewareInfo.file);
367
+ }
368
+ else {
369
+ // En producción, usar archivos compilados
370
+ const compiledPath = middlewareInfo.file
371
+ .replace(/^app\/pages\//, 'dist/server/')
372
+ .replace(/\.ts$/, '.js');
373
+ const moduleUrl = node_path_1.default.resolve(compiledPath);
374
+ moduleToLoad = await Promise.resolve(`${moduleUrl}`).then(s => __importStar(require(s)));
375
+ }
376
+ // Only cache in production mode
377
+ if (isProduction) {
378
+ middlewareModuleCache.set(cacheKey, moduleToLoad);
379
+ }
380
+ return moduleToLoad;
381
+ }
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.processRequest = processRequest;
7
7
  const promises_1 = __importDefault(require("node:fs/promises"));
8
8
  const pages_1 = require("../pages");
9
+ const render_1 = require("../render");
9
10
  const platform_1 = require("../platform");
10
11
  const html_generator_1 = require("./html-generator");
11
12
  async function preparePlatform(req, enablePlatformDetection = true, isProduction = false) {
@@ -25,7 +26,12 @@ async function preparePlatform(req, enablePlatformDetection = true, isProduction
25
26
  }
26
27
  async function processRequest(context, config, renderServer) {
27
28
  const { req, res, page, next } = context;
28
- const { enablePlatformDetection, renderFunction, viteConfig } = config;
29
+ // config.viteConfig can be a ViteConfig or a thunk returning it (auto mode)
30
+ const resolvedViteConfig = typeof config.viteConfig === 'function'
31
+ ? config.viteConfig()
32
+ : config.viteConfig;
33
+ const { enablePlatformDetection, renderFunction } = config;
34
+ const viteConfig = resolvedViteConfig;
29
35
  try {
30
36
  const platformContext = await preparePlatform(req, enablePlatformDetection, viteConfig.isProduction);
31
37
  if (renderFunction) {
@@ -40,13 +46,22 @@ async function processRequest(context, config, renderServer) {
40
46
  }
41
47
  if (!renderServer) {
42
48
  const renderOptions = viteConfig.vite ? { vite: viteConfig.vite } : {};
43
- renderServer = (0, pages_1.createRenderServer)(renderOptions);
49
+ renderServer = (0, render_1.createRenderServer)(renderOptions);
44
50
  }
45
51
  const protocol = req.headers['x-forwarded-proto'] || (req.connection?.encrypted ? 'https' : 'http');
46
52
  const host = req.headers.host || 'localhost';
47
53
  const urlObj = new URL(req.url, `${protocol}://${host}`);
48
54
  const pathname = urlObj.pathname;
49
- const rendered = await renderServer({ url: pathname });
55
+ // Inicializar res.locals si no existe (para middlewares)
56
+ if (!res.locals) {
57
+ res.locals = {};
58
+ }
59
+ const rendered = await renderServer({
60
+ url: pathname,
61
+ req,
62
+ res,
63
+ props: res.locals.serverSideProps
64
+ });
50
65
  const template = await getTemplate(req, viteConfig);
51
66
  const html = await (0, html_generator_1.generateCompleteHTML)({
52
67
  template,
@@ -55,7 +70,9 @@ async function processRequest(context, config, renderServer) {
55
70
  manifest: viteConfig.manifest,
56
71
  platform: platformContext.platform,
57
72
  isProduction: viteConfig.isProduction,
58
- platformInfo: platformContext.platformInfo
73
+ platformInfo: platformContext.platformInfo,
74
+ // pasar solo la config segura
75
+ ...(res.locals?.htmlConfig ? { serverSideResult: res.locals.htmlConfig } : {})
59
76
  });
60
77
  res.setHeader('Content-Type', 'text/html');
61
78
  res.send(html);
@@ -5,6 +5,6 @@ export interface ViteConfig {
5
5
  isProduction: boolean;
6
6
  }
7
7
  export declare function setupDev(base?: string): Promise<ViteConfig>;
8
- export declare function setupProd(): Promise<Pick<ViteConfig, 'manifest' | 'templateHtml'>>;
8
+ export declare function setupProd(): Promise<ViteConfig>;
9
9
  export declare function createProdMiddleware(): () => Promise<import("express-serve-static-core").Router>;
10
10
  export declare function setupVite(isProduction: boolean, base?: string): Promise<ViteConfig>;
@@ -63,7 +63,12 @@ async function setupDev(base = '/') {
63
63
  async function setupProd() {
64
64
  const manifest = JSON.parse(await promises_1.default.readFile('./dist/client/.vite/manifest.json', 'utf-8'));
65
65
  const templateHtml = await promises_1.default.readFile('./index.html', 'utf-8');
66
- return { manifest, templateHtml };
66
+ return {
67
+ vite: null,
68
+ manifest,
69
+ templateHtml,
70
+ isProduction: true
71
+ };
67
72
  }
68
73
  function createProdMiddleware() {
69
74
  const middlewares = express_1.default.Router();
@@ -77,21 +82,9 @@ function createProdMiddleware() {
77
82
  }
78
83
  async function setupVite(isProduction, base = '/') {
79
84
  if (isProduction) {
80
- const prodConfig = await setupProd();
81
- return {
82
- vite: undefined,
83
- manifest: prodConfig.manifest,
84
- templateHtml: prodConfig.templateHtml,
85
- isProduction: true
86
- };
85
+ return await setupProd();
87
86
  }
88
87
  else {
89
- const devConfig = await setupDev(base);
90
- return {
91
- vite: devConfig.vite,
92
- manifest: devConfig.manifest,
93
- templateHtml: '',
94
- isProduction: false
95
- };
88
+ return await setupDev(base);
96
89
  }
97
90
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { createViteRouter, createAutoViteServer, listDetectedPages, getPages } from './router';
2
- export { getViteInput, getClientEntriesInput, generateTempEntries, createRenderServer, resolvePlatformCSS } from './pages';
3
- export { detectPlatform, getPlatformCSSClass, resolveEntryClient } from './platform';
2
+ export { getViteInput, getViteSSRInput, getClientEntriesInput, generateTempEntries, resolvePlatformCSS } from './pages';
3
+ export { createRenderServer } from './render';
4
+ export { detectPlatform } from './platform';
4
5
  export type { PlatformInfo } from './platform';
5
6
  export type { ViteRouterOptions, AutoViteServerOptions } from './router';
6
7
  export type { PageInfo } from './pages';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveEntryClient = exports.getPlatformCSSClass = exports.detectPlatform = exports.resolvePlatformCSS = exports.createRenderServer = exports.generateTempEntries = exports.getClientEntriesInput = exports.getViteInput = exports.getPages = exports.listDetectedPages = exports.createAutoViteServer = exports.createViteRouter = void 0;
3
+ exports.detectPlatform = exports.createRenderServer = exports.resolvePlatformCSS = exports.generateTempEntries = exports.getClientEntriesInput = exports.getViteSSRInput = exports.getViteInput = exports.getPages = exports.listDetectedPages = exports.createAutoViteServer = exports.createViteRouter = void 0;
4
4
  // Main API
5
5
  var router_1 = require("./router");
6
6
  Object.defineProperty(exports, "createViteRouter", { enumerable: true, get: function () { return router_1.createViteRouter; } });
@@ -10,12 +10,13 @@ Object.defineProperty(exports, "getPages", { enumerable: true, get: function ()
10
10
  // Core functions for Vite config
11
11
  var pages_1 = require("./pages");
12
12
  Object.defineProperty(exports, "getViteInput", { enumerable: true, get: function () { return pages_1.getViteInput; } });
13
+ Object.defineProperty(exports, "getViteSSRInput", { enumerable: true, get: function () { return pages_1.getViteSSRInput; } });
13
14
  Object.defineProperty(exports, "getClientEntriesInput", { enumerable: true, get: function () { return pages_1.getClientEntriesInput; } });
14
15
  Object.defineProperty(exports, "generateTempEntries", { enumerable: true, get: function () { return pages_1.generateTempEntries; } });
15
- Object.defineProperty(exports, "createRenderServer", { enumerable: true, get: function () { return pages_1.createRenderServer; } });
16
16
  Object.defineProperty(exports, "resolvePlatformCSS", { enumerable: true, get: function () { return pages_1.resolvePlatformCSS; } });
17
+ // Render functions
18
+ var render_1 = require("./render");
19
+ Object.defineProperty(exports, "createRenderServer", { enumerable: true, get: function () { return render_1.createRenderServer; } });
17
20
  // Platform detection
18
21
  var platform_1 = require("./platform");
19
22
  Object.defineProperty(exports, "detectPlatform", { enumerable: true, get: function () { return platform_1.detectPlatform; } });
20
- Object.defineProperty(exports, "getPlatformCSSClass", { enumerable: true, get: function () { return platform_1.getPlatformCSSClass; } });
21
- Object.defineProperty(exports, "resolveEntryClient", { enumerable: true, get: function () { return platform_1.resolveEntryClient; } });
package/dist/pages.d.ts CHANGED
@@ -6,21 +6,16 @@ export interface PageInfo {
6
6
  }
7
7
  export declare function getPages(): PageInfo[];
8
8
  export declare function getViteInput(): Record<string, string>;
9
+ export declare function getViteSSRInput(): Record<string, string>;
9
10
  export declare function loadManifest(distPath?: string): Promise<any>;
11
+ /**
12
+ * Convierte una ruta de página TypeScript a su equivalente compilado en producción
13
+ *
14
+ * @param pageFile - Ruta del archivo de página (relativa: "app/pages/pokedex/index.tsx" o absoluta: "/path/to/app/pages/pokedex/index.tsx")
15
+ * @returns Ruta absoluta del archivo compilado (ej: "/path/to/project/dist/server/pokedex/index.js")
16
+ */
17
+ export declare function getCompiledProdPage(pageFile: string): string;
10
18
  export declare function resolvePlatformCSS(basePath: string, platform: PlatformInfo): Promise<string>;
11
19
  export declare function generateTempEntries(distPath?: string, platformInfo?: PlatformInfo): Promise<string[]>;
12
20
  export declare function generateSingleEntry(page: PageInfo, entryPath: string, preferredScssFile: string): Promise<void>;
13
21
  export declare function getClientEntriesInput(distPath?: string): Promise<Record<string, string>>;
14
- export interface RenderOptions {
15
- url: string;
16
- props?: any;
17
- }
18
- export interface CreateRenderServerOptions {
19
- vite?: any;
20
- }
21
- export declare function createRenderServer(options?: CreateRenderServerOptions): (renderOptions: RenderOptions) => Promise<{
22
- html: string;
23
- props: any;
24
- route: string;
25
- page: string;
26
- }>;
package/dist/pages.js CHANGED
@@ -38,17 +38,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.getPages = getPages;
40
40
  exports.getViteInput = getViteInput;
41
+ exports.getViteSSRInput = getViteSSRInput;
41
42
  exports.loadManifest = loadManifest;
43
+ exports.getCompiledProdPage = getCompiledProdPage;
42
44
  exports.resolvePlatformCSS = resolvePlatformCSS;
43
45
  exports.generateTempEntries = generateTempEntries;
44
46
  exports.generateSingleEntry = generateSingleEntry;
45
47
  exports.getClientEntriesInput = getClientEntriesInput;
46
- exports.createRenderServer = createRenderServer;
47
48
  const promises_1 = __importDefault(require("node:fs/promises"));
48
49
  const node_path_1 = __importDefault(require("node:path"));
49
50
  const fast_glob_1 = __importDefault(require("fast-glob"));
50
- const react_1 = __importDefault(require("react"));
51
- const server_1 = require("react-dom/server");
52
51
  function getPages() {
53
52
  // Busca tanto page.tsx como page/index.tsx y prioriza el más corto
54
53
  const files = fast_glob_1.default.sync('app/pages/**/*.{tsx,jsx}');
@@ -74,6 +73,17 @@ function getViteInput() {
74
73
  }
75
74
  return input;
76
75
  }
76
+ // Para Vite SSR: input incluyendo páginas + middlewares
77
+ function getViteSSRInput() {
78
+ const input = getViteInput(); // Empezar con las páginas
79
+ // Agregar TODOS los middlewares: .middlewares.ts y middlewares.ts
80
+ const middlewareFiles = fast_glob_1.default.sync('app/pages/**/{middlewares,*.middlewares}.{ts,js}');
81
+ for (const middlewareFile of middlewareFiles) {
82
+ const key = middlewareFile.replace(/^app\/pages\//, '').replace(/\.(ts|js)$/, '');
83
+ input[key] = node_path_1.default.resolve(middlewareFile);
84
+ }
85
+ return input;
86
+ }
77
87
  async function loadManifest(distPath = 'dist') {
78
88
  const assetsDir = node_path_1.default.join(distPath, 'server/.vite');
79
89
  const files = await promises_1.default.readdir(assetsDir);
@@ -84,6 +94,36 @@ async function loadManifest(distPath = 'dist') {
84
94
  const manifest = (await Promise.resolve(`${node_path_1.default.join(assetsDir, manifestFile)}`).then(s => __importStar(require(s)))).default;
85
95
  return manifest;
86
96
  }
97
+ /**
98
+ * Convierte una ruta de página TypeScript a su equivalente compilado en producción
99
+ *
100
+ * @param pageFile - Ruta del archivo de página (relativa: "app/pages/pokedex/index.tsx" o absoluta: "/path/to/app/pages/pokedex/index.tsx")
101
+ * @returns Ruta absoluta del archivo compilado (ej: "/path/to/project/dist/server/pokedex/index.js")
102
+ */
103
+ function getCompiledProdPage(pageFile) {
104
+ if (!pageFile.endsWith('.tsx')) {
105
+ throw new Error(`getCompiledProdPage expects a .tsx file, got: ${pageFile}`);
106
+ }
107
+ // Si es una ruta absoluta, extraer solo la parte relativa
108
+ let relativePath;
109
+ if (node_path_1.default.isAbsolute(pageFile)) {
110
+ // Buscar la parte después de "app/pages/" or "app\pages\" (Windows-compatible)
111
+ const normalizedPath = pageFile.replace(/\\/g, '/');
112
+ const appPagesIndex = normalizedPath.indexOf('app/pages/');
113
+ if (appPagesIndex === -1) {
114
+ throw new Error(`Absolute path must contain "app/pages/", got: ${pageFile}`);
115
+ }
116
+ relativePath = normalizedPath.substring(appPagesIndex);
117
+ }
118
+ else {
119
+ relativePath = pageFile;
120
+ }
121
+ // Convertir app/pages/pokedex/index.tsx a dist/server/pokedex/index.js
122
+ const compiledRelativePath = relativePath
123
+ .replace(/^app\/pages\//, '') // Quitar prefijo app/pages/
124
+ .replace(/\.tsx$/, '.js'); // Cambiar extensión .tsx a .js
125
+ return node_path_1.default.resolve(process.cwd(), 'dist', 'server', compiledRelativePath);
126
+ }
87
127
  async function fileExists(file) {
88
128
  try {
89
129
  await promises_1.default.access(file);
@@ -238,59 +278,3 @@ async function getClientEntriesInput(distPath = 'dist') {
238
278
  }
239
279
  return input;
240
280
  }
241
- function createRenderServer(options = {}) {
242
- const pages = getPages();
243
- const { vite } = options;
244
- return async (renderOptions) => {
245
- const { url, props = {} } = renderOptions;
246
- // Encuentra la página que coincide con la URL
247
- const matchedPage = pages.find(page => {
248
- if (page.route === '/')
249
- return url === '/' || url === '';
250
- return url === page.route || url.startsWith(page.route + '/');
251
- });
252
- if (!matchedPage) {
253
- throw new Error(`Page not found for URL: ${url}`);
254
- }
255
- try {
256
- // Import dinámico de la página usando vite.ssrLoadModule si está disponible
257
- let pageModule;
258
- if (vite) {
259
- // En desarrollo: usar vite.ssrLoadModule para manejar .tsx
260
- const modulePath = `/${matchedPage.file}`;
261
- pageModule = await vite.ssrLoadModule(modulePath);
262
- }
263
- else {
264
- // En producción: usar import directo del archivo compilado
265
- const moduleUrl = matchedPage.abs.replace(/\.tsx$/, '.js').replace('/app/pages/', '/dist/server/');
266
- pageModule = await Promise.resolve(`${moduleUrl}`).then(s => __importStar(require(s)));
267
- }
268
- const PageComponent = pageModule.default;
269
- const getServerSideProps = pageModule.getServerSideProps;
270
- if (!PageComponent) {
271
- throw new Error(`No default export found in ${matchedPage.file}`);
272
- }
273
- // Si existe getServerSideProps, la ejecutamos para obtener props iniciales
274
- let finalProps = { ...props };
275
- if (getServerSideProps && typeof getServerSideProps === 'function') {
276
- console.log(`Calling getServerSideProps for ${matchedPage.route}`);
277
- const serverSideResult = await getServerSideProps();
278
- if (serverSideResult && serverSideResult.props) {
279
- finalProps = { ...finalProps, ...serverSideResult.props };
280
- }
281
- }
282
- // Renderiza el componente con las props finales
283
- const html = (0, server_1.renderToString)(react_1.default.createElement(PageComponent, finalProps));
284
- return {
285
- html,
286
- props: finalProps,
287
- route: matchedPage.route,
288
- page: matchedPage.file
289
- };
290
- }
291
- catch (error) {
292
- console.error(`Error rendering page ${matchedPage.route}:`, error);
293
- throw error;
294
- }
295
- };
296
- }
@@ -14,11 +14,3 @@ export interface PlatformInfo {
14
14
  * Detecta plataforma usando headers custom + User-Agent fallback
15
15
  */
16
16
  export declare function detectPlatform(userAgent: string, headers?: any): PlatformInfo;
17
- /**
18
- * Genera CSS class para HTML basado en platform info
19
- */
20
- export declare function getPlatformCSSClass(platform: PlatformInfo): string;
21
- /**
22
- * Determina qué entry-client usar basado en platform
23
- */
24
- export declare function resolveEntryClient(baseName: string, platform: PlatformInfo): string;
package/dist/platform.js CHANGED
@@ -5,8 +5,6 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.detectPlatform = detectPlatform;
8
- exports.getPlatformCSSClass = getPlatformCSSClass;
9
- exports.resolveEntryClient = resolveEntryClient;
10
8
  /**
11
9
  * Detecta plataforma usando headers custom + User-Agent fallback
12
10
  */
@@ -106,38 +104,3 @@ function detectFromUserAgent(userAgent) {
106
104
  source: 'user-agent'
107
105
  };
108
106
  }
109
- /**
110
- * Genera CSS class para HTML basado en platform info
111
- */
112
- function getPlatformCSSClass(platform) {
113
- const classes = [
114
- platform.category, // 'web', 'webview', 'native'
115
- platform.device, // 'phone', 'tablet', 'desktop'
116
- platform.os // 'ios', 'android', etc.
117
- ];
118
- return classes.join(' ');
119
- }
120
- /**
121
- * Determina qué entry-client usar basado en platform
122
- */
123
- function resolveEntryClient(baseName, platform) {
124
- const candidates = [
125
- // Específico para mobile: device.os (phone.ios, tablet.android)
126
- ...(platform.device !== 'desktop'
127
- ? [`${baseName}__entry-client.${platform.device}.${platform.os}.tsx`]
128
- : []),
129
- // OS específico: ios, android
130
- `${baseName}__entry-client.${platform.os}.tsx`,
131
- // Device: mobile, desktop, tablet
132
- `${baseName}__entry-client.${platform.device}.tsx`,
133
- // Legacy compatibility
134
- ...(platform.device === 'phone' || platform.device === 'tablet'
135
- ? [`${baseName}__entry-client.mobile.tsx`]
136
- : []),
137
- // Fallback
138
- `${baseName}__entry-client.tsx`
139
- ];
140
- // En producción, deberías verificar que el archivo existe
141
- // Por ahora retorna el primer candidato
142
- return candidates[0];
143
- }
package/dist/render.d.ts CHANGED
@@ -1,3 +1,8 @@
1
+ import { RequestHandler } from 'express';
2
+ /**
3
+ * RENDER MIDDLEWARE PARA EL ROUTER
4
+ */
5
+ export declare function createRenderMiddleware(page: any, options: any): RequestHandler;
1
6
  export interface RenderOptions {
2
7
  url: string;
3
8
  props?: any;
package/dist/render.js CHANGED
@@ -36,10 +36,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.createRenderMiddleware = createRenderMiddleware;
39
40
  exports.createRenderServer = createRenderServer;
40
41
  const react_1 = __importDefault(require("react"));
41
42
  const server_1 = require("react-dom/server");
42
43
  const pages_1 = require("./pages");
44
+ const request_handler_1 = require("./helpers/request-handler");
45
+ /**
46
+ * RENDER MIDDLEWARE PARA EL ROUTER
47
+ */
48
+ function createRenderMiddleware(page, options) {
49
+ return async (req, res, next) => {
50
+ try {
51
+ await (0, request_handler_1.processRequest)({ req, res, page, next }, options);
52
+ }
53
+ catch (error) {
54
+ next(error);
55
+ }
56
+ };
57
+ }
43
58
  function createRenderServer(options = {}) {
44
59
  const pages = (0, pages_1.getPages)();
45
60
  const { vite } = options;
@@ -64,28 +79,34 @@ function createRenderServer(options = {}) {
64
79
  }
65
80
  else {
66
81
  // En producción: usar import directo del archivo compilado
67
- const moduleUrl = matchedPage.abs.replace(/\.tsx$/, '.js').replace('/app/pages/', '/dist/server/');
68
- pageModule = await Promise.resolve(`${moduleUrl}`).then(s => __importStar(require(s)));
82
+ const moduleUrl = (0, pages_1.getCompiledProdPage)(matchedPage.abs);
83
+ try {
84
+ pageModule = await Promise.resolve(`${moduleUrl}`).then(s => __importStar(require(s)));
85
+ }
86
+ catch (importError) {
87
+ console.error('Error loading module:', importError);
88
+ throw importError;
89
+ }
69
90
  }
70
91
  const PageComponent = pageModule.default;
71
- const getServerSideProps = pageModule.getServerSideProps;
72
92
  if (!PageComponent) {
73
93
  throw new Error(`No default export found in ${matchedPage.file}`);
74
94
  }
75
- // Si existe getServerSideProps, la ejecutamos para obtener props iniciales
76
- let finalProps = { ...props };
77
- if (getServerSideProps && typeof getServerSideProps === 'function') {
78
- console.log(`Calling getServerSideProps for ${matchedPage.route}`);
79
- const serverSideResult = await getServerSideProps();
80
- if (serverSideResult && serverSideResult.props) {
81
- finalProps = { ...finalProps, ...serverSideResult.props };
82
- }
83
- }
95
+ // Los middlewares ya se ejecutaron antes de llegar aquí.
96
+ // `props` contiene todo lo que los middlewares pusieron en `res.locals`.
97
+ // Combinamos todo para SSR y luego filtramos lo sensible para el cliente.
98
+ const finalProps = {
99
+ ...props,
100
+ ...(props.serverSideProps || {})
101
+ };
84
102
  // Renderiza el componente con las props finales
85
103
  const html = (0, server_1.renderToString)(react_1.default.createElement(PageComponent, finalProps));
104
+ // Evitar mandar htmlConfig al cliente
105
+ const { htmlConfig, serverSideProps, ...rest } = finalProps;
106
+ const clientProps = serverSideProps || rest;
86
107
  return {
87
108
  html,
88
- props: finalProps,
109
+ props: clientProps,
89
110
  route: matchedPage.route,
90
111
  page: matchedPage.file
91
112
  };
package/dist/router.js CHANGED
@@ -11,7 +11,8 @@ const express_1 = require("express");
11
11
  const pages_1 = require("./pages");
12
12
  const express_2 = __importDefault(require("express"));
13
13
  const vite_config_1 = require("./helpers/vite-config");
14
- const request_handler_1 = require("./helpers/request-handler");
14
+ const middlewares_1 = require("./helpers/middlewares");
15
+ const render_1 = require("./render");
15
16
  async function createAutoViteServer(options = {}) {
16
17
  const { port = 5173, base = '/', enablePlatformDetection = true } = options;
17
18
  const isProduction = process.env.NODE_ENV === 'production';
@@ -36,12 +37,14 @@ async function createAutoViteServer(options = {}) {
36
37
  app.use(express_2.default.static('public'));
37
38
  const start = () => {
38
39
  return app.listen(port, () => {
39
- const pages = (0, pages_1.getPages)();
40
- console.log(`🚀 Auto Vite Server started at http://localhost:${port}`);
41
- console.log(`📄 Auto-detected routes:`);
42
- pages.forEach(page => {
43
- console.log(` ${page.route} -> ${page.file}`);
44
- });
40
+ if (process.env.NODE_ENV !== 'production') {
41
+ const pages = (0, pages_1.getPages)();
42
+ console.log(`🚀 Auto Vite Server started at http://localhost:${port}`);
43
+ console.log(`📄 Auto-detected routes:`);
44
+ pages.forEach(page => {
45
+ console.log(` ${page.route} -> ${page.file}`);
46
+ });
47
+ }
45
48
  });
46
49
  };
47
50
  return { app, vite: viteConfig.vite, start };
@@ -54,10 +57,9 @@ function createViteRouter(options = {}) {
54
57
  return createManualRouter(options);
55
58
  }
56
59
  function createAutoRouter(options) {
57
- const { enablePlatformDetection = true, renderFunction } = options;
60
+ const { renderFunction, enablePlatformDetection = true } = options;
58
61
  const isProduction = process.env.NODE_ENV === 'production';
59
62
  let viteConfig = null;
60
- let renderServer = null;
61
63
  let initialized = false;
62
64
  const mainRouter = (0, express_1.Router)();
63
65
  const initializeIfNeeded = async () => {
@@ -77,38 +79,79 @@ function createAutoRouter(options) {
77
79
  return viteConfig;
78
80
  };
79
81
  const pages = (0, pages_1.getPages)();
80
- pages.forEach(page => {
81
- mainRouter.get(page.route, async (req, res, next) => {
82
+ // TU PSEUDOCÓDIGO IMPLEMENTADO CORRECTAMENTE:
83
+ // Initialize Vite ONCE before setting up any routes
84
+ const setupRoutes = async () => {
85
+ if (!viteConfig)
82
86
  await initializeIfNeeded();
83
- await (0, request_handler_1.processRequest)({ req, res, page, next }, {
87
+ // Process pages sequentially to avoid race conditions
88
+ for (const page of pages) {
89
+ // Dynamic middleware loading for HMR support
90
+ const HMRMiddleware = await (0, middlewares_1.createDynamicPageMiddlewares)(page.route, page.file, viteConfig?.vite);
91
+ // Productive middlewares
92
+ const prevMiddlewares = await (0, middlewares_1.loadPageMiddlewares)(page.route, viteConfig?.vite);
93
+ const serverSidePropsMiddleware = await (0, middlewares_1.getServerSidePropsAsMiddleware)(page.file, viteConfig?.vite);
94
+ const renderMiddleware = (0, render_1.createRenderMiddleware)(page, {
84
95
  enablePlatformDetection,
85
96
  renderFunction,
86
- viteConfig
87
- }, renderServer);
88
- });
89
- });
97
+ viteConfig: () => viteConfig // pasar por función para evitar capturar null
98
+ });
99
+ const pageMiddlewares = isProduction ? [
100
+ ...prevMiddlewares,
101
+ serverSidePropsMiddleware,
102
+ renderMiddleware
103
+ ] : [
104
+ HMRMiddleware,
105
+ renderMiddleware
106
+ ];
107
+ mainRouter.get(page.route, ...pageMiddlewares);
108
+ // Error middleware separado
109
+ mainRouter.use(page.route, (0, middlewares_1.createPageErrorHandler)(page.file, viteConfig?.vite));
110
+ }
111
+ };
112
+ // Setup routes asynchronously but don't block router creation
113
+ setupRoutes().catch(console.error);
90
114
  return mainRouter;
91
115
  }
92
116
  function createManualRouter(options) {
93
- const { enablePlatformDetection = true, vite, templateHtml = '', isProduction = process.env.NODE_ENV === 'production', renderFunction } = options;
117
+ const { vite, renderFunction, enablePlatformDetection = true } = options;
94
118
  const router = (0, express_1.Router)();
95
119
  const pages = (0, pages_1.getPages)();
96
- let renderServer = null;
120
+ // Crear viteConfig para processRequest
97
121
  const viteConfig = {
98
122
  vite,
99
- manifest: {},
100
- templateHtml,
101
- isProduction
123
+ templateHtml: options.templateHtml || '',
124
+ isProduction: options.isProduction || false,
125
+ manifest: null
102
126
  };
103
- pages.forEach(page => {
104
- router.get(page.route, async (req, res, next) => {
105
- await (0, request_handler_1.processRequest)({ req, res, page, next }, {
127
+ // Process pages sequentially to avoid race conditions
128
+ const setupRoutes = async () => {
129
+ for (const page of pages) {
130
+ // Dynamic middleware loading for HMR support(only in dev)
131
+ const HMRMiddleware = await (0, middlewares_1.createDynamicPageMiddlewares)(page.route, page.file, vite);
132
+ // Productive middlewares
133
+ const prevMiddlewares = await (0, middlewares_1.loadPageMiddlewares)(page.route, vite);
134
+ const serverSidePropsMiddleware = await (0, middlewares_1.getServerSidePropsAsMiddleware)(page.file, vite);
135
+ const renderMiddleware = (0, render_1.createRenderMiddleware)(page, {
106
136
  enablePlatformDetection,
107
137
  renderFunction,
108
138
  viteConfig
109
- }, renderServer);
110
- });
111
- });
139
+ });
140
+ const pageMiddlewares = options.isProduction ? [
141
+ ...prevMiddlewares,
142
+ serverSidePropsMiddleware,
143
+ renderMiddleware
144
+ ] : [
145
+ HMRMiddleware,
146
+ renderMiddleware
147
+ ];
148
+ router.get(page.route, ...pageMiddlewares);
149
+ // Error middleware separado
150
+ router.use(page.route, (0, middlewares_1.createPageErrorHandler)(page.file, vite));
151
+ }
152
+ };
153
+ // Setup routes asynchronously but don't block router creation
154
+ setupRoutes().catch(console.error);
112
155
  return router;
113
156
  }
114
157
  function listDetectedPages() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ressjs/vite-router",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Express router factory for ress.js with automatic page detection and SSR",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",