vatts 1.0.5-alpha.2 → 1.0.5-alpha.3
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/dist/renderer.js +164 -93
- package/package.json +1 -1
package/dist/renderer.js
CHANGED
|
@@ -41,6 +41,22 @@ function requireWithoutStyles(modulePath) {
|
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
// --- Gerenciamento de Console (Silenciador) ---
|
|
45
|
+
const originalConsole = {
|
|
46
|
+
log: console.log,
|
|
47
|
+
info: console.info,
|
|
48
|
+
debug: console.debug
|
|
49
|
+
};
|
|
50
|
+
function silenceConsole() {
|
|
51
|
+
console.log = () => { };
|
|
52
|
+
console.info = () => { };
|
|
53
|
+
console.debug = () => { };
|
|
54
|
+
}
|
|
55
|
+
function restoreConsole() {
|
|
56
|
+
console.log = originalConsole.log;
|
|
57
|
+
console.info = originalConsole.info;
|
|
58
|
+
console.debug = originalConsole.debug;
|
|
59
|
+
}
|
|
44
60
|
// --- Funções de Metadata e Scripts ---
|
|
45
61
|
function generateMetaTags(metadata) {
|
|
46
62
|
const tags = [];
|
|
@@ -135,46 +151,81 @@ function obfuscateData(data) {
|
|
|
135
151
|
const hash = Buffer.from(Date.now().toString()).toString('base64').substring(0, 8);
|
|
136
152
|
return `${hash}.${base64}`;
|
|
137
153
|
}
|
|
138
|
-
// Retorna as URLs dos scripts
|
|
139
|
-
//
|
|
140
|
-
function
|
|
154
|
+
// Retorna as URLs dos scripts e CSS
|
|
155
|
+
// Procura em .vatts/ e .vatts/assets/
|
|
156
|
+
function getBuildAssets(req) {
|
|
141
157
|
const projectDir = process.cwd();
|
|
142
158
|
const distDir = path_1.default.join(projectDir, '.vatts');
|
|
159
|
+
const assetsDir = path_1.default.join(distDir, 'assets');
|
|
143
160
|
if (!fs_1.default.existsSync(distDir))
|
|
144
161
|
return null;
|
|
162
|
+
let scripts = [];
|
|
163
|
+
let styles = [];
|
|
164
|
+
// Helper para processar arquivos de um diretório
|
|
165
|
+
const processDirectory = (directory, urlPrefix) => {
|
|
166
|
+
if (!fs_1.default.existsSync(directory))
|
|
167
|
+
return;
|
|
168
|
+
const files = fs_1.default.readdirSync(directory);
|
|
169
|
+
files.forEach(file => {
|
|
170
|
+
if (file.endsWith('.map'))
|
|
171
|
+
return; // Ignora sourcemaps
|
|
172
|
+
const fullPath = path_1.default.join(directory, file);
|
|
173
|
+
const stat = fs_1.default.statSync(fullPath);
|
|
174
|
+
if (stat.isFile()) {
|
|
175
|
+
if (file.endsWith('.js')) {
|
|
176
|
+
scripts.push(`${urlPrefix}/${file}`);
|
|
177
|
+
}
|
|
178
|
+
else if (file.endsWith('.css')) {
|
|
179
|
+
styles.push(`${urlPrefix}/${file}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
};
|
|
145
184
|
try {
|
|
185
|
+
// 1. Verificar Manifesto (se existir)
|
|
146
186
|
const manifestPath = path_1.default.join(distDir, 'manifest.json');
|
|
147
187
|
if (fs_1.default.existsSync(manifestPath)) {
|
|
148
188
|
const manifest = JSON.parse(fs_1.default.readFileSync(manifestPath, 'utf8'));
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
.
|
|
152
|
-
|
|
189
|
+
const manifestFiles = Object.values(manifest);
|
|
190
|
+
scripts = manifestFiles
|
|
191
|
+
.filter((f) => f.endsWith('.js'))
|
|
192
|
+
.map((f) => `/_vatts/${f}`);
|
|
193
|
+
styles = manifestFiles
|
|
194
|
+
.filter((f) => f.endsWith('.css'))
|
|
195
|
+
.map((f) => `/_vatts/${f}`);
|
|
153
196
|
}
|
|
154
197
|
else {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
198
|
+
// 2. Fallback: Scan manual de diretórios
|
|
199
|
+
// Scan na raiz .vatts/ (Geralmente entry points)
|
|
200
|
+
processDirectory(distDir, '/_vatts');
|
|
201
|
+
// Scan em .vatts/assets/ (Assets estáticos, chunks, CSS extraído)
|
|
202
|
+
processDirectory(assetsDir, '/_vatts/assets');
|
|
203
|
+
// Ordenação básica para garantir que o main carregue
|
|
204
|
+
scripts.sort((a, b) => {
|
|
158
205
|
if (a.includes('main'))
|
|
159
206
|
return -1;
|
|
160
207
|
if (b.includes('main'))
|
|
161
208
|
return 1;
|
|
162
209
|
return a.localeCompare(b);
|
|
163
210
|
});
|
|
164
|
-
return jsFiles.length > 0 ? jsFiles.map(file => `/_vatts/${file}`) : null;
|
|
165
211
|
}
|
|
212
|
+
if (scripts.length === 0)
|
|
213
|
+
return null;
|
|
214
|
+
return { scripts, styles };
|
|
166
215
|
}
|
|
167
|
-
catch {
|
|
216
|
+
catch (e) {
|
|
217
|
+
console.error("Error loading assets:", e);
|
|
168
218
|
return null;
|
|
169
219
|
}
|
|
170
220
|
}
|
|
171
|
-
function ServerRoot({ lang, title, metaTagsHtml, initialDataScript, hotReloadScript, dataScript, children }) {
|
|
221
|
+
function ServerRoot({ lang, title, metaTagsHtml, stylesHtml, initialDataScript, hotReloadScript, dataScript, children }) {
|
|
172
222
|
// Concatena tudo que vai no head em uma única string
|
|
173
223
|
const headContent = `
|
|
174
224
|
<meta charset="utf-8" />
|
|
175
225
|
<title>${title}</title>
|
|
176
226
|
${initialDataScript ? `<script>${initialDataScript}</script>` : ''}
|
|
177
227
|
${metaTagsHtml || ''}
|
|
228
|
+
${stylesHtml || ''}
|
|
178
229
|
`;
|
|
179
230
|
return ((0, jsx_runtime_1.jsxs)("html", { lang: lang, children: [(0, jsx_runtime_1.jsx)("head", { dangerouslySetInnerHTML: { __html: headContent } }), (0, jsx_runtime_1.jsxs)("body", { children: [dataScript, (0, jsx_runtime_1.jsx)("div", { id: "root", children: children }), hotReloadScript && ((0, jsx_runtime_1.jsx)("div", { style: { display: 'none' }, dangerouslySetInnerHTML: { __html: hotReloadScript } }))] })] }));
|
|
180
231
|
}
|
|
@@ -182,91 +233,111 @@ async function renderAsStream({ req, res, route, params, allRoutes }) {
|
|
|
182
233
|
const { generateMetadata } = route;
|
|
183
234
|
const isProduction = !req.hwebDev;
|
|
184
235
|
const hotReloadManager = req.hotReloadManager;
|
|
185
|
-
//
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (layoutInfo) {
|
|
197
|
-
try {
|
|
198
|
-
// Recarrega o componente de layout para ter acesso à função (o router só guarda metadata)
|
|
199
|
-
const layoutModule = requireWithoutStyles(path_1.default.resolve(process.cwd(), layoutInfo.componentPath));
|
|
200
|
-
LayoutComponent = layoutModule.default;
|
|
236
|
+
// SILENCIAR CONSOLE: Inicia o silêncio para evitar logs de renderização
|
|
237
|
+
silenceConsole();
|
|
238
|
+
try {
|
|
239
|
+
// 1. Verificar Build - Se não tiver scripts, retorna tela de Loading
|
|
240
|
+
const assets = getBuildAssets(req);
|
|
241
|
+
if (!assets || assets.scripts.length === 0) {
|
|
242
|
+
// Se falhar o build, restauramos o console para o erro aparecer se necessário
|
|
243
|
+
restoreConsole();
|
|
244
|
+
res.setHeader('Content-Type', 'text/html');
|
|
245
|
+
res.end(getBuildingHTML());
|
|
246
|
+
return;
|
|
201
247
|
}
|
|
202
|
-
|
|
203
|
-
|
|
248
|
+
// 2. Preparar Layout
|
|
249
|
+
const layoutInfo = (0, router_1.getLayout)();
|
|
250
|
+
let LayoutComponent = null;
|
|
251
|
+
if (layoutInfo) {
|
|
252
|
+
try {
|
|
253
|
+
// Recarrega o componente de layout para ter acesso à função (o router só guarda metadata)
|
|
254
|
+
const layoutModule = requireWithoutStyles(path_1.default.resolve(process.cwd(), layoutInfo.componentPath));
|
|
255
|
+
LayoutComponent = layoutModule.default;
|
|
256
|
+
}
|
|
257
|
+
catch (e) {
|
|
258
|
+
// Usamos console.error original aqui, pois erro de layout é crítico
|
|
259
|
+
restoreConsole();
|
|
260
|
+
console.error("Error loading layout component for SSR:", e);
|
|
261
|
+
silenceConsole(); // Volta a silenciar
|
|
262
|
+
}
|
|
204
263
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
metadata = { ...metadata, ...layoutInfo.metadata };
|
|
210
|
-
}
|
|
211
|
-
if (generateMetadata) {
|
|
212
|
-
const routeMetadata = await Promise.resolve(generateMetadata(params, req));
|
|
213
|
-
metadata = { ...metadata, ...routeMetadata };
|
|
214
|
-
}
|
|
215
|
-
// 4. Preparar Dados Iniciais
|
|
216
|
-
const results = await Promise.all(allRoutes.map(async (r) => {
|
|
217
|
-
let routeMeta = {};
|
|
218
|
-
if (r.generateMetadata) {
|
|
219
|
-
routeMeta = await r.generateMetadata(params, req);
|
|
264
|
+
// 3. Preparar Metadata
|
|
265
|
+
let metadata = { title: 'Vatts App' };
|
|
266
|
+
if (layoutInfo && layoutInfo.metadata) {
|
|
267
|
+
metadata = { ...metadata, ...layoutInfo.metadata };
|
|
220
268
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
initialParams: params,
|
|
231
|
-
};
|
|
232
|
-
// Scripts
|
|
233
|
-
const obfuscatedData = obfuscateData(initialData);
|
|
234
|
-
const hotReloadScript = !isProduction && hotReloadManager ? hotReloadManager.getClientScript() : '';
|
|
235
|
-
const metaTagsHtml = generateMetaTags(metadata);
|
|
236
|
-
const htmlLang = metadata.language || 'pt-BR';
|
|
237
|
-
// 5. Componente da Página Atual
|
|
238
|
-
const PageComponent = route.component;
|
|
239
|
-
// Monta a árvore da aplicação
|
|
240
|
-
let AppTree = (0, jsx_runtime_1.jsx)(PageComponent, { params: params });
|
|
241
|
-
if (LayoutComponent) {
|
|
242
|
-
AppTree = (0, jsx_runtime_1.jsx)(LayoutComponent, { children: AppTree });
|
|
243
|
-
}
|
|
244
|
-
// 6. Streaming
|
|
245
|
-
return new Promise((resolve, reject) => {
|
|
246
|
-
let didError = false;
|
|
247
|
-
const { pipe } = (0, server_1.renderToPipeableStream)((0, jsx_runtime_1.jsx)(ServerRoot, { lang: htmlLang, title: metadata.title || 'Vatts.js', metaTagsHtml: metaTagsHtml,
|
|
248
|
-
// Recriando o script de dados exatamente como o client espera
|
|
249
|
-
initialDataScript: `/* Data Injection */`, hotReloadScript: hotReloadScript, dataScript: (0, jsx_runtime_1.jsx)("script", { id: "__vatts_data__", type: "text/plain", "data-h": obfuscatedData }), children: AppTree }), {
|
|
250
|
-
// Usar bootstrapModules para scripts tipo módulo (ESM)
|
|
251
|
-
bootstrapModules: bootstrapScripts,
|
|
252
|
-
onShellReady() {
|
|
253
|
-
res.setHeader('Content-Type', 'text/html');
|
|
254
|
-
pipe(res);
|
|
255
|
-
resolve();
|
|
256
|
-
},
|
|
257
|
-
onShellError(error) {
|
|
258
|
-
console.error('Streaming Shell Error:', error);
|
|
259
|
-
res.statusCode = 500;
|
|
260
|
-
res.setHeader('Content-Type', 'text/html');
|
|
261
|
-
res.end('<h1>Internal Server Error</h1>');
|
|
262
|
-
resolve();
|
|
263
|
-
},
|
|
264
|
-
onError(error) {
|
|
265
|
-
didError = true;
|
|
266
|
-
console.error('Streaming Error:', error);
|
|
269
|
+
if (generateMetadata) {
|
|
270
|
+
const routeMetadata = await Promise.resolve(generateMetadata(params, req));
|
|
271
|
+
metadata = { ...metadata, ...routeMetadata };
|
|
272
|
+
}
|
|
273
|
+
// 4. Preparar Dados Iniciais
|
|
274
|
+
const results = await Promise.all(allRoutes.map(async (r) => {
|
|
275
|
+
let routeMeta = {};
|
|
276
|
+
if (r.generateMetadata) {
|
|
277
|
+
routeMeta = await r.generateMetadata(params, req);
|
|
267
278
|
}
|
|
279
|
+
return {
|
|
280
|
+
pattern: r.pattern,
|
|
281
|
+
componentPath: r.componentPath,
|
|
282
|
+
metadata: routeMeta,
|
|
283
|
+
};
|
|
284
|
+
}));
|
|
285
|
+
const initialData = {
|
|
286
|
+
routes: results,
|
|
287
|
+
initialComponentPath: route.componentPath,
|
|
288
|
+
initialParams: params,
|
|
289
|
+
};
|
|
290
|
+
// Scripts e Estilos
|
|
291
|
+
const obfuscatedData = obfuscateData(initialData);
|
|
292
|
+
const hotReloadScript = !isProduction && hotReloadManager ? hotReloadManager.getClientScript() : '';
|
|
293
|
+
const metaTagsHtml = generateMetaTags(metadata);
|
|
294
|
+
const htmlLang = metadata.language || 'pt-BR';
|
|
295
|
+
// Gera tags de estilo para o head
|
|
296
|
+
const stylesHtml = assets.styles.map(styleUrl => `<link rel="stylesheet" href="${styleUrl}">`).join('\n');
|
|
297
|
+
// 5. Componente da Página Atual
|
|
298
|
+
const PageComponent = route.component;
|
|
299
|
+
// Monta a árvore da aplicação
|
|
300
|
+
let AppTree = (0, jsx_runtime_1.jsx)(PageComponent, { params: params });
|
|
301
|
+
if (LayoutComponent) {
|
|
302
|
+
AppTree = (0, jsx_runtime_1.jsx)(LayoutComponent, { children: AppTree });
|
|
303
|
+
}
|
|
304
|
+
// 6. Streaming
|
|
305
|
+
return new Promise((resolve, reject) => {
|
|
306
|
+
let didError = false;
|
|
307
|
+
const { pipe } = (0, server_1.renderToPipeableStream)((0, jsx_runtime_1.jsx)(ServerRoot, { lang: htmlLang, title: metadata.title || 'Vatts.js', metaTagsHtml: metaTagsHtml, stylesHtml: stylesHtml,
|
|
308
|
+
// Recriando o script de dados exatamente como o client espera
|
|
309
|
+
initialDataScript: `/* Data Injection */`, hotReloadScript: hotReloadScript, dataScript: (0, jsx_runtime_1.jsx)("script", { id: "__vatts_data__", type: "text/plain", "data-h": obfuscatedData }), children: AppTree }), {
|
|
310
|
+
// Usar bootstrapModules para scripts tipo módulo (ESM)
|
|
311
|
+
bootstrapModules: assets.scripts,
|
|
312
|
+
onShellReady() {
|
|
313
|
+
// Restaurar console assim que o shell estiver pronto (cabeçalho enviado)
|
|
314
|
+
restoreConsole();
|
|
315
|
+
res.setHeader('Content-Type', 'text/html');
|
|
316
|
+
pipe(res);
|
|
317
|
+
resolve();
|
|
318
|
+
},
|
|
319
|
+
onShellError(error) {
|
|
320
|
+
restoreConsole(); // Restaura para mostrar o erro real
|
|
321
|
+
console.error('Streaming Shell Error:', error);
|
|
322
|
+
res.statusCode = 500;
|
|
323
|
+
res.setHeader('Content-Type', 'text/html');
|
|
324
|
+
res.end('<h1>Internal Server Error</h1>');
|
|
325
|
+
resolve();
|
|
326
|
+
},
|
|
327
|
+
onError(error) {
|
|
328
|
+
didError = true;
|
|
329
|
+
// Log de erro de stream ainda é importante, mas podemos filtrar se quiser
|
|
330
|
+
// Aqui mantemos o log de erro original do React que vai para stderr
|
|
331
|
+
console.error('Streaming Error:', error);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
268
334
|
});
|
|
269
|
-
}
|
|
335
|
+
}
|
|
336
|
+
catch (err) {
|
|
337
|
+
restoreConsole();
|
|
338
|
+
console.error("Critical Render Error:", err);
|
|
339
|
+
throw err;
|
|
340
|
+
}
|
|
270
341
|
}
|
|
271
342
|
// Mantemos a função antiga para compatibilidade
|
|
272
343
|
async function render(options) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vatts",
|
|
3
|
-
"version": "1.0.5-alpha.
|
|
3
|
+
"version": "1.0.5-alpha.3",
|
|
4
4
|
"description": "Vatts.js is a high-level framework for building web applications with ease and speed. It provides a robust set of tools and features to streamline development and enhance productivity.",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"author": "itsmuzin",
|