@ressjs/vite-router 0.4.1 → 0.5.0
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 +444 -69
- package/dist/helpers/html-generator.d.ts +1 -0
- package/dist/helpers/html-generator.js +43 -5
- package/dist/helpers/middlewares.d.ts +72 -0
- package/dist/helpers/middlewares.js +381 -0
- package/dist/helpers/request-handler.js +21 -4
- package/dist/helpers/vite-config.d.ts +1 -1
- package/dist/helpers/vite-config.js +8 -15
- package/dist/index.d.ts +3 -2
- package/dist/index.js +5 -4
- package/dist/pages.d.ts +17 -13
- package/dist/pages.js +64 -61
- package/dist/platform.d.ts +0 -8
- package/dist/platform.js +0 -37
- package/dist/render.d.ts +5 -0
- package/dist/render.js +50 -17
- package/dist/router.js +70 -27
- package/package.json +2 -2
package/dist/pages.js
CHANGED
|
@@ -36,19 +36,29 @@ 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.convertRouteToExpress = convertRouteToExpress;
|
|
39
40
|
exports.getPages = getPages;
|
|
40
41
|
exports.getViteInput = getViteInput;
|
|
42
|
+
exports.getViteSSRInput = getViteSSRInput;
|
|
41
43
|
exports.loadManifest = loadManifest;
|
|
44
|
+
exports.getCompiledProdPage = getCompiledProdPage;
|
|
42
45
|
exports.resolvePlatformCSS = resolvePlatformCSS;
|
|
43
46
|
exports.generateTempEntries = generateTempEntries;
|
|
44
47
|
exports.generateSingleEntry = generateSingleEntry;
|
|
45
48
|
exports.getClientEntriesInput = getClientEntriesInput;
|
|
46
|
-
exports.createRenderServer = createRenderServer;
|
|
47
49
|
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
48
50
|
const node_path_1 = __importDefault(require("node:path"));
|
|
49
51
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Convierte rutas estilo Next.js con parámetros dinámicos a formato Express
|
|
54
|
+
* Ejemplos:
|
|
55
|
+
* '/photocard/[idPhotocard]' → '/photocard/:idPhotocard'
|
|
56
|
+
* '/products/[category]/[id]' → '/products/:category/:id'
|
|
57
|
+
* '/home' → '/home' (sin cambios)
|
|
58
|
+
*/
|
|
59
|
+
function convertRouteToExpress(route) {
|
|
60
|
+
return route.replace(/\[([^\]]+)\]/g, ':$1');
|
|
61
|
+
}
|
|
52
62
|
function getPages() {
|
|
53
63
|
// Busca tanto page.tsx como page/index.tsx y prioriza el más corto
|
|
54
64
|
const files = fast_glob_1.default.sync('app/pages/**/*.{tsx,jsx}');
|
|
@@ -60,7 +70,8 @@ function getPages() {
|
|
|
60
70
|
// Prioriza page.tsx sobre page/index.tsx
|
|
61
71
|
if (!seen.has(route)) {
|
|
62
72
|
seen.add(route);
|
|
63
|
-
|
|
73
|
+
const expressRoute = convertRouteToExpress(route);
|
|
74
|
+
pages.push({ route, expressRoute, file, abs: node_path_1.default.resolve(file) });
|
|
64
75
|
}
|
|
65
76
|
}
|
|
66
77
|
return pages;
|
|
@@ -74,6 +85,17 @@ function getViteInput() {
|
|
|
74
85
|
}
|
|
75
86
|
return input;
|
|
76
87
|
}
|
|
88
|
+
// Para Vite SSR: input incluyendo páginas + middlewares
|
|
89
|
+
function getViteSSRInput() {
|
|
90
|
+
const input = getViteInput(); // Empezar con las páginas
|
|
91
|
+
// Agregar TODOS los middlewares: .middlewares.ts y middlewares.ts
|
|
92
|
+
const middlewareFiles = fast_glob_1.default.sync('app/pages/**/{middlewares,*.middlewares}.{ts,js}');
|
|
93
|
+
for (const middlewareFile of middlewareFiles) {
|
|
94
|
+
const key = middlewareFile.replace(/^app\/pages\//, '').replace(/\.(ts|js)$/, '');
|
|
95
|
+
input[key] = node_path_1.default.resolve(middlewareFile);
|
|
96
|
+
}
|
|
97
|
+
return input;
|
|
98
|
+
}
|
|
77
99
|
async function loadManifest(distPath = 'dist') {
|
|
78
100
|
const assetsDir = node_path_1.default.join(distPath, 'server/.vite');
|
|
79
101
|
const files = await promises_1.default.readdir(assetsDir);
|
|
@@ -84,6 +106,38 @@ async function loadManifest(distPath = 'dist') {
|
|
|
84
106
|
const manifest = (await Promise.resolve(`${node_path_1.default.join(assetsDir, manifestFile)}`).then(s => __importStar(require(s)))).default;
|
|
85
107
|
return manifest;
|
|
86
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Convierte una ruta de página TypeScript a su equivalente compilado en producción
|
|
111
|
+
*
|
|
112
|
+
* @param pageFile - Ruta del archivo de página (relativa: "app/pages/pokedex/index.tsx" o absoluta: "/path/to/app/pages/pokedex/index.tsx")
|
|
113
|
+
* @returns Ruta absoluta del archivo compilado (ej: "/path/to/project/dist/server/pokedex/index.js")
|
|
114
|
+
*/
|
|
115
|
+
function getCompiledProdPage(pageFile) {
|
|
116
|
+
if (!pageFile.endsWith('.tsx')) {
|
|
117
|
+
throw new Error(`getCompiledProdPage expects a .tsx file, got: ${pageFile}`);
|
|
118
|
+
}
|
|
119
|
+
// Si es una ruta absoluta, extraer solo la parte relativa
|
|
120
|
+
let relativePath;
|
|
121
|
+
if (node_path_1.default.isAbsolute(pageFile)) {
|
|
122
|
+
// Buscar la parte después de "app/pages/" or "app\pages\" (Windows-compatible)
|
|
123
|
+
const normalizedPath = pageFile.replace(/\\/g, '/');
|
|
124
|
+
const appPagesIndex = normalizedPath.indexOf('app/pages/');
|
|
125
|
+
if (appPagesIndex === -1) {
|
|
126
|
+
throw new Error(`Absolute path must contain "app/pages/", got: ${pageFile}`);
|
|
127
|
+
}
|
|
128
|
+
relativePath = normalizedPath.substring(appPagesIndex);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
relativePath = pageFile;
|
|
132
|
+
}
|
|
133
|
+
// Convertir app/pages/pokedex/index.tsx a dist/server/pokedex/index.js
|
|
134
|
+
// También convierte [id] a _id_ para rutas dinámicas
|
|
135
|
+
const compiledRelativePath = relativePath
|
|
136
|
+
.replace(/^app\/pages\//, '') // Quitar prefijo app/pages/
|
|
137
|
+
.replace(/\.tsx$/, '.js') // Cambiar extensión .tsx a .js
|
|
138
|
+
.replace(/\[([^\]]+)\]/g, '_$1_'); // Convertir [id] a _id_
|
|
139
|
+
return node_path_1.default.resolve(process.cwd(), 'dist', 'server', compiledRelativePath);
|
|
140
|
+
}
|
|
87
141
|
async function fileExists(file) {
|
|
88
142
|
try {
|
|
89
143
|
await promises_1.default.access(file);
|
|
@@ -145,7 +199,12 @@ async function generateTempEntries(distPath = 'dist', platformInfo) {
|
|
|
145
199
|
// Solo crea el directorio si no existe, no lo borra
|
|
146
200
|
await promises_1.default.mkdir(entriesDir, { recursive: true });
|
|
147
201
|
const promises = pages.map(async (page) => {
|
|
148
|
-
|
|
202
|
+
// Sanitizar nombre: convertir [id] a _id_ para nombres de archivo
|
|
203
|
+
const rel = page.file
|
|
204
|
+
.replace(/^app\/pages\//, '')
|
|
205
|
+
.replace(/\.tsx$|\.jsx$/, '')
|
|
206
|
+
.replace(/\//g, '__')
|
|
207
|
+
.replace(/\[([^\]]+)\]/g, '_$1_');
|
|
149
208
|
if (platformInfo && platformInfo.device !== 'desktop') {
|
|
150
209
|
// Solo genera entry específico para mobile devices (phone, tablet)
|
|
151
210
|
const basePath = page.file.replace(/\.(tsx|jsx)$/, '');
|
|
@@ -238,59 +297,3 @@ async function getClientEntriesInput(distPath = 'dist') {
|
|
|
238
297
|
}
|
|
239
298
|
return input;
|
|
240
299
|
}
|
|
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
|
-
}
|
package/dist/platform.d.ts
CHANGED
|
@@ -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
package/dist/render.js
CHANGED
|
@@ -36,21 +36,48 @@ 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;
|
|
46
61
|
return async (renderOptions) => {
|
|
47
62
|
const { url, props = {} } = renderOptions;
|
|
48
63
|
// Encuentra la página que coincide con la URL
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
// Función helper para hacer matching de rutas dinámicas
|
|
65
|
+
const matchRoute = (pageRoute, url) => {
|
|
66
|
+
if (pageRoute === '/')
|
|
51
67
|
return url === '/' || url === '';
|
|
52
|
-
|
|
53
|
-
|
|
68
|
+
// Si no tiene parámetros dinámicos, hacer matching exacto
|
|
69
|
+
if (!pageRoute.includes('[')) {
|
|
70
|
+
return url === pageRoute || url.startsWith(pageRoute + '/');
|
|
71
|
+
}
|
|
72
|
+
// Convertir ruta de página a regex para matching dinámico
|
|
73
|
+
// Ejemplo: /photocard/[id] → /^\/photocard\/([^\/]+)$/
|
|
74
|
+
const regexPattern = pageRoute
|
|
75
|
+
.replace(/\[([^\]]+)\]/g, '([^/]+)') // [id] → ([^/]+)
|
|
76
|
+
.replace(/\//g, '\\/'); // escapar slashes
|
|
77
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
78
|
+
return regex.test(url);
|
|
79
|
+
};
|
|
80
|
+
const matchedPage = pages.find(page => matchRoute(page.route, url));
|
|
54
81
|
if (!matchedPage) {
|
|
55
82
|
throw new Error(`Page not found for URL: ${url}`);
|
|
56
83
|
}
|
|
@@ -64,28 +91,34 @@ function createRenderServer(options = {}) {
|
|
|
64
91
|
}
|
|
65
92
|
else {
|
|
66
93
|
// En producción: usar import directo del archivo compilado
|
|
67
|
-
const moduleUrl =
|
|
68
|
-
|
|
94
|
+
const moduleUrl = (0, pages_1.getCompiledProdPage)(matchedPage.abs);
|
|
95
|
+
try {
|
|
96
|
+
pageModule = await Promise.resolve(`${moduleUrl}`).then(s => __importStar(require(s)));
|
|
97
|
+
}
|
|
98
|
+
catch (importError) {
|
|
99
|
+
console.error('Error loading module:', importError);
|
|
100
|
+
throw importError;
|
|
101
|
+
}
|
|
69
102
|
}
|
|
70
103
|
const PageComponent = pageModule.default;
|
|
71
|
-
const getServerSideProps = pageModule.getServerSideProps;
|
|
72
104
|
if (!PageComponent) {
|
|
73
105
|
throw new Error(`No default export found in ${matchedPage.file}`);
|
|
74
106
|
}
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
}
|
|
107
|
+
// Los middlewares ya se ejecutaron antes de llegar aquí.
|
|
108
|
+
// `props` contiene todo lo que los middlewares pusieron en `res.locals`.
|
|
109
|
+
// Combinamos todo para SSR y luego filtramos lo sensible para el cliente.
|
|
110
|
+
const finalProps = {
|
|
111
|
+
...props,
|
|
112
|
+
...(props.serverSideProps || {})
|
|
113
|
+
};
|
|
84
114
|
// Renderiza el componente con las props finales
|
|
85
115
|
const html = (0, server_1.renderToString)(react_1.default.createElement(PageComponent, finalProps));
|
|
116
|
+
// Evitar mandar htmlConfig al cliente
|
|
117
|
+
const { htmlConfig, serverSideProps, ...rest } = finalProps;
|
|
118
|
+
const clientProps = serverSideProps || rest;
|
|
86
119
|
return {
|
|
87
120
|
html,
|
|
88
|
-
props:
|
|
121
|
+
props: clientProps,
|
|
89
122
|
route: matchedPage.route,
|
|
90
123
|
page: matchedPage.file
|
|
91
124
|
};
|
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
|
|
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,15 @@ async function createAutoViteServer(options = {}) {
|
|
|
36
37
|
app.use(express_2.default.static('public'));
|
|
37
38
|
const start = () => {
|
|
38
39
|
return app.listen(port, () => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
+
const expressDisplay = page.route !== page.expressRoute ? ` (Express: ${page.expressRoute})` : '';
|
|
46
|
+
console.log(` ${page.route}${expressDisplay} -> ${page.file}`);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
45
49
|
});
|
|
46
50
|
};
|
|
47
51
|
return { app, vite: viteConfig.vite, start };
|
|
@@ -54,10 +58,9 @@ function createViteRouter(options = {}) {
|
|
|
54
58
|
return createManualRouter(options);
|
|
55
59
|
}
|
|
56
60
|
function createAutoRouter(options) {
|
|
57
|
-
const { enablePlatformDetection = true
|
|
61
|
+
const { renderFunction, enablePlatformDetection = true } = options;
|
|
58
62
|
const isProduction = process.env.NODE_ENV === 'production';
|
|
59
63
|
let viteConfig = null;
|
|
60
|
-
let renderServer = null;
|
|
61
64
|
let initialized = false;
|
|
62
65
|
const mainRouter = (0, express_1.Router)();
|
|
63
66
|
const initializeIfNeeded = async () => {
|
|
@@ -77,38 +80,78 @@ function createAutoRouter(options) {
|
|
|
77
80
|
return viteConfig;
|
|
78
81
|
};
|
|
79
82
|
const pages = (0, pages_1.getPages)();
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
// Initialize Vite ONCE before setting up any routes
|
|
84
|
+
const setupRoutes = async () => {
|
|
85
|
+
if (!viteConfig)
|
|
82
86
|
await initializeIfNeeded();
|
|
83
|
-
|
|
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
|
-
}
|
|
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.expressRoute, ...pageMiddlewares);
|
|
108
|
+
// Error middleware separado
|
|
109
|
+
mainRouter.use(page.expressRoute, (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 {
|
|
117
|
+
const { vite, renderFunction, enablePlatformDetection = true } = options;
|
|
94
118
|
const router = (0, express_1.Router)();
|
|
95
119
|
const pages = (0, pages_1.getPages)();
|
|
96
|
-
|
|
120
|
+
// Crear viteConfig para processRequest
|
|
97
121
|
const viteConfig = {
|
|
98
122
|
vite,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
123
|
+
templateHtml: options.templateHtml || '',
|
|
124
|
+
isProduction: options.isProduction || false,
|
|
125
|
+
manifest: null
|
|
102
126
|
};
|
|
103
|
-
pages
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
139
|
+
});
|
|
140
|
+
const pageMiddlewares = options.isProduction ? [
|
|
141
|
+
...prevMiddlewares,
|
|
142
|
+
serverSidePropsMiddleware,
|
|
143
|
+
renderMiddleware
|
|
144
|
+
] : [
|
|
145
|
+
HMRMiddleware,
|
|
146
|
+
renderMiddleware
|
|
147
|
+
];
|
|
148
|
+
router.get(page.expressRoute, ...pageMiddlewares);
|
|
149
|
+
// Error middleware separado
|
|
150
|
+
router.use(page.expressRoute, (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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ressjs/vite-router",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Express router factory for ress.js with automatic page detection and
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Express router factory for ress.js with automatic page detection, SSR and dynamic routes support",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"publishConfig": {
|