@ressjs/vite-router 0.5.2 → 0.6.0-rc.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/LICENSE +69 -0
- package/README.md +9 -515
- package/dist/client/entry.d.mts +2 -0
- package/dist/client/entry.mjs +1 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +8 -0
- package/dist/config/base-path.d.ts +44 -0
- package/dist/config/base-path.js +100 -0
- package/dist/config/codegen.d.ts +29 -0
- package/dist/config/codegen.js +131 -0
- package/dist/config/define.d.ts +8 -0
- package/dist/config/define.js +12 -0
- package/dist/config/env.d.ts +19 -0
- package/dist/config/env.js +40 -0
- package/dist/config/index.d.ts +18 -0
- package/dist/config/index.js +46 -0
- package/dist/config/load.d.ts +28 -0
- package/dist/config/load.js +82 -0
- package/dist/config/middleware.d.ts +18 -0
- package/dist/config/middleware.js +79 -0
- package/dist/config/rules.d.ts +59 -0
- package/dist/config/rules.js +162 -0
- package/dist/config/types.d.ts +189 -0
- package/dist/config/types.js +2 -0
- package/dist/config/validate.d.ts +19 -0
- package/dist/config/validate.js +143 -0
- package/dist/config/watch.d.ts +53 -0
- package/dist/config/watch.js +163 -0
- package/dist/fs/module-extensions.d.ts +105 -0
- package/dist/fs/module-extensions.js +213 -0
- package/dist/head/resolve.d.ts +5 -0
- package/dist/head/resolve.js +166 -0
- package/dist/head/types.d.ts +44 -0
- package/dist/head/types.js +2 -0
- package/dist/helpers/html-generator.d.ts +26 -6
- package/dist/helpers/html-generator.js +96 -138
- package/dist/helpers/middlewares.d.ts +32 -21
- package/dist/helpers/middlewares.js +181 -159
- package/dist/helpers/page-config-merge.d.ts +11 -0
- package/dist/helpers/page-config-merge.js +84 -0
- package/dist/helpers/request-handler.d.ts +15 -2
- package/dist/helpers/request-handler.js +164 -27
- package/dist/index.d.ts +35 -3
- package/dist/index.js +77 -8
- package/dist/isr/capture.d.ts +79 -0
- package/dist/isr/capture.js +222 -0
- package/dist/isr/handler.d.ts +49 -0
- package/dist/isr/handler.js +207 -0
- package/dist/isr/key.d.ts +26 -0
- package/dist/isr/key.js +59 -0
- package/dist/isr/page-config.d.ts +17 -0
- package/dist/isr/page-config.js +71 -0
- package/dist/isr/preview.d.ts +5 -0
- package/dist/isr/preview.js +38 -0
- package/dist/isr/public-request.d.ts +50 -0
- package/dist/isr/public-request.js +108 -0
- package/dist/isr/response.d.ts +41 -0
- package/dist/isr/response.js +128 -0
- package/dist/isr/store.d.ts +42 -0
- package/dist/isr/store.js +108 -0
- package/dist/isr/types.d.ts +62 -0
- package/dist/isr/types.js +2 -0
- package/dist/pages.d.ts +10 -9
- package/dist/pages.js +42 -261
- package/dist/platform.d.ts +11 -14
- package/dist/platform.js +18 -102
- package/dist/plugin/environments.d.ts +68 -0
- package/dist/plugin/environments.js +74 -0
- package/dist/plugin/index.d.ts +59 -0
- package/dist/plugin/index.js +195 -0
- package/dist/plugin/route-manifest.d.ts +19 -0
- package/dist/plugin/route-manifest.js +55 -0
- package/dist/plugin/virtual-entries.d.ts +26 -0
- package/dist/plugin/virtual-entries.js +80 -0
- package/dist/render.d.ts +39 -2
- package/dist/render.js +75 -77
- package/dist/router.d.ts +32 -13
- package/dist/router.js +180 -146
- package/dist/routes/dispatcher.d.ts +58 -0
- package/dist/routes/dispatcher.js +70 -0
- package/dist/routes/manifest.d.ts +17 -0
- package/dist/routes/manifest.js +62 -0
- package/dist/routes/match.d.ts +20 -0
- package/dist/routes/match.js +75 -0
- package/dist/routes/module.d.ts +14 -0
- package/dist/routes/module.js +30 -0
- package/dist/routes/parse.d.ts +31 -0
- package/dist/routes/parse.js +114 -0
- package/dist/routes/rank.d.ts +12 -0
- package/dist/routes/rank.js +49 -0
- package/dist/routes/router.d.ts +54 -0
- package/dist/routes/router.js +153 -0
- package/dist/routes/scan.d.ts +26 -0
- package/dist/routes/scan.js +98 -0
- package/dist/routes/types.d.ts +114 -0
- package/dist/routes/types.js +17 -0
- package/dist/runtime/dev-server.d.ts +64 -0
- package/dist/runtime/dev-server.js +94 -0
- package/dist/runtime/dev-styles.d.ts +13 -0
- package/dist/runtime/dev-styles.js +50 -0
- package/dist/runtime/module-loader.d.ts +55 -0
- package/dist/runtime/module-loader.js +122 -0
- package/dist/runtime/prod-server.d.ts +55 -0
- package/dist/runtime/prod-server.js +188 -0
- package/dist/runtime/template.d.ts +10 -0
- package/dist/runtime/template.js +33 -0
- package/dist/security/client-props.d.ts +25 -0
- package/dist/security/client-props.js +51 -0
- package/dist/security/config.d.ts +121 -0
- package/dist/security/config.js +77 -0
- package/dist/security/csp.d.ts +53 -0
- package/dist/security/csp.js +118 -0
- package/dist/security/dev-hardening.d.ts +46 -0
- package/dist/security/dev-hardening.js +65 -0
- package/dist/security/errors.d.ts +37 -0
- package/dist/security/errors.js +84 -0
- package/dist/security/escape.d.ts +40 -0
- package/dist/security/escape.js +90 -0
- package/dist/security/head-tags.d.ts +32 -0
- package/dist/security/head-tags.js +156 -0
- package/dist/security/headers.d.ts +76 -0
- package/dist/security/headers.js +278 -0
- package/dist/security/index.d.ts +24 -0
- package/dist/security/index.js +49 -0
- package/dist/security/serialize.d.ts +48 -0
- package/dist/security/serialize.js +146 -0
- package/dist/variants/assets.d.ts +33 -0
- package/dist/variants/assets.js +144 -0
- package/dist/variants/catalog.d.ts +33 -0
- package/dist/variants/catalog.js +79 -0
- package/dist/variants/platform-tokens.d.ts +9 -0
- package/dist/variants/platform-tokens.js +15 -0
- package/dist/variants/resolve.d.ts +40 -0
- package/dist/variants/resolve.js +90 -0
- package/dist/variants/suffix.d.ts +8 -0
- package/dist/variants/suffix.js +12 -0
- package/dist/variants/types.d.ts +72 -0
- package/dist/variants/types.js +2 -0
- package/package.json +23 -11
- package/dist/helpers/vite-config.d.ts +0 -10
- package/dist/helpers/vite-config.js +0 -90
|
@@ -1,85 +1,108 @@
|
|
|
1
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
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
4
|
};
|
|
38
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.middlewareAppliesTo = middlewareAppliesTo;
|
|
7
|
+
exports.toMiddlewareEntry = toMiddlewareEntry;
|
|
8
|
+
exports.middlewaresFromManifest = middlewaresFromManifest;
|
|
39
9
|
exports.getMiddlewares = getMiddlewares;
|
|
40
10
|
exports.loadPageMiddlewares = loadPageMiddlewares;
|
|
41
11
|
exports.loadPageModule = loadPageModule;
|
|
42
12
|
exports.createGetServerSidePropsMiddleware = createGetServerSidePropsMiddleware;
|
|
43
13
|
exports.createPageErrorHandler = createPageErrorHandler;
|
|
44
|
-
exports.createDynamicPageMiddlewares = createDynamicPageMiddlewares;
|
|
45
14
|
exports.getPagePrevMiddlewares = getPagePrevMiddlewares;
|
|
46
15
|
exports.getServerSidePropsAsMiddleware = getServerSidePropsAsMiddleware;
|
|
47
16
|
exports.getErrorMiddleware = getErrorMiddleware;
|
|
48
17
|
const node_path_1 = __importDefault(require("node:path"));
|
|
18
|
+
// En Windows una ruta absoluta (`D:\\…`) no es un especificador válido para
|
|
19
|
+
// `import()`: hay que pasarla como URL `file://`. Sin esto, los middlewares no
|
|
20
|
+
// cargaban en producción y la ruta quedaba sin ellos.
|
|
21
|
+
const node_url_1 = require("node:url");
|
|
49
22
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
50
|
-
const
|
|
23
|
+
const prod_server_1 = require("../runtime/prod-server");
|
|
24
|
+
const environments_1 = require("../plugin/environments");
|
|
25
|
+
const module_1 = require("../routes/module");
|
|
26
|
+
const module_extensions_1 = require("../fs/module-extensions");
|
|
27
|
+
const page_config_1 = require("../isr/page-config");
|
|
28
|
+
const page_config_merge_1 = require("./page-config-merge");
|
|
29
|
+
/**
|
|
30
|
+
* Si un middleware de carpeta con alcance `scope` aplica a `route`.
|
|
31
|
+
*
|
|
32
|
+
* Se compara por segmentos: `admin/middlewares.ts` protege `/admin` y
|
|
33
|
+
* `/admin/x`, pero no `/administrator`, que sólo comparte el prefijo de texto.
|
|
34
|
+
* La raíz aplica a todo.
|
|
35
|
+
*/
|
|
36
|
+
function middlewareAppliesTo(scope, route) {
|
|
37
|
+
const scopeSegments = scope.split('/').filter(Boolean);
|
|
38
|
+
const routeSegments = route.split('/').filter(Boolean);
|
|
39
|
+
if (scopeSegments.length > routeSegments.length)
|
|
40
|
+
return false;
|
|
41
|
+
return scopeSegments.every((segment, i) => routeSegments[i] === segment);
|
|
42
|
+
}
|
|
43
|
+
/** Los middlewares que corren para una ruta: los de carpeta que la contienen y el de la página. */
|
|
44
|
+
function middlewaresFor(all, pageRoute) {
|
|
45
|
+
return all.filter((middleware) => middleware.type === 'page-specific'
|
|
46
|
+
? middleware.route === pageRoute
|
|
47
|
+
: middlewareAppliesTo(middleware.route, pageRoute));
|
|
48
|
+
}
|
|
49
|
+
/** Lo que el build escribe en el manifest por cada middleware. */
|
|
50
|
+
function toMiddlewareEntry(info) {
|
|
51
|
+
return {
|
|
52
|
+
file: info.file,
|
|
53
|
+
route: info.route,
|
|
54
|
+
type: info.type,
|
|
55
|
+
depth: info.depth,
|
|
56
|
+
server: { devId: info.file },
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** Los middlewares tal como los registró el build, listos para cargar. */
|
|
60
|
+
function middlewaresFromManifest(entries) {
|
|
61
|
+
return entries.map((entry) => ({
|
|
62
|
+
route: entry.route,
|
|
63
|
+
file: entry.file,
|
|
64
|
+
abs: node_path_1.default.resolve(entry.file),
|
|
65
|
+
type: entry.type,
|
|
66
|
+
depth: entry.depth,
|
|
67
|
+
buildChunk: entry.server.buildChunk,
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
51
70
|
/**
|
|
52
71
|
* Busca archivos de middlewares tanto específicos por página como globales por carpeta
|
|
53
72
|
*/
|
|
54
|
-
function getMiddlewares() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
73
|
+
function getMiddlewares(options = {}) {
|
|
74
|
+
const cwd = options.cwd ?? process.cwd();
|
|
75
|
+
// Las dos formas: `algo.middlewares.<ext>` para una página, `middlewares.<ext>`
|
|
76
|
+
// para una carpeta. Qué extensiones cuentan lo declara la política, no este archivo.
|
|
77
|
+
const [globalGlob, pageGlobPattern] = (0, module_extensions_1.middlewareGlobs)((0, module_extensions_1.getExtensionPolicy)());
|
|
78
|
+
const files = fast_glob_1.default.sync(pageGlobPattern, { cwd }).sort();
|
|
79
|
+
const globalFiles = fast_glob_1.default.sync(globalGlob, { cwd }).sort();
|
|
58
80
|
const middlewares = [];
|
|
59
81
|
// Procesar archivos específicos de página: page.middlewares.ts
|
|
60
82
|
for (const file of files) {
|
|
61
|
-
|
|
62
|
-
|
|
83
|
+
// La derivación recorta cualquier extensión reconocida: antes sólo quitaba
|
|
84
|
+
// `.ts` y `.js`, así que un `.middlewares.tsx` producía una ruta con la
|
|
85
|
+
// extensión adentro, no coincidía con ninguna página y no corría nunca.
|
|
86
|
+
let route = (0, module_extensions_1.middlewareRoute)(file).replace(/\/index$/, '') || '/';
|
|
63
87
|
// Calcular depth: contar slashes en la ruta del archivo
|
|
64
88
|
const depth = (file.match(/\//g) || []).length;
|
|
65
89
|
middlewares.push({
|
|
66
90
|
route,
|
|
67
91
|
file,
|
|
68
|
-
abs: node_path_1.default.resolve(file),
|
|
92
|
+
abs: node_path_1.default.resolve(cwd, file),
|
|
69
93
|
type: 'page-specific',
|
|
70
94
|
depth
|
|
71
95
|
});
|
|
72
96
|
}
|
|
73
97
|
// Procesar archivos globales: middlewares.ts
|
|
74
98
|
for (const file of globalFiles) {
|
|
75
|
-
let route =
|
|
76
|
-
route = route || '/';
|
|
99
|
+
let route = (0, module_extensions_1.middlewareRoute)(file) || '/';
|
|
77
100
|
// Calcular depth: contar slashes en la ruta del archivo
|
|
78
101
|
const depth = (file.match(/\//g) || []).length;
|
|
79
102
|
middlewares.push({
|
|
80
103
|
route,
|
|
81
104
|
file,
|
|
82
|
-
abs: node_path_1.default.resolve(file),
|
|
105
|
+
abs: node_path_1.default.resolve(cwd, file),
|
|
83
106
|
type: 'folder-global',
|
|
84
107
|
depth
|
|
85
108
|
});
|
|
@@ -89,21 +112,9 @@ function getMiddlewares() {
|
|
|
89
112
|
/**
|
|
90
113
|
* Carga middlewares para una página específica y los convierte en middlewares de Express
|
|
91
114
|
*/
|
|
92
|
-
async function loadPageMiddlewares(pageRoute,
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
});
|
|
115
|
+
async function loadPageMiddlewares(pageRoute, loader, middlewares) {
|
|
116
|
+
// Los que registró el build, si están; si no (desarrollo), el sistema de archivos.
|
|
117
|
+
const relevantMiddlewares = middlewaresFor(middlewares ?? getMiddlewares(), pageRoute);
|
|
107
118
|
// Ordenar por jerarquía: depth menor primero, luego por tipo
|
|
108
119
|
relevantMiddlewares.sort((a, b) => {
|
|
109
120
|
// Primero por depth (carpetas más arriba en la jerarquía van primero)
|
|
@@ -121,7 +132,7 @@ async function loadPageMiddlewares(pageRoute, vite) {
|
|
|
121
132
|
// Cargar middlewares de archivos .middlewares.ts
|
|
122
133
|
for (const middlewareFile of relevantMiddlewares) {
|
|
123
134
|
try {
|
|
124
|
-
const moduleToLoad = await loadMiddlewareModule(middlewareFile,
|
|
135
|
+
const moduleToLoad = await loadMiddlewareModule(middlewareFile, loader);
|
|
125
136
|
const handlers = moduleToLoad.default || [];
|
|
126
137
|
for (const handler of handlers) {
|
|
127
138
|
if (typeof handler === 'function') {
|
|
@@ -130,7 +141,15 @@ async function loadPageMiddlewares(pageRoute, vite) {
|
|
|
130
141
|
}
|
|
131
142
|
}
|
|
132
143
|
catch (error) {
|
|
133
|
-
|
|
144
|
+
// Fallo cerrado: un middleware que no carga no desaparece de la cadena,
|
|
145
|
+
// porque si protegía la ruta la dejaría abierta. En producción no se
|
|
146
|
+
// arranca; en desarrollo la ruta responde con error hasta que cargue.
|
|
147
|
+
const failure = new Error(`[ress] No se pudo cargar el middleware "${middlewareFile.file}": ` +
|
|
148
|
+
(error instanceof Error ? error.message : String(error)), { cause: error });
|
|
149
|
+
if (process.env.NODE_ENV === 'production')
|
|
150
|
+
throw failure;
|
|
151
|
+
console.error(failure.message);
|
|
152
|
+
expressMiddlewares.push((_req, _res, next) => next(failure));
|
|
134
153
|
}
|
|
135
154
|
}
|
|
136
155
|
return expressMiddlewares;
|
|
@@ -138,7 +157,7 @@ async function loadPageMiddlewares(pageRoute, vite) {
|
|
|
138
157
|
/**
|
|
139
158
|
* Carga el módulo completo de una página
|
|
140
159
|
*/
|
|
141
|
-
async function loadPageModule(pageFile,
|
|
160
|
+
async function loadPageModule(pageFile, loader) {
|
|
142
161
|
const isProduction = process.env.NODE_ENV === 'production';
|
|
143
162
|
const cacheKey = `${pageFile}-${process.env.NODE_ENV || 'development'}`;
|
|
144
163
|
// Only use cache in production mode to allow HMR in development
|
|
@@ -147,19 +166,12 @@ async function loadPageModule(pageFile, vite) {
|
|
|
147
166
|
}
|
|
148
167
|
try {
|
|
149
168
|
let pageModule;
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
pageModule = await vite.ssrLoadModule(modulePath);
|
|
169
|
+
if (loader) {
|
|
170
|
+
pageModule = await loader.load(`/${pageFile}`);
|
|
153
171
|
}
|
|
154
172
|
else {
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
}
|
|
173
|
+
const moduleUrl = (0, prod_server_1.resolveServerModulePath)(pageFile);
|
|
174
|
+
pageModule = await import(/* @vite-ignore */ (0, node_url_1.pathToFileURL)(moduleUrl).href);
|
|
163
175
|
}
|
|
164
176
|
const result = pageModule;
|
|
165
177
|
// Only cache in production mode
|
|
@@ -180,7 +192,10 @@ async function loadPageModule(pageFile, vite) {
|
|
|
180
192
|
/**
|
|
181
193
|
* Convierte getServerSideProps en un middleware de Express
|
|
182
194
|
*/
|
|
183
|
-
function createGetServerSidePropsMiddleware(pageModule) {
|
|
195
|
+
function createGetServerSidePropsMiddleware(pageModule, file = 'la página') {
|
|
196
|
+
// Se declara acá afuera, no dentro del handler: tiene que sobrevivir entre
|
|
197
|
+
// requests para que el aviso salga una sola vez por página y no en cada hit.
|
|
198
|
+
let warnedAboutLegacyHeadApi = false;
|
|
184
199
|
return async (req, res, next) => {
|
|
185
200
|
if (!pageModule.getServerSideProps) {
|
|
186
201
|
next();
|
|
@@ -190,13 +205,30 @@ function createGetServerSidePropsMiddleware(pageModule) {
|
|
|
190
205
|
const result = await pageModule.getServerSideProps(req, res);
|
|
191
206
|
// Manejar ServerSideResult
|
|
192
207
|
if (result && typeof result === 'object') {
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
208
|
+
// `title` y `html` eran la forma en la que F-004 devolvía el head antes
|
|
209
|
+
// de `pageConfig` (ver PR #44). Se reemplazaron sin dejar rastro: una
|
|
210
|
+
// página que todavía las devuelve no rompe, simplemente deja de tener
|
|
211
|
+
// efecto en silencio. Un aviso en desarrollo es la única señal de que
|
|
212
|
+
// hace falta migrar.
|
|
213
|
+
if (!warnedAboutLegacyHeadApi && ('title' in result || 'html' in result) && process.env.NODE_ENV !== 'production') {
|
|
214
|
+
warnedAboutLegacyHeadApi = true;
|
|
215
|
+
console.warn(`[ress] getServerSideProps de "${req.path}" devuelve "title" y/o "html", ` +
|
|
216
|
+
'una API de F-004 anterior a pageConfig que ya no se interpreta. ' +
|
|
217
|
+
'Usá pageConfig.head para title/meta/link/script, y htmlAttributes / ' +
|
|
218
|
+
'bodyAttributes para los atributos de <html> y <body>.');
|
|
219
|
+
}
|
|
220
|
+
if (result.pageConfig) {
|
|
221
|
+
const { document, rendering } = splitPageConfig(result.pageConfig);
|
|
222
|
+
// La configuración del documento sólo existe durante este request y no
|
|
223
|
+
// se serializa junto con las props de hidratación.
|
|
224
|
+
res.locals.pageConfig = document;
|
|
225
|
+
// La de render tiene la misma firma que el export estático y se
|
|
226
|
+
// combina con él: lo devuelto acá gana. Viaja en la petición, que
|
|
227
|
+
// nunca se serializa, y la leen el render (hidratación) y la caché
|
|
228
|
+
// (plazos de esta entrada y modo de la ruta).
|
|
229
|
+
if (Object.keys(rendering).length) {
|
|
230
|
+
req.ressPageRendering = (0, page_config_1.resolvePageRendering)({ ...renderingOf(pageModule.pageConfig), ...rendering }, file);
|
|
231
|
+
}
|
|
200
232
|
}
|
|
201
233
|
// Props → solo en un bucket claro (serverSideProps)
|
|
202
234
|
if (result.props) {
|
|
@@ -213,67 +245,54 @@ function createGetServerSidePropsMiddleware(pageModule) {
|
|
|
213
245
|
}
|
|
214
246
|
};
|
|
215
247
|
}
|
|
248
|
+
/** Separa lo que describe el documento de lo que decide cómo se renderiza. */
|
|
249
|
+
function splitPageConfig(config) {
|
|
250
|
+
const document = { ...config };
|
|
251
|
+
for (const field of page_config_merge_1.RENDERING_FIELDS)
|
|
252
|
+
delete document[field];
|
|
253
|
+
return { document, rendering: renderingOf(config) };
|
|
254
|
+
}
|
|
255
|
+
function renderingOf(config) {
|
|
256
|
+
const rendering = {};
|
|
257
|
+
for (const field of page_config_merge_1.RENDERING_FIELDS) {
|
|
258
|
+
if (config?.[field] !== undefined)
|
|
259
|
+
rendering[field] = config[field];
|
|
260
|
+
}
|
|
261
|
+
return rendering;
|
|
262
|
+
}
|
|
216
263
|
/**
|
|
217
264
|
* Creates a unified error handler for a specific page route
|
|
218
265
|
* This replaces the old createPageErrorMiddleware with a more useful approach
|
|
219
266
|
*/
|
|
220
|
-
function createPageErrorHandler(pageFile,
|
|
267
|
+
function createPageErrorHandler(pageFile, loader, middlewares) {
|
|
221
268
|
return async (err, req, res, next) => {
|
|
222
|
-
const errorMiddleware = await getErrorMiddleware(pageFile,
|
|
269
|
+
const errorMiddleware = await getErrorMiddleware(pageFile, loader, middlewares);
|
|
270
|
+
// Sin errorMiddleware propio (ni en la página ni en la jerarquía de
|
|
271
|
+
// middlewares), la responsabilidad sigue hasta Express —o hasta un error
|
|
272
|
+
// handler que la aplicación haya montado después del router—, que no
|
|
273
|
+
// reproduce err.message en producción.
|
|
274
|
+
if (!errorMiddleware)
|
|
275
|
+
return next(err);
|
|
223
276
|
errorMiddleware(err, req, res, next);
|
|
224
277
|
};
|
|
225
278
|
}
|
|
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
279
|
/**
|
|
237
280
|
* Creates a dynamic middleware handler that reloads middlewares on each request in development
|
|
238
281
|
* This enables HMR for middlewares
|
|
239
282
|
* I FUCKING HATE THIS FUNCTION BUT IT SEEMS TO WORK
|
|
240
283
|
*/
|
|
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
284
|
/**
|
|
266
285
|
* 1. Resuelve middlewares previos al getServerSideProps
|
|
267
286
|
*/
|
|
268
|
-
async function getPagePrevMiddlewares(pageRoute,
|
|
269
|
-
return await loadPageMiddlewares(pageRoute,
|
|
287
|
+
async function getPagePrevMiddlewares(pageRoute, loader) {
|
|
288
|
+
return await loadPageMiddlewares(pageRoute, loader);
|
|
270
289
|
}
|
|
271
290
|
/**
|
|
272
291
|
* 2. Convierte getServerSideProps a middleware
|
|
273
292
|
*/
|
|
274
|
-
async function getServerSidePropsAsMiddleware(pageFile,
|
|
275
|
-
const pageModule = await loadPageModule(pageFile,
|
|
276
|
-
return pageModule ? createGetServerSidePropsMiddleware(pageModule) : (_req, _res, next) => next();
|
|
293
|
+
async function getServerSidePropsAsMiddleware(pageFile, loader) {
|
|
294
|
+
const pageModule = await loadPageModule(pageFile, loader);
|
|
295
|
+
return pageModule ? createGetServerSidePropsMiddleware(pageModule, pageFile) : (_req, _res, next) => next();
|
|
277
296
|
}
|
|
278
297
|
/**
|
|
279
298
|
* 3. Error middleware con fallback automático y jerarquía
|
|
@@ -282,46 +301,44 @@ async function getServerSidePropsAsMiddleware(pageFile, vite) {
|
|
|
282
301
|
* 2. errorMiddleware en [page].middlewares.ts
|
|
283
302
|
* 3. errorMiddleware en carpeta/middlewares.ts
|
|
284
303
|
* 4. errorMiddleware en root middlewares.ts (más general)
|
|
285
|
-
* 5.
|
|
304
|
+
* 5. ninguno: null, para que el llamador delegue con next(err)
|
|
286
305
|
*/
|
|
287
|
-
async function getErrorMiddleware(pageFile,
|
|
288
|
-
const pageModule = await loadPageModule(pageFile,
|
|
306
|
+
async function getErrorMiddleware(pageFile, loader, middlewares) {
|
|
307
|
+
const pageModule = await loadPageModule(pageFile, loader);
|
|
289
308
|
// 1. Prioridad máxima: errorMiddleware en la página
|
|
290
309
|
if (pageModule?.errorMiddleware) {
|
|
291
310
|
return pageModule.errorMiddleware;
|
|
292
311
|
}
|
|
293
312
|
// 2-4. Buscar errorMiddleware en middlewares siguiendo jerarquía
|
|
294
|
-
const errorMiddleware = await findErrorMiddlewareInHierarchy(pageFile,
|
|
313
|
+
const errorMiddleware = await findErrorMiddlewareInHierarchy(pageFile, loader, middlewares);
|
|
295
314
|
if (errorMiddleware) {
|
|
296
315
|
return errorMiddleware;
|
|
297
316
|
}
|
|
298
|
-
// 5.
|
|
299
|
-
return
|
|
317
|
+
// 5. No hay ninguno declarado: que siga hasta Express
|
|
318
|
+
return null;
|
|
300
319
|
}
|
|
301
320
|
/**
|
|
302
321
|
* Busca errorMiddleware en la jerarquía de middlewares
|
|
303
322
|
* Desde el más específico (página) hasta el más general (root)
|
|
304
323
|
*/
|
|
305
|
-
async function findErrorMiddlewareInHierarchy(pageFile,
|
|
324
|
+
async function findErrorMiddlewareInHierarchy(pageFile, loader, middlewares) {
|
|
306
325
|
// Obtener todos los middlewares que podrían aplicar a esta página
|
|
307
|
-
const allMiddlewares = getMiddlewares();
|
|
326
|
+
const allMiddlewares = middlewares ?? getMiddlewares();
|
|
308
327
|
// Convertir pageFile a route para matching
|
|
309
|
-
|
|
328
|
+
// Sin `try` esto lanzaría desde el camino de error —el que atiende cuando algo
|
|
329
|
+
// ya falló—, y una página que no se pudo renderizar terminaría en una
|
|
330
|
+
// excepción sin manejar en vez de en la página de error.
|
|
331
|
+
let pageRoute;
|
|
332
|
+
try {
|
|
333
|
+
pageRoute = '/' + (0, module_extensions_1.pageIdOf)(pageFile);
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
pageRoute = '/' + pageFile.replace(/^app\/pages\//, '').replace(/\.[^./]+$/, '');
|
|
337
|
+
}
|
|
310
338
|
pageRoute = pageRoute.replace(/\/index$/, '') || '/';
|
|
311
339
|
// Filtrar middlewares relevantes para esta página
|
|
312
|
-
|
|
313
|
-
|
|
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
|
-
})
|
|
340
|
+
// El mismo alcance que la cadena: por segmentos, la raíz aplica a todo.
|
|
341
|
+
const relevantMiddlewares = middlewaresFor(allMiddlewares, pageRoute)
|
|
325
342
|
.sort((a, b) => {
|
|
326
343
|
// Ordenar por especificidad: mayor depth = más específico
|
|
327
344
|
if (a.depth !== b.depth)
|
|
@@ -336,7 +353,7 @@ async function findErrorMiddlewareInHierarchy(pageFile, vite) {
|
|
|
336
353
|
// Buscar errorMiddleware en orden de especificidad
|
|
337
354
|
for (const middlewareInfo of relevantMiddlewares) {
|
|
338
355
|
try {
|
|
339
|
-
const middlewareModule = await loadMiddlewareModule(middlewareInfo,
|
|
356
|
+
const middlewareModule = await loadMiddlewareModule(middlewareInfo, loader);
|
|
340
357
|
if (middlewareModule?.errorMiddleware) {
|
|
341
358
|
return middlewareModule.errorMiddleware;
|
|
342
359
|
}
|
|
@@ -347,14 +364,15 @@ async function findErrorMiddlewareInHierarchy(pageFile, vite) {
|
|
|
347
364
|
}
|
|
348
365
|
return null;
|
|
349
366
|
}
|
|
350
|
-
//
|
|
367
|
+
// Caché de módulos de middleware. Sólo activa en producción: en desarrollo
|
|
368
|
+
// cada rearmado del router debe volver a leerlos para reflejar los cambios.
|
|
351
369
|
const middlewareModuleCache = new Map();
|
|
352
|
-
//
|
|
370
|
+
// Caché de módulos de página. Sólo activa en producción, por el mismo motivo.
|
|
353
371
|
const pageModuleCache = new Map();
|
|
354
372
|
/**
|
|
355
373
|
* Cargar un módulo de middleware específico
|
|
356
374
|
*/
|
|
357
|
-
async function loadMiddlewareModule(middlewareInfo,
|
|
375
|
+
async function loadMiddlewareModule(middlewareInfo, loader) {
|
|
358
376
|
const isProduction = process.env.NODE_ENV === 'production';
|
|
359
377
|
const cacheKey = `${middlewareInfo.file}-${process.env.NODE_ENV || 'development'}`;
|
|
360
378
|
// Only use cache in production mode to allow HMR in development
|
|
@@ -362,18 +380,22 @@ async function loadMiddlewareModule(middlewareInfo, vite) {
|
|
|
362
380
|
return middlewareModuleCache.get(cacheKey);
|
|
363
381
|
}
|
|
364
382
|
let moduleToLoad;
|
|
365
|
-
if (
|
|
366
|
-
|
|
383
|
+
if (isProduction && middlewareInfo.buildChunk) {
|
|
384
|
+
// El chunk que registró el build, no un nombre derivado de la fuente.
|
|
385
|
+
const moduleUrl = (0, module_1.resolveServerModule)({ pageId: middlewareInfo.file, server: { devId: middlewareInfo.file, buildChunk: middlewareInfo.buildChunk } }, { root: process.cwd(), isProduction: true, serverOutDir: environments_1.OUT_DIR.ssr });
|
|
386
|
+
// `resolveServerModule` devuelve una ruta absoluta: en Windows sólo se
|
|
387
|
+
// puede importar como URL `file://`.
|
|
388
|
+
moduleToLoad = await import(/* @vite-ignore */ (0, node_url_1.pathToFileURL)(moduleUrl).href);
|
|
389
|
+
}
|
|
390
|
+
else if (!isProduction && loader) {
|
|
391
|
+
moduleToLoad = await loader.load(middlewareInfo.file);
|
|
367
392
|
}
|
|
368
393
|
else {
|
|
369
|
-
// En producción
|
|
370
|
-
//
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
.replace(/\[(\w+)\]/g, '_$1_'); // [photocardId] -> _photocardId_
|
|
375
|
-
const moduleUrl = node_path_1.default.resolve(compiledPath);
|
|
376
|
-
moduleToLoad = await Promise.resolve(`${moduleUrl}`).then(s => __importStar(require(s)));
|
|
394
|
+
// En producción se importa el artefacto compilado. La traducción del nombre
|
|
395
|
+
// es la misma que usa el resto del framework: antes esta copia sólo recortaba
|
|
396
|
+
// `.ts`, así que un middleware `.js` cargaba un archivo inexistente.
|
|
397
|
+
const moduleUrl = (0, prod_server_1.resolveServerModulePath)(middlewareInfo.file);
|
|
398
|
+
moduleToLoad = await import(/* @vite-ignore */ (0, node_url_1.pathToFileURL)(moduleUrl).href);
|
|
377
399
|
}
|
|
378
400
|
// Only cache in production mode
|
|
379
401
|
if (isProduction) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PageConfig } from '../head/types';
|
|
2
|
+
/**
|
|
3
|
+
* El documento de una petición: el `pageConfig` estático de la página como base
|
|
4
|
+
* y lo que devolvió `getServerSideProps` encima.
|
|
5
|
+
*
|
|
6
|
+
* Los campos de render no participan: se decidieron al armar la ruta y no son
|
|
7
|
+
* parte del documento.
|
|
8
|
+
*/
|
|
9
|
+
export declare function mergePageConfig(staticConfig: PageConfig | undefined, dynamicConfig: PageConfig | undefined): PageConfig | undefined;
|
|
10
|
+
/** Los campos de render que alguien intentó fijar por petición. */
|
|
11
|
+
export declare const RENDERING_FIELDS: readonly ["renderingMode", "revalidate", "expire", "hydrate", "searchParams"];
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RENDERING_FIELDS = void 0;
|
|
4
|
+
exports.mergePageConfig = mergePageConfig;
|
|
5
|
+
/** Qué hace que dos `<meta>` sean la misma declaración. */
|
|
6
|
+
function metaIdentity(meta) {
|
|
7
|
+
for (const key of ['name', 'property', 'httpEquiv', 'http-equiv', 'charset', 'itemProp']) {
|
|
8
|
+
const value = meta[key];
|
|
9
|
+
if (value !== undefined)
|
|
10
|
+
return `${key === 'http-equiv' ? 'httpEquiv' : key}:${String(value).toLowerCase()}`;
|
|
11
|
+
}
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
function mergeHead(base, over) {
|
|
15
|
+
if (!base)
|
|
16
|
+
return over;
|
|
17
|
+
if (!over)
|
|
18
|
+
return base;
|
|
19
|
+
// Una `description` estática y otra calculada no son dos descripciones: la
|
|
20
|
+
// calculada reemplaza a la estática.
|
|
21
|
+
const replaced = new Set((over.meta ?? []).map(metaIdentity).filter(Boolean));
|
|
22
|
+
const concat = (a, b) => (a || b ? [...(a ?? []), ...(b ?? [])] : undefined);
|
|
23
|
+
const merged = {
|
|
24
|
+
...base,
|
|
25
|
+
...over,
|
|
26
|
+
meta: concat((base.meta ?? []).filter((m) => !replaced.has(metaIdentity(m))), over.meta),
|
|
27
|
+
link: concat(base.link, over.link),
|
|
28
|
+
script: concat(base.script, over.script),
|
|
29
|
+
style: concat(base.style, over.style),
|
|
30
|
+
noscript: concat(base.noscript, over.noscript),
|
|
31
|
+
};
|
|
32
|
+
for (const key of Object.keys(merged)) {
|
|
33
|
+
if (merged[key] === undefined)
|
|
34
|
+
delete merged[key];
|
|
35
|
+
}
|
|
36
|
+
return merged;
|
|
37
|
+
}
|
|
38
|
+
function mergeVariant(base, over) {
|
|
39
|
+
const merged = { ...base, ...over };
|
|
40
|
+
const head = mergeHead(base.head, over.head);
|
|
41
|
+
if (head)
|
|
42
|
+
merged.head = head;
|
|
43
|
+
if (base.htmlAttributes || over.htmlAttributes) {
|
|
44
|
+
merged.htmlAttributes = { ...base.htmlAttributes, ...over.htmlAttributes };
|
|
45
|
+
}
|
|
46
|
+
if (base.bodyAttributes || over.bodyAttributes) {
|
|
47
|
+
merged.bodyAttributes = { ...base.bodyAttributes, ...over.bodyAttributes };
|
|
48
|
+
}
|
|
49
|
+
return merged;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* El documento de una petición: el `pageConfig` estático de la página como base
|
|
53
|
+
* y lo que devolvió `getServerSideProps` encima.
|
|
54
|
+
*
|
|
55
|
+
* Los campos de render no participan: se decidieron al armar la ruta y no son
|
|
56
|
+
* parte del documento.
|
|
57
|
+
*/
|
|
58
|
+
function mergePageConfig(staticConfig, dynamicConfig) {
|
|
59
|
+
const base = documentOf(staticConfig);
|
|
60
|
+
const over = documentOf(dynamicConfig);
|
|
61
|
+
if (!base)
|
|
62
|
+
return over;
|
|
63
|
+
if (!over)
|
|
64
|
+
return base;
|
|
65
|
+
const merged = mergeVariant(base, over);
|
|
66
|
+
if (base.variants || over.variants) {
|
|
67
|
+
const variants = { ...base.variants };
|
|
68
|
+
for (const [name, variant] of Object.entries(over.variants ?? {})) {
|
|
69
|
+
variants[name] = variants[name] ? mergeVariant(variants[name], variant) : variant;
|
|
70
|
+
}
|
|
71
|
+
merged.variants = variants;
|
|
72
|
+
}
|
|
73
|
+
return merged;
|
|
74
|
+
}
|
|
75
|
+
/** Los campos de render que alguien intentó fijar por petición. */
|
|
76
|
+
exports.RENDERING_FIELDS = ['renderingMode', 'revalidate', 'expire', 'hydrate', 'searchParams'];
|
|
77
|
+
function documentOf(config) {
|
|
78
|
+
if (!config)
|
|
79
|
+
return undefined;
|
|
80
|
+
const document = { ...config };
|
|
81
|
+
for (const field of exports.RENDERING_FIELDS)
|
|
82
|
+
delete document[field];
|
|
83
|
+
return document;
|
|
84
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { RessRuntime } from '../runtime/dev-server';
|
|
2
|
+
import type { RequestPlatform } from '../isr/key';
|
|
2
3
|
export interface RequestContext {
|
|
3
4
|
req: any;
|
|
4
5
|
res: any;
|
|
@@ -12,6 +13,18 @@ export interface RouterConfig {
|
|
|
12
13
|
platform: string;
|
|
13
14
|
req: any;
|
|
14
15
|
}) => Promise<string>;
|
|
15
|
-
viteConfig:
|
|
16
|
+
viteConfig: RessRuntime;
|
|
16
17
|
}
|
|
18
|
+
type PlatformContext = RequestPlatform;
|
|
19
|
+
export declare function resolveRequestPlatform(req: any, enablePlatformDetection?: boolean): PlatformContext;
|
|
20
|
+
/**
|
|
21
|
+
* Arma el render server a partir de la config de la ruta.
|
|
22
|
+
*
|
|
23
|
+
* `viteConfig` puede llegar como thunk (modo automático: el runtime se
|
|
24
|
+
* resuelve después de crear el router), por eso se resuelve acá y no al
|
|
25
|
+
* armar `RouterConfig`. Se llama una sola vez por middleware: quien la usa
|
|
26
|
+
* cachea el resultado en su propio closure.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildRenderServer(config: RouterConfig): any;
|
|
17
29
|
export declare function processRequest(context: RequestContext, config: RouterConfig, renderServer?: any): Promise<void>;
|
|
30
|
+
export {};
|