vatts 2.1.2 → 2.1.3-canary.1.0.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.
@@ -23,125 +23,10 @@ exports.render = render;
23
23
  const react_1 = __importDefault(require("react"));
24
24
  const server_1 = require("react-dom/server");
25
25
  const router_1 = require("../router");
26
- const fs_1 = __importDefault(require("fs"));
27
26
  const path_1 = __importDefault(require("path"));
27
+ const common_1 = require("../renderers/common");
28
28
  const BuildingPage_1 = __importDefault(require("../react/BuildingPage"));
29
29
  const server_error_1 = __importDefault(require("../react/server-error"));
30
- function stripScriptTags(html) {
31
- if (!html)
32
- return '';
33
- return html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, '');
34
- }
35
- function getRequestUrl(req) {
36
- return req?.originalUrl || req?.url;
37
- }
38
- function toError(err) {
39
- if (err instanceof Error)
40
- return err;
41
- if (typeof err === 'string')
42
- return new Error(err);
43
- try {
44
- return new Error(JSON.stringify(err));
45
- }
46
- catch {
47
- return new Error(String(err));
48
- }
49
- }
50
- // --- Polyfill para Browser Env no Server ---
51
- // Cria objetos globais falsos para evitar que bibliotecas client-side quebrem no SSR
52
- function polyfillBrowserEnv() {
53
- if (typeof window === 'undefined') {
54
- const win = {
55
- document: {
56
- createElement: () => ({ style: {}, setAttribute: () => { }, classList: { add: () => { }, remove: () => { } } }),
57
- getElementById: () => null,
58
- getElementsByTagName: () => [],
59
- querySelector: () => null,
60
- querySelectorAll: () => [],
61
- head: {},
62
- body: { style: {} },
63
- addEventListener: () => { },
64
- removeEventListener: () => { },
65
- cookie: '',
66
- location: { href: '', origin: '' }
67
- },
68
- navigator: {
69
- userAgent: 'Node.js/VattsSSR',
70
- },
71
- location: {
72
- href: 'http://localhost',
73
- origin: 'http://localhost',
74
- pathname: '/',
75
- search: '',
76
- hash: '',
77
- assign: () => { },
78
- replace: () => { },
79
- reload: () => { },
80
- },
81
- history: {
82
- pushState: () => { },
83
- replaceState: () => { },
84
- },
85
- screen: { width: 1920, height: 1080 },
86
- addEventListener: () => { },
87
- removeEventListener: () => { },
88
- matchMedia: () => ({ matches: false, addListener: () => { }, removeListener: () => { } }),
89
- requestAnimationFrame: (cb) => setTimeout(cb, 0),
90
- cancelAnimationFrame: (id) => clearTimeout(id),
91
- setTimeout: setTimeout,
92
- clearTimeout: clearTimeout,
93
- setInterval: setInterval,
94
- clearInterval: clearInterval,
95
- localStorage: {
96
- getItem: () => null,
97
- setItem: () => { },
98
- removeItem: () => { },
99
- clear: () => { },
100
- },
101
- sessionStorage: {
102
- getItem: () => null,
103
- setItem: () => { },
104
- removeItem: () => { },
105
- clear: () => { },
106
- },
107
- // MOCK SILENCIOSO: Substitui o console original por funções vazias no ambiente window fake
108
- // para evitar que logs do client-side poluam o terminal do servidor durante o SSR.
109
- console: {
110
- log: () => { },
111
- warn: () => { },
112
- error: () => { },
113
- info: () => { },
114
- debug: () => { },
115
- trace: () => { },
116
- dir: () => { },
117
- },
118
- Image: class {
119
- constructor() { }
120
- },
121
- };
122
- const globalAny = global;
123
- // Helper para definir globais de forma segura
124
- // Node 21+ tem globais 'navigator', 'performance' etc que são getter-only e quebram se tentar sobrescrever
125
- const setGlobal = (key, value) => {
126
- try {
127
- if (typeof globalAny[key] === 'undefined') {
128
- globalAny[key] = value;
129
- }
130
- }
131
- catch (e) {
132
- // Se falhar (propriedade read-only), ignoramos silenciosamente
133
- }
134
- };
135
- setGlobal('window', win);
136
- setGlobal('document', win.document);
137
- setGlobal('navigator', win.navigator);
138
- setGlobal('location', win.location);
139
- setGlobal('localStorage', win.localStorage);
140
- setGlobal('sessionStorage', win.sessionStorage);
141
- setGlobal('requestAnimationFrame', win.requestAnimationFrame);
142
- setGlobal('cancelAnimationFrame', win.cancelAnimationFrame);
143
- }
144
- }
145
30
  function buildShellHtml(options) {
146
31
  const { lang, title, metaTagsHtml, stylesHtml, hotReloadScript, obfuscatedData, scriptsHtml } = options;
147
32
  return `<!DOCTYPE html>
@@ -166,7 +51,7 @@ async function sendReactSsrFallback(options) {
166
51
  .map((src) => `<script type="module" src="${src}"></script>`)
167
52
  .join('\n');
168
53
  // No DEV a gente remove scripts do head pra garantir que só aparece a página de erro.
169
- const safeMetaTagsHtmlForDev = stripScriptTags(metaTagsHtml);
54
+ const safeMetaTagsHtmlForDev = (0, common_1.stripScriptTags)(metaTagsHtml);
170
55
  if (res.headersSent) {
171
56
  try {
172
57
  res.end();
@@ -190,10 +75,10 @@ async function sendReactSsrFallback(options) {
190
75
  }));
191
76
  return;
192
77
  }
193
- const err = toError(error);
78
+ const err = (0, common_1.toError)(error);
194
79
  return new Promise((resolve) => {
195
80
  const { pipe } = (0, server_1.renderToPipeableStream)(react_1.default.createElement(ServerRoot, { lang: lang, title: title, metaTagsHtml: safeMetaTagsHtmlForDev, stylesHtml: stylesHtml, initialDataScript: `/* Data Injection */`, hotReloadScript: '', dataScript: react_1.default.createElement("script", { id: "__vatts_data__", type: "text/plain", "data-h": obfuscatedData }) },
196
- react_1.default.createElement(server_error_1.default, { error: err, requestUrl: getRequestUrl(req), hint: "SSR failed to render this route. See the error below." })), {
81
+ react_1.default.createElement(server_error_1.default, { error: err, requestUrl: (0, common_1.getRequestUrl)(req), hint: "SSR failed to render this route. See the error below." })), {
197
82
  onAllReady() {
198
83
  pipe(res);
199
84
  resolve();
@@ -209,200 +94,6 @@ async function sendReactSsrFallback(options) {
209
94
  });
210
95
  });
211
96
  }
212
- // --- Helpers de Servidor ---
213
- // Função auxiliar para importar módulos ignorando CSS (mesma lógica do router.ts)
214
- function requireWithoutStyles(modulePath) {
215
- const extensions = ['.css', '.scss', '.sass', '.less', '.png', '.jpg', '.jpeg', '.gif', '.svg'];
216
- const originalHandlers = {};
217
- extensions.forEach(ext => {
218
- originalHandlers[ext] = require.extensions[ext];
219
- require.extensions[ext] = (m, filename) => {
220
- m.exports = {};
221
- };
222
- });
223
- try {
224
- const resolved = require.resolve(modulePath);
225
- if (require.cache[resolved])
226
- delete require.cache[resolved];
227
- return require(modulePath);
228
- }
229
- catch (e) {
230
- return require(modulePath);
231
- }
232
- finally {
233
- extensions.forEach(ext => {
234
- if (originalHandlers[ext]) {
235
- require.extensions[ext] = originalHandlers[ext];
236
- }
237
- else {
238
- delete require.extensions[ext];
239
- }
240
- });
241
- }
242
- }
243
- // --- Funções de Metadata e Scripts ---
244
- function generateMetaTags(metadata) {
245
- const tags = [];
246
- tags.push(`<meta charset="${metadata.charset || 'UTF-8'}">`);
247
- tags.push(`<meta name="viewport" content="${metadata.viewport || 'width=device-width, initial-scale=1.0'}">`);
248
- if (metadata.description)
249
- tags.push(`<meta name="description" content="${metadata.description}">`);
250
- if (metadata.keywords) {
251
- const keywordsStr = Array.isArray(metadata.keywords) ? metadata.keywords.join(', ') : metadata.keywords;
252
- tags.push(`<meta name="keywords" content="${keywordsStr}">`);
253
- }
254
- if (metadata.author)
255
- tags.push(`<meta name="author" content="${metadata.author}">`);
256
- if (metadata.themeColor)
257
- tags.push(`<meta name="theme-color" content="${metadata.themeColor}">`);
258
- if (metadata.robots)
259
- tags.push(`<meta name="robots" content="${metadata.robots}">`);
260
- if (metadata.canonical)
261
- tags.push(`<link rel="canonical" href="${metadata.canonical}">`);
262
- if (metadata.favicon)
263
- tags.push(`<link rel="icon" href="${metadata.favicon}">`);
264
- // Apple & Manifest
265
- if (metadata.appleTouchIcon)
266
- tags.push(`<link rel="apple-touch-icon" href="${metadata.appleTouchIcon}">`);
267
- if (metadata.manifest)
268
- tags.push(`<link rel="manifest" href="${metadata.manifest}">`);
269
- // Open Graph
270
- if (metadata.openGraph) {
271
- const og = metadata.openGraph;
272
- if (og.title)
273
- tags.push(`<meta property="og:title" content="${og.title}">`);
274
- if (og.description)
275
- tags.push(`<meta property="og:description" content="${og.description}">`);
276
- if (og.type)
277
- tags.push(`<meta property="og:type" content="${og.type}">`);
278
- if (og.url)
279
- tags.push(`<meta property="og:url" content="${og.url}">`);
280
- if (og.siteName)
281
- tags.push(`<meta property="og:site_name" content="${og.siteName}">`);
282
- if (og.locale)
283
- tags.push(`<meta property="og:locale" content="${og.locale}">`);
284
- if (og.image) {
285
- const imgUrl = typeof og.image === 'string' ? og.image : og.image.url;
286
- tags.push(`<meta property="og:image" content="${imgUrl}">`);
287
- if (typeof og.image !== 'string') {
288
- if (og.image.width)
289
- tags.push(`<meta property="og:image:width" content="${og.image.width}">`);
290
- if (og.image.height)
291
- tags.push(`<meta property="og:image:height" content="${og.image.height}">`);
292
- if (og.image.alt)
293
- tags.push(`<meta property="og:image:alt" content="${og.image.alt}">`);
294
- }
295
- }
296
- }
297
- // Twitter Card
298
- if (metadata.twitter) {
299
- const tw = metadata.twitter;
300
- if (tw.card)
301
- tags.push(`<meta name="twitter:card" content="${tw.card}">`);
302
- if (tw.site)
303
- tags.push(`<meta name="twitter:site" content="${tw.site}">`);
304
- if (tw.creator)
305
- tags.push(`<meta name="twitter:creator" content="${tw.creator}">`);
306
- if (tw.title)
307
- tags.push(`<meta name="twitter:title" content="${tw.title}">`);
308
- if (tw.description)
309
- tags.push(`<meta name="twitter:description" content="${tw.description}">`);
310
- if (tw.image)
311
- tags.push(`<meta name="twitter:image" content="${tw.image}">`);
312
- if (tw.imageAlt)
313
- tags.push(`<meta name="twitter:image:alt" content="${tw.imageAlt}">`);
314
- }
315
- // Custom Meta Tags
316
- if (metadata.other) {
317
- for (const [key, value] of Object.entries(metadata.other)) {
318
- tags.push(`<meta name="${key}" content="${value}">`);
319
- }
320
- }
321
- if (metadata.scripts) {
322
- for (const [key, value] of Object.entries(metadata.scripts)) {
323
- const rest = Object.entries(value).map((r) => {
324
- return '' + r[0] + '="' + r[1] + '"';
325
- });
326
- tags.push(`<script src="${key}" ${rest.join(" ")}></script>`);
327
- }
328
- }
329
- return tags.join('\n');
330
- }
331
- function obfuscateData(data) {
332
- const jsonStr = JSON.stringify(data);
333
- const base64 = Buffer.from(jsonStr).toString('base64');
334
- const hash = Buffer.from(Date.now().toString()).toString('base64').substring(0, 8);
335
- return `${hash}.${base64}`;
336
- }
337
- function getBuildAssets(req) {
338
- const projectDir = process.cwd();
339
- const distDir = path_1.default.join(projectDir, '.vatts');
340
- const assetsDir = path_1.default.join(distDir, 'assets');
341
- const chunksDir = path_1.default.join(distDir, 'chunks');
342
- if (!fs_1.default.existsSync(distDir))
343
- return null;
344
- let scripts = [];
345
- let styles = [];
346
- // Helper para processar arquivos de um diretório
347
- const processDirectory = (directory, urlPrefix) => {
348
- if (!fs_1.default.existsSync(directory))
349
- return;
350
- const files = fs_1.default.readdirSync(directory);
351
- files.forEach(file => {
352
- if (file.endsWith('.map'))
353
- return; // Ignora sourcemaps
354
- const fullPath = path_1.default.join(directory, file);
355
- const stat = fs_1.default.statSync(fullPath);
356
- if (stat.isFile()) {
357
- // MODIFICADO: Aceita .js OU .js.bra
358
- if (file.endsWith('.js') || file.endsWith('.js.br') || file.endsWith('.js.gz')) {
359
- scripts.push(`${urlPrefix}/${file.replace(".br", '').replace(".gz", '')}`);
360
- }
361
- else if (file.endsWith('.css')) {
362
- styles.push(`${urlPrefix}/${file}`);
363
- }
364
- }
365
- });
366
- };
367
- try {
368
- // 1. Verificar Manifesto (se existir)
369
- const manifestPath = path_1.default.join(distDir, 'manifest.json');
370
- if (fs_1.default.existsSync(manifestPath)) {
371
- const manifest = JSON.parse(fs_1.default.readFileSync(manifestPath, 'utf8'));
372
- const manifestFiles = Object.values(manifest);
373
- scripts = manifestFiles
374
- // MODIFICADO: Filtra .js E .js.br no manifesto
375
- .filter((f) => f.endsWith('.js') || f.endsWith('.js.br') || f.endsWith('.js.gz'))
376
- .map((f) => `/_vatts/${f.replace(".br", "").replace(".gz", "")}`);
377
- styles = manifestFiles
378
- .filter((f) => f.endsWith('.css'))
379
- .map((f) => `/_vatts/${f}`);
380
- }
381
- else {
382
- // 2. Fallback: Scan manual de diretórios
383
- // Scan na raiz .vatts/ (Geralmente entry points)
384
- processDirectory(distDir, '/_vatts');
385
- // Scan em .vatts/assets/ (Assets estáticos, chunks, CSS extraído)
386
- processDirectory(assetsDir, '/_vatts/assets');
387
- processDirectory(chunksDir, '/_vatts/chunks');
388
- // Ordenação básica para garantir que o main carregue
389
- scripts.sort((a, b) => {
390
- if (a.includes('main'))
391
- return -1;
392
- if (b.includes('main'))
393
- return 1;
394
- return a.localeCompare(b);
395
- });
396
- }
397
- if (scripts.length === 0)
398
- return null;
399
- return { scripts, styles };
400
- }
401
- catch (e) {
402
- console.error("Error loading assets:", e);
403
- return null;
404
- }
405
- }
406
97
  function ServerRoot({ lang, title, metaTagsHtml, stylesHtml, initialDataScript, hotReloadScript, dataScript, children }) {
407
98
  // Concatena tudo que vai no head em uma única string
408
99
  const headContent = `
@@ -422,7 +113,7 @@ function ServerRoot({ lang, title, metaTagsHtml, stylesHtml, initialDataScript,
422
113
  async function render({ req, res, route, params, allRoutes }) {
423
114
  // ATENÇÃO: Polyfill executado aqui para garantir que window/document existam
424
115
  // antes de qualquer lógica de componente ser executada.
425
- polyfillBrowserEnv();
116
+ (0, common_1.polyfillBrowserEnv)();
426
117
  const { generateMetadata } = route;
427
118
  const isProduction = !req.hwebDev;
428
119
  const hotReloadManager = req.hotReloadManager;
@@ -432,7 +123,7 @@ async function render({ req, res, route, params, allRoutes }) {
432
123
  let layoutInfo = null;
433
124
  try {
434
125
  // 1. Verificar Build - Se não tiver scripts, retorna tela de Loading
435
- assets = getBuildAssets(req);
126
+ assets = (0, common_1.getBuildAssets)();
436
127
  if (!assets || assets.scripts.length === 0) {
437
128
  const { pipe } = (0, server_1.renderToPipeableStream)(react_1.default.createElement(BuildingPage_1.default, null), {
438
129
  onShellReady() {
@@ -448,7 +139,7 @@ async function render({ req, res, route, params, allRoutes }) {
448
139
  if (layoutInfo) {
449
140
  try {
450
141
  // Recarrega o componente de layout para ter acesso à função (o router só guarda metadata)
451
- const layoutModule = requireWithoutStyles(path_1.default.resolve(process.cwd(), layoutInfo.componentPath));
142
+ const layoutModule = (0, common_1.requireWithoutStyles)(path_1.default.resolve(process.cwd(), layoutInfo.componentPath));
452
143
  LayoutComponent = layoutModule.default;
453
144
  }
454
145
  catch (e) {
@@ -484,9 +175,9 @@ async function render({ req, res, route, params, allRoutes }) {
484
175
  initialParams: params,
485
176
  };
486
177
  // Scripts e Estilos
487
- const obfuscatedData = obfuscateData(initialData);
178
+ const obfuscatedData = (0, common_1.obfuscateData)(initialData);
488
179
  const hotReloadScript = !isProduction && hotReloadManager ? hotReloadManager.getClientScript() : '';
489
- const metaTagsHtml = generateMetaTags(metadata);
180
+ const metaTagsHtml = (0, common_1.generateMetaTags)(metadata);
490
181
  const htmlLang = metadata.language || 'pt-BR';
491
182
  // Gera tags de estilo para o head
492
183
  const stylesHtml = assets.styles.map(styleUrl => `<link rel="stylesheet" href="${styleUrl}">`).join('\n');
@@ -559,7 +250,7 @@ async function render({ req, res, route, params, allRoutes }) {
559
250
  title: metadata.title || 'Vatts.js',
560
251
  metaTagsHtml: (() => {
561
252
  try {
562
- return generateMetaTags(metadata);
253
+ return (0, common_1.generateMetaTags)(metadata);
563
254
  }
564
255
  catch {
565
256
  return '';
@@ -569,7 +260,7 @@ async function render({ req, res, route, params, allRoutes }) {
569
260
  hotReloadScript: !isProduction && hotReloadManager ? hotReloadManager.getClientScript() : '',
570
261
  obfuscatedData: (() => {
571
262
  try {
572
- return obfuscateData({
263
+ return (0, common_1.obfuscateData)({
573
264
  routes: [],
574
265
  initialComponentPath: route.componentPath,
575
266
  initialParams: params,
@@ -0,0 +1,57 @@
1
+ import type { GenericRequest } from '../types/framework';
2
+ import { Metadata } from '../types';
3
+ /**
4
+ * Common utility functions shared between React and Vue renderers
5
+ */
6
+ /**
7
+ * Removes all script tags from HTML string
8
+ */
9
+ export declare function stripScriptTags(html: string): string;
10
+ /**
11
+ * Extracts the request URL from generic request object
12
+ */
13
+ export declare function getRequestUrl(req: GenericRequest): string | undefined;
14
+ /**
15
+ * Converts an unknown error to an Error instance
16
+ */
17
+ export declare function toError(err: unknown): Error;
18
+ /**
19
+ * Creates a fake browser environment for server-side rendering
20
+ * This prevents client-side libraries from breaking when used in Node.js
21
+ */
22
+ export declare function createBrowserEnvironmentPolyfill(): any;
23
+ /**
24
+ * Sets up the global browser environment polyfill for SSR
25
+ * Safely handles Node.js read-only properties
26
+ */
27
+ export declare function polyfillBrowserEnv(): void;
28
+ /**
29
+ * Imports a module while ignoring CSS and other style imports
30
+ * Prevents style processing errors during SSR
31
+ */
32
+ export declare function requireWithoutStyles<T>(modulePath: string): T;
33
+ /**
34
+ * Obfuscates data for client-side hydration
35
+ * Uses base64 encoding with a timestamp hash
36
+ */
37
+ export declare function obfuscateData(data: any): string;
38
+ /**
39
+ * Generates HTML meta tags from metadata object
40
+ */
41
+ export declare function generateMetaTags(metadata: Metadata): string;
42
+ /**
43
+ * Interface for build assets (scripts and styles)
44
+ */
45
+ export interface BuildAssets {
46
+ scripts: string[];
47
+ styles: string[];
48
+ }
49
+ /**
50
+ * Retrieves compiled assets from .vatts build directory
51
+ */
52
+ export declare function getBuildAssets(): BuildAssets | null;
53
+ /**
54
+ * Analyzes component source code to extract static asset imports
55
+ * and generate preload links for injection into the head
56
+ */
57
+ export declare function extractComponentPreloads(componentPath: string): string[];
@@ -0,0 +1,411 @@
1
+ "use strict";
2
+ /*
3
+ * This file is part of the Vatts.js Project.
4
+ * Copyright (c) 2026 mfraz
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+ var __importDefault = (this && this.__importDefault) || function (mod) {
19
+ return (mod && mod.__esModule) ? mod : { "default": mod };
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.stripScriptTags = stripScriptTags;
23
+ exports.getRequestUrl = getRequestUrl;
24
+ exports.toError = toError;
25
+ exports.createBrowserEnvironmentPolyfill = createBrowserEnvironmentPolyfill;
26
+ exports.polyfillBrowserEnv = polyfillBrowserEnv;
27
+ exports.requireWithoutStyles = requireWithoutStyles;
28
+ exports.obfuscateData = obfuscateData;
29
+ exports.generateMetaTags = generateMetaTags;
30
+ exports.getBuildAssets = getBuildAssets;
31
+ exports.extractComponentPreloads = extractComponentPreloads;
32
+ const fs_1 = __importDefault(require("fs"));
33
+ const path_1 = __importDefault(require("path"));
34
+ /**
35
+ * Common utility functions shared between React and Vue renderers
36
+ */
37
+ // --- String/HTML Utilities ---
38
+ /**
39
+ * Removes all script tags from HTML string
40
+ */
41
+ function stripScriptTags(html) {
42
+ if (!html)
43
+ return '';
44
+ return html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, '');
45
+ }
46
+ /**
47
+ * Extracts the request URL from generic request object
48
+ */
49
+ function getRequestUrl(req) {
50
+ return req?.originalUrl || req?.url;
51
+ }
52
+ /**
53
+ * Converts an unknown error to an Error instance
54
+ */
55
+ function toError(err) {
56
+ if (err instanceof Error)
57
+ return err;
58
+ if (typeof err === 'string')
59
+ return new Error(err);
60
+ try {
61
+ return new Error(JSON.stringify(err));
62
+ }
63
+ catch {
64
+ return new Error(String(err));
65
+ }
66
+ }
67
+ // --- Browser Environment Polyfills ---
68
+ /**
69
+ * Creates a fake browser environment for server-side rendering
70
+ * This prevents client-side libraries from breaking when used in Node.js
71
+ */
72
+ function createBrowserEnvironmentPolyfill() {
73
+ return {
74
+ document: {
75
+ createElement: () => ({ style: {}, setAttribute: () => { }, classList: { add: () => { }, remove: () => { } } }),
76
+ getElementById: () => null,
77
+ getElementsByTagName: () => [],
78
+ querySelector: () => null,
79
+ querySelectorAll: () => [],
80
+ head: {},
81
+ body: { style: {} },
82
+ addEventListener: () => { },
83
+ removeEventListener: () => { },
84
+ cookie: '',
85
+ location: { href: '', origin: '' },
86
+ scrollTo: () => { },
87
+ },
88
+ navigator: {
89
+ userAgent: 'Node.js/VattsSSR',
90
+ },
91
+ location: {
92
+ href: 'http://localhost',
93
+ origin: 'http://localhost',
94
+ pathname: '/',
95
+ search: '',
96
+ hash: '',
97
+ assign: () => { },
98
+ replace: () => { },
99
+ reload: () => { },
100
+ },
101
+ history: {
102
+ pushState: () => { },
103
+ replaceState: () => { },
104
+ },
105
+ screen: { width: 1920, height: 1080 },
106
+ addEventListener: () => { },
107
+ removeEventListener: () => { },
108
+ matchMedia: () => ({ matches: false, addListener: () => { }, removeListener: () => { } }),
109
+ requestAnimationFrame: (cb) => setTimeout(cb, 0),
110
+ cancelAnimationFrame: (id) => clearTimeout(id),
111
+ setTimeout: setTimeout,
112
+ clearTimeout: clearTimeout,
113
+ setInterval: setInterval,
114
+ clearInterval: clearInterval,
115
+ localStorage: {
116
+ getItem: () => null,
117
+ setItem: () => { },
118
+ removeItem: () => { },
119
+ clear: () => { },
120
+ },
121
+ sessionStorage: {
122
+ getItem: () => null,
123
+ setItem: () => { },
124
+ removeItem: () => { },
125
+ clear: () => { },
126
+ },
127
+ console: {
128
+ log: () => { },
129
+ warn: () => { },
130
+ error: () => { },
131
+ info: () => { },
132
+ debug: () => { },
133
+ trace: () => { },
134
+ dir: () => { },
135
+ },
136
+ Image: class {
137
+ constructor() { }
138
+ },
139
+ };
140
+ }
141
+ /**
142
+ * Sets up the global browser environment polyfill for SSR
143
+ * Safely handles Node.js read-only properties
144
+ */
145
+ function polyfillBrowserEnv() {
146
+ if (typeof window === 'undefined') {
147
+ const win = createBrowserEnvironmentPolyfill();
148
+ const globalAny = global;
149
+ // Helper to safely set globals
150
+ // Node 21+ has read-only globals like 'navigator', 'performance' etc
151
+ const setGlobal = (key, value) => {
152
+ try {
153
+ if (typeof globalAny[key] === 'undefined') {
154
+ globalAny[key] = value;
155
+ }
156
+ }
157
+ catch (e) {
158
+ // If it fails (read-only property), silently ignore
159
+ }
160
+ };
161
+ setGlobal('window', win);
162
+ setGlobal('document', win.document);
163
+ setGlobal('navigator', win.navigator);
164
+ setGlobal('location', win.location);
165
+ setGlobal('localStorage', win.localStorage);
166
+ setGlobal('sessionStorage', win.sessionStorage);
167
+ setGlobal('requestAnimationFrame', win.requestAnimationFrame);
168
+ setGlobal('cancelAnimationFrame', win.cancelAnimationFrame);
169
+ }
170
+ }
171
+ // --- Module Loading Utilities ---
172
+ /**
173
+ * Imports a module while ignoring CSS and other style imports
174
+ * Prevents style processing errors during SSR
175
+ */
176
+ function requireWithoutStyles(modulePath) {
177
+ const extensions = ['.css', '.scss', '.sass', '.less', '.png', '.jpg', '.jpeg', '.gif', '.svg'];
178
+ const originalHandlers = {};
179
+ extensions.forEach(ext => {
180
+ originalHandlers[ext] = require.extensions[ext];
181
+ require.extensions[ext] = (m, filename) => {
182
+ m.exports = {};
183
+ };
184
+ });
185
+ try {
186
+ const resolved = require.resolve(modulePath);
187
+ if (require.cache[resolved])
188
+ delete require.cache[resolved];
189
+ return require(modulePath);
190
+ }
191
+ catch (e) {
192
+ return require(modulePath);
193
+ }
194
+ finally {
195
+ extensions.forEach(ext => {
196
+ if (originalHandlers[ext]) {
197
+ require.extensions[ext] = originalHandlers[ext];
198
+ }
199
+ else {
200
+ delete require.extensions[ext];
201
+ }
202
+ });
203
+ }
204
+ }
205
+ // --- Data Obfuscation ---
206
+ /**
207
+ * Obfuscates data for client-side hydration
208
+ * Uses base64 encoding with a timestamp hash
209
+ */
210
+ function obfuscateData(data) {
211
+ const jsonStr = JSON.stringify(data);
212
+ const base64 = Buffer.from(jsonStr).toString('base64');
213
+ const hash = Buffer.from(Date.now().toString()).toString('base64').substring(0, 8);
214
+ return `${hash}.${base64}`;
215
+ }
216
+ // --- Metadata Generation ---
217
+ /**
218
+ * Generates HTML meta tags from metadata object
219
+ */
220
+ function generateMetaTags(metadata) {
221
+ const tags = [];
222
+ tags.push(`<meta charset="${metadata.charset || 'UTF-8'}">`);
223
+ tags.push(`<meta name="viewport" content="${metadata.viewport || 'width=device-width, initial-scale=1.0'}">`);
224
+ if (metadata.description)
225
+ tags.push(`<meta name="description" content="${metadata.description}">`);
226
+ if (metadata.keywords) {
227
+ const keywordsStr = Array.isArray(metadata.keywords) ? metadata.keywords.join(', ') : metadata.keywords;
228
+ tags.push(`<meta name="keywords" content="${keywordsStr}">`);
229
+ }
230
+ if (metadata.author)
231
+ tags.push(`<meta name="author" content="${metadata.author}">`);
232
+ if (metadata.themeColor)
233
+ tags.push(`<meta name="theme-color" content="${metadata.themeColor}">`);
234
+ if (metadata.robots)
235
+ tags.push(`<meta name="robots" content="${metadata.robots}">`);
236
+ if (metadata.canonical)
237
+ tags.push(`<link rel="canonical" href="${metadata.canonical}">`);
238
+ if (metadata.favicon)
239
+ tags.push(`<link rel="icon" href="${metadata.favicon}">`);
240
+ // Apple & Manifest
241
+ if (metadata.appleTouchIcon)
242
+ tags.push(`<link rel="apple-touch-icon" href="${metadata.appleTouchIcon}">`);
243
+ if (metadata.manifest)
244
+ tags.push(`<link rel="manifest" href="${metadata.manifest}">`);
245
+ // Open Graph
246
+ if (metadata.openGraph) {
247
+ const og = metadata.openGraph;
248
+ if (og.title)
249
+ tags.push(`<meta property="og:title" content="${og.title}">`);
250
+ if (og.description)
251
+ tags.push(`<meta property="og:description" content="${og.description}">`);
252
+ if (og.type)
253
+ tags.push(`<meta property="og:type" content="${og.type}">`);
254
+ if (og.url)
255
+ tags.push(`<meta property="og:url" content="${og.url}">`);
256
+ if (og.siteName)
257
+ tags.push(`<meta property="og:site_name" content="${og.siteName}">`);
258
+ if (og.locale)
259
+ tags.push(`<meta property="og:locale" content="${og.locale}">`);
260
+ if (og.image) {
261
+ const imgUrl = typeof og.image === 'string' ? og.image : og.image.url;
262
+ tags.push(`<meta property="og:image" content="${imgUrl}">`);
263
+ if (typeof og.image !== 'string') {
264
+ if (og.image.width)
265
+ tags.push(`<meta property="og:image:width" content="${og.image.width}">`);
266
+ if (og.image.height)
267
+ tags.push(`<meta property="og:image:height" content="${og.image.height}">`);
268
+ if (og.image.alt)
269
+ tags.push(`<meta property="og:image:alt" content="${og.image.alt}">`);
270
+ }
271
+ }
272
+ }
273
+ // Twitter Card
274
+ if (metadata.twitter) {
275
+ const tw = metadata.twitter;
276
+ if (tw.card)
277
+ tags.push(`<meta name="twitter:card" content="${tw.card}">`);
278
+ if (tw.site)
279
+ tags.push(`<meta name="twitter:site" content="${tw.site}">`);
280
+ if (tw.creator)
281
+ tags.push(`<meta name="twitter:creator" content="${tw.creator}">`);
282
+ if (tw.title)
283
+ tags.push(`<meta name="twitter:title" content="${tw.title}">`);
284
+ if (tw.description)
285
+ tags.push(`<meta name="twitter:description" content="${tw.description}">`);
286
+ if (tw.image)
287
+ tags.push(`<meta name="twitter:image" content="${tw.image}">`);
288
+ if (tw.imageAlt)
289
+ tags.push(`<meta name="twitter:image:alt" content="${tw.imageAlt}">`);
290
+ }
291
+ // Custom Meta Tags
292
+ if (metadata.other) {
293
+ for (const [key, value] of Object.entries(metadata.other)) {
294
+ tags.push(`<meta name="${key}" content="${value}">`);
295
+ }
296
+ }
297
+ if (metadata.scripts) {
298
+ for (const [key, value] of Object.entries(metadata.scripts)) {
299
+ const rest = Object.entries(value).map((r) => {
300
+ return '' + r[0] + '="' + r[1] + '"';
301
+ });
302
+ tags.push(`<script src="${key}" ${rest.join(" ")}></script>`);
303
+ }
304
+ }
305
+ return tags.join('\n');
306
+ }
307
+ /**
308
+ * Retrieves compiled assets from .vatts build directory
309
+ */
310
+ function getBuildAssets() {
311
+ const projectDir = process.cwd();
312
+ const distDir = path_1.default.join(projectDir, '.vatts');
313
+ const assetsDir = path_1.default.join(distDir, 'assets');
314
+ const chunksDir = path_1.default.join(distDir, 'chunks');
315
+ if (!fs_1.default.existsSync(distDir))
316
+ return null;
317
+ const scripts = [];
318
+ const styles = [];
319
+ // Helper to process directories
320
+ const processDirectory = (directory, urlPrefix) => {
321
+ if (!fs_1.default.existsSync(directory))
322
+ return;
323
+ const files = fs_1.default.readdirSync(directory);
324
+ files.forEach(file => {
325
+ if (file.endsWith('.map'))
326
+ return; // Skip sourcemaps
327
+ const url = `${urlPrefix}/${file.replace(".br", '').replace(".gz", '')}`;
328
+ // Support .js, .js.br, .js.gz
329
+ if (file.endsWith('.js') || file.endsWith('.js.br') || file.endsWith('.js.gz')) {
330
+ scripts.push(url);
331
+ }
332
+ else if (file.endsWith('.css')) {
333
+ styles.push(url);
334
+ }
335
+ });
336
+ };
337
+ // Read assets from .vatts/
338
+ processDirectory(distDir, '/_vatts');
339
+ // Read assets from .vatts/assets
340
+ processDirectory(assetsDir, '/_vatts/assets');
341
+ // Read chunks from .vatts/chunks
342
+ processDirectory(chunksDir, '/_vatts/chunks');
343
+ return { scripts, styles };
344
+ }
345
+ /**
346
+ * Analyzes component source code to extract static asset imports
347
+ * and generate preload links for injection into the head
348
+ */
349
+ function extractComponentPreloads(componentPath) {
350
+ if (!componentPath || !fs_1.default.existsSync(componentPath))
351
+ return [];
352
+ const assetsDir = path_1.default.join(process.cwd(), '.vatts', 'assets');
353
+ let availableAssets = [];
354
+ try {
355
+ if (fs_1.default.existsSync(assetsDir)) {
356
+ availableAssets = fs_1.default.readdirSync(assetsDir);
357
+ }
358
+ }
359
+ catch (e) {
360
+ // Silently fail if assets dir not found
361
+ }
362
+ const findHashedAsset = (filename) => {
363
+ if (availableAssets.includes(filename))
364
+ return filename;
365
+ const ext = path_1.default.extname(filename);
366
+ const base = path_1.default.basename(filename, ext);
367
+ const match = availableAssets.find(asset => asset.endsWith(ext) && asset.includes(base));
368
+ return match || null;
369
+ };
370
+ try {
371
+ const content = fs_1.default.readFileSync(componentPath, 'utf8');
372
+ const tags = new Set();
373
+ const processPath = (fullPath) => {
374
+ const filename = path_1.default.basename(fullPath);
375
+ const realFilename = findHashedAsset(filename);
376
+ if (!realFilename) {
377
+ return;
378
+ }
379
+ const ext = path_1.default.extname(realFilename).toLowerCase();
380
+ const publicUrl = `/_vatts/assets/${realFilename}`;
381
+ if (['.mp4', '.webm'].includes(ext)) {
382
+ tags.add(`<link rel="preload" as="video" href="${publicUrl}">`);
383
+ }
384
+ else if (['.css'].includes(ext)) {
385
+ tags.add(`<link rel="preload" as="style" href="${publicUrl}">`);
386
+ tags.add(`<link rel="stylesheet" href="${publicUrl}">`);
387
+ }
388
+ else if (['.js', '.js.br', '.js.gz'].includes(ext)) {
389
+ tags.add(`<link rel="preload" as="script" href="${publicUrl.replace(".br", '').replace(".gz", '')}">`);
390
+ }
391
+ else if (['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.avif'].includes(ext)) {
392
+ tags.add(`<link rel="preload" as="image" href="${publicUrl}">`);
393
+ }
394
+ };
395
+ const importRegex = /(?:import(?:\s+[^;'"]+\s+from)?\s+|require\(\s*)['"]([^'"]+\.(png|jpg|jpeg|gif|svg|webp|avif|mp4|webm|css|js))['"]/g;
396
+ let match;
397
+ while ((match = importRegex.exec(content)) !== null) {
398
+ processPath(match[1]);
399
+ }
400
+ const imgTagRegex = /<img\s+[^>]*src=['"]([^'"]+\.(png|jpg|jpeg|gif|svg|webp|avif))['"]/g;
401
+ while ((match = imgTagRegex.exec(content)) !== null) {
402
+ const src = match[1];
403
+ processPath(src);
404
+ }
405
+ return Array.from(tags);
406
+ }
407
+ catch (e) {
408
+ console.warn(`Failed to extract preloads for ${componentPath}:`, e);
409
+ return [];
410
+ }
411
+ }
@@ -40,99 +40,11 @@ exports.renderVue = renderVue;
40
40
  const router_1 = require("../router");
41
41
  const fs_1 = __importDefault(require("fs"));
42
42
  const path_1 = __importDefault(require("path"));
43
+ const common_1 = require("../renderers/common");
43
44
  const vue = __importStar(require("vue"));
44
45
  const vueServerRenderer = __importStar(require("@vue/server-renderer"));
45
46
  const BuildingPage_vue_1 = __importDefault(require("./BuildingPage.vue"));
46
47
  const server_error_vue_1 = __importDefault(require("./server-error.vue"));
47
- function getRequestUrl(req) {
48
- return req?.originalUrl || req?.url;
49
- }
50
- // --- Polyfill para Browser Env no Server ---
51
- // Cria objetos globais falsos para evitar que bibliotecas client-side quebrem no SSR
52
- // CORREÇÃO: Usa setGlobal para evitar erros em propriedades read-only do Node (ex: navigator)
53
- function polyfillBrowserEnv() {
54
- if (typeof window === 'undefined') {
55
- const win = {
56
- document: {
57
- createElement: () => ({ style: {}, setAttribute: () => { }, classList: { add: () => { }, remove: () => { } } }),
58
- getElementById: () => null,
59
- getElementsByTagName: () => [],
60
- querySelector: () => null,
61
- querySelectorAll: () => [],
62
- head: {},
63
- body: { style: {} },
64
- addEventListener: () => { },
65
- removeEventListener: () => { },
66
- cookie: '',
67
- location: { href: '', origin: '' }
68
- },
69
- navigator: {
70
- userAgent: 'Node.js/VattsSSR',
71
- },
72
- location: {
73
- href: 'http://localhost',
74
- origin: 'http://localhost',
75
- pathname: '/',
76
- search: '',
77
- hash: '',
78
- assign: () => { },
79
- replace: () => { },
80
- reload: () => { },
81
- },
82
- history: {
83
- pushState: () => { },
84
- replaceState: () => { },
85
- },
86
- screen: { width: 1920, height: 1080 },
87
- addEventListener: () => { },
88
- removeEventListener: () => { },
89
- matchMedia: () => ({ matches: false, addListener: () => { }, removeListener: () => { } }),
90
- requestAnimationFrame: (cb) => setTimeout(cb, 0),
91
- cancelAnimationFrame: (id) => clearTimeout(id),
92
- setTimeout: setTimeout,
93
- clearTimeout: clearTimeout,
94
- setInterval: setInterval,
95
- clearInterval: clearInterval,
96
- localStorage: {
97
- getItem: () => null,
98
- setItem: () => { },
99
- removeItem: () => { },
100
- clear: () => { },
101
- },
102
- sessionStorage: {
103
- getItem: () => null,
104
- setItem: () => { },
105
- removeItem: () => { },
106
- clear: () => { },
107
- },
108
- console: console,
109
- Image: class {
110
- constructor() { }
111
- },
112
- };
113
- const globalAny = global;
114
- // Helper para definir globais de forma segura
115
- // Node 21+ tem globais 'navigator', 'performance' etc que são getter-only e quebram se tentar sobrescrever
116
- const setGlobal = (key, value) => {
117
- try {
118
- if (typeof globalAny[key] === 'undefined') {
119
- globalAny[key] = value;
120
- }
121
- }
122
- catch (e) {
123
- // Se falhar (propriedade read-only), ignoramos silenciosamente
124
- }
125
- };
126
- setGlobal('window', win);
127
- setGlobal('document', win.document);
128
- setGlobal('navigator', win.navigator);
129
- setGlobal('location', win.location);
130
- setGlobal('localStorage', win.localStorage);
131
- setGlobal('sessionStorage', win.sessionStorage);
132
- setGlobal('requestAnimationFrame', win.requestAnimationFrame);
133
- setGlobal('cancelAnimationFrame', win.cancelAnimationFrame);
134
- }
135
- }
136
48
  function buildVueShellDocument(options) {
137
49
  const { lang, title, metaTagsHtml, scriptPreloadsHtml, componentPreloadsHtml, stylesHtml, obfuscatedData, scriptsHtml, hotReloadScript, bodyInnerHtml, } = options;
138
50
  return `<!DOCTYPE html>
@@ -153,135 +65,6 @@ function buildVueShellDocument(options) {
153
65
  </body>
154
66
  </html>`;
155
67
  }
156
- function stripScriptTags(html) {
157
- if (!html)
158
- return '';
159
- return html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, '');
160
- }
161
- // --- Helpers de Servidor (Duplicados para manter isolamento) ---
162
- function requireWithoutStyles(modulePath) {
163
- const extensions = ['.css', '.scss', '.sass', '.less', '.png', '.jpg', '.jpeg', '.gif', '.svg'];
164
- const originalHandlers = {};
165
- extensions.forEach(ext => {
166
- originalHandlers[ext] = require.extensions[ext];
167
- require.extensions[ext] = (m, filename) => {
168
- m.exports = {};
169
- };
170
- });
171
- try {
172
- const resolved = require.resolve(modulePath);
173
- if (require.cache[resolved])
174
- delete require.cache[resolved];
175
- return require(modulePath);
176
- }
177
- catch (e) {
178
- return require(modulePath);
179
- }
180
- finally {
181
- extensions.forEach(ext => {
182
- if (originalHandlers[ext]) {
183
- require.extensions[ext] = originalHandlers[ext];
184
- }
185
- else {
186
- delete require.extensions[ext];
187
- }
188
- });
189
- }
190
- }
191
- function obfuscateData(data) {
192
- const jsonStr = JSON.stringify(data);
193
- const base64 = Buffer.from(jsonStr).toString('base64');
194
- const hash = Buffer.from(Date.now().toString()).toString('base64').substring(0, 8);
195
- return `${hash}.${base64}`;
196
- }
197
- /**
198
- * Analisa o código fonte do componente para encontrar imports estáticos de assets
199
- * e gerar links de preload para injetar no head.
200
- * * ATUALIZADO: Verifica se o arquivo existe em .vatts/assets (com hash) antes de gerar o link.
201
- */
202
- function extractComponentPreloads(componentPath) {
203
- if (!componentPath || !fs_1.default.existsSync(componentPath))
204
- return [];
205
- // Localização dos assets compilados para verificação de hash
206
- const assetsDir = path_1.default.join(process.cwd(), '.vatts', 'assets');
207
- let availableAssets = [];
208
- try {
209
- if (fs_1.default.existsSync(assetsDir)) {
210
- availableAssets = fs_1.default.readdirSync(assetsDir);
211
- }
212
- }
213
- catch (e) {
214
- // Silently fail if assets dir not found
215
- }
216
- // Função auxiliar para encontrar o arquivo real com hash
217
- const findHashedAsset = (filename) => {
218
- // 1. Se o arquivo existe exatamente como pedido
219
- if (availableAssets.includes(filename))
220
- return filename;
221
- // 2. Procura por versão com hash (ex: style.css -> style.CjdCylXW.css ou da8dfae3-style.CjdCylXW.css)
222
- const ext = path_1.default.extname(filename);
223
- const base = path_1.default.basename(filename, ext); // "style"
224
- // Filtra arquivos que terminam com a extensão correta e contêm o nome base
225
- // Isso garante que pegamos o arquivo hasheado gerado pelo build
226
- const match = availableAssets.find(asset => asset.endsWith(ext) && asset.includes(base));
227
- return match || null;
228
- };
229
- try {
230
- const content = fs_1.default.readFileSync(componentPath, 'utf8');
231
- const tags = new Set();
232
- const processPath = (fullPath) => {
233
- const filename = path_1.default.basename(fullPath);
234
- // VERIFICAÇÃO DE HASH:
235
- // Tenta encontrar o nome real do arquivo na pasta de assets.
236
- // Se não encontrar (retornar null), ignoramos o arquivo para não gerar link quebrado (404).
237
- const realFilename = findHashedAsset(filename);
238
- if (!realFilename) {
239
- return; // Bloqueia a entrada se não tiver correspondente hash/físico
240
- }
241
- const ext = path_1.default.extname(realFilename).toLowerCase();
242
- // Usa o nome real encontrado (com hash)
243
- const publicUrl = `/_vatts/assets/${realFilename}`;
244
- if (['.mp4', '.webm'].includes(ext)) {
245
- tags.add(`<link rel="preload" as="video" href="${publicUrl}">`);
246
- }
247
- else if (['.css'].includes(ext)) {
248
- tags.add(`<link rel="preload" as="style" href="${publicUrl}">`);
249
- tags.add(`<link rel="stylesheet" href="${publicUrl}">`);
250
- }
251
- else if (['.js', '.js.br', '.js.gz'].includes(ext)) {
252
- // Adicionado suporte para JS
253
- tags.add(`<link rel="preload" as="script" href="${publicUrl.replace(".br", '').replace(".gz", '')}">`);
254
- }
255
- else if (['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.avif'].includes(ext)) {
256
- tags.add(`<link rel="preload" as="image" href="${publicUrl}">`);
257
- }
258
- };
259
- // 1. Imports (ESM) & Requires (CJS)
260
- // Captura:
261
- // - import foo from './foo.png' (Named import)
262
- // - import './style.css' (Side-effect import)
263
- // - require('./image.jpg') (CommonJS)
264
- // Adicionado |js na lista de extensões
265
- const importRegex = /(?:import(?:\s+[^;'"]+\s+from)?\s+|require\(\s*)['"]([^'"]+\.(png|jpg|jpeg|gif|svg|webp|avif|mp4|webm|css|js))['"]/g;
266
- let match;
267
- while ((match = importRegex.exec(content)) !== null) {
268
- processPath(match[1]);
269
- }
270
- // 2. Imagens no Template (src="...")
271
- // Captura caminhos relativos ou absolutos de imagens hardcoded no HTML do Vue
272
- const imgTagRegex = /<img\s+[^>]*src=['"]([^'"]+\.(png|jpg|jpeg|gif|svg|webp|avif))['"]/g;
273
- while ((match = imgTagRegex.exec(content)) !== null) {
274
- const src = match[1];
275
- // Para tags img src, também processamos para tentar achar a versão hash
276
- processPath(src);
277
- }
278
- return Array.from(tags);
279
- }
280
- catch (e) {
281
- console.warn(`Failed to extract preloads for ${componentPath}:`, e);
282
- return [];
283
- }
284
- }
285
68
  /**
286
69
  * Garante que o componente Vue esteja carregado e compilado corretamente.
287
70
  * Se o loader falhar em trazer o template (render function), compilamos manualmente aqui.
@@ -291,7 +74,7 @@ function ensureVueComponent(existingComponent, componentPath) {
291
74
  // 1. Se não temos o componente objeto, tentamos carregar do disco
292
75
  if (!component && componentPath) {
293
76
  try {
294
- const module = requireWithoutStyles(componentPath);
77
+ const module = (0, common_1.requireWithoutStyles)(componentPath);
295
78
  component = module.default || module;
296
79
  }
297
80
  catch (e) {
@@ -374,150 +157,10 @@ function ensureVueComponent(existingComponent, componentPath) {
374
157
  }
375
158
  return component;
376
159
  }
377
- // --- Funções de Metadata ---
378
- function generateMetaTags(metadata) {
379
- const tags = [];
380
- tags.push(`<meta charset="${metadata.charset || 'UTF-8'}">`);
381
- tags.push(`<meta name="viewport" content="${metadata.viewport || 'width=device-width, initial-scale=1.0'}">`);
382
- if (metadata.description)
383
- tags.push(`<meta name="description" content="${metadata.description}">`);
384
- if (metadata.keywords) {
385
- const keywordsStr = Array.isArray(metadata.keywords) ? metadata.keywords.join(', ') : metadata.keywords;
386
- tags.push(`<meta name="keywords" content="${keywordsStr}">`);
387
- }
388
- if (metadata.author)
389
- tags.push(`<meta name="author" content="${metadata.author}">`);
390
- if (metadata.themeColor)
391
- tags.push(`<meta name="theme-color" content="${metadata.themeColor}">`);
392
- if (metadata.robots)
393
- tags.push(`<meta name="robots" content="${metadata.robots}">`);
394
- if (metadata.canonical)
395
- tags.push(`<link rel="canonical" href="${metadata.canonical}">`);
396
- if (metadata.favicon)
397
- tags.push(`<link rel="icon" href="${metadata.favicon}">`);
398
- // Apple & Manifest
399
- if (metadata.appleTouchIcon)
400
- tags.push(`<link rel="apple-touch-icon" href="${metadata.appleTouchIcon}">`);
401
- if (metadata.manifest)
402
- tags.push(`<link rel="manifest" href="${metadata.manifest}">`);
403
- // Open Graph
404
- if (metadata.openGraph) {
405
- const og = metadata.openGraph;
406
- if (og.title)
407
- tags.push(`<meta property="og:title" content="${og.title}">`);
408
- if (og.description)
409
- tags.push(`<meta property="og:description" content="${og.description}">`);
410
- if (og.type)
411
- tags.push(`<meta property="og:type" content="${og.type}">`);
412
- if (og.url)
413
- tags.push(`<meta property="og:url" content="${og.url}">`);
414
- if (og.siteName)
415
- tags.push(`<meta property="og:site_name" content="${og.siteName}">`);
416
- if (og.locale)
417
- tags.push(`<meta property="og:locale" content="${og.locale}">`);
418
- if (og.image) {
419
- const imgUrl = typeof og.image === 'string' ? og.image : og.image.url;
420
- tags.push(`<meta property="og:image" content="${imgUrl}">`);
421
- if (typeof og.image !== 'string') {
422
- if (og.image.width)
423
- tags.push(`<meta property="og:image:width" content="${og.image.width}">`);
424
- if (og.image.height)
425
- tags.push(`<meta property="og:image:height" content="${og.image.height}">`);
426
- if (og.image.alt)
427
- tags.push(`<meta property="og:image:alt" content="${og.image.alt}">`);
428
- }
429
- }
430
- }
431
- // Twitter Card
432
- if (metadata.twitter) {
433
- const tw = metadata.twitter;
434
- if (tw.card)
435
- tags.push(`<meta name="twitter:card" content="${tw.card}">`);
436
- if (tw.site)
437
- tags.push(`<meta name="twitter:site" content="${tw.site}">`);
438
- if (tw.creator)
439
- tags.push(`<meta name="twitter:creator" content="${tw.creator}">`);
440
- if (tw.title)
441
- tags.push(`<meta name="twitter:title" content="${tw.title}">`);
442
- if (tw.description)
443
- tags.push(`<meta name="twitter:description" content="${tw.description}">`);
444
- if (tw.image)
445
- tags.push(`<meta name="twitter:image" content="${tw.image}">`);
446
- if (tw.imageAlt)
447
- tags.push(`<meta name="twitter:image:alt" content="${tw.imageAlt}">`);
448
- }
449
- // Custom Meta Tags
450
- if (metadata.other) {
451
- for (const [key, value] of Object.entries(metadata.other)) {
452
- tags.push(`<meta name="${key}" content="${value}">`);
453
- }
454
- }
455
- if (metadata.scripts) {
456
- for (const [key, value] of Object.entries(metadata.scripts)) {
457
- const rest = Object.entries(value).map((r) => {
458
- return '' + r[0] + '="' + r[1] + '"';
459
- });
460
- tags.push(`<script src="${key}" ${rest.join(" ")}></script>`);
461
- }
462
- }
463
- return tags.join('\n');
464
- }
465
- function getBuildAssets(req) {
466
- const projectDir = process.cwd();
467
- const distDir = path_1.default.join(projectDir, '.vatts');
468
- const assetsDir = path_1.default.join(distDir, 'assets');
469
- if (!fs_1.default.existsSync(distDir))
470
- return null;
471
- let scripts = [];
472
- let styles = [];
473
- const processDirectory = (directory, urlPrefix) => {
474
- if (!fs_1.default.existsSync(directory))
475
- return;
476
- const files = fs_1.default.readdirSync(directory);
477
- files.forEach(file => {
478
- if (file.endsWith('.map'))
479
- return;
480
- const fullPath = path_1.default.join(directory, file);
481
- if (fs_1.default.statSync(fullPath).isFile()) {
482
- if (file.endsWith('.js') || file.endsWith(".js.br") || file.endsWith(".js.gz"))
483
- scripts.push(`${urlPrefix}/${file.replace(".br", '').replace(".gz", '')}`);
484
- else if (file.endsWith('.css'))
485
- styles.push(`${urlPrefix}/${file}`);
486
- }
487
- });
488
- };
489
- try {
490
- const manifestPath = path_1.default.join(distDir, 'manifest.json');
491
- if (fs_1.default.existsSync(manifestPath)) {
492
- const manifest = JSON.parse(fs_1.default.readFileSync(manifestPath, 'utf8'));
493
- const manifestFiles = Object.values(manifest);
494
- scripts = manifestFiles.filter((f) => f.endsWith('.js') || f.endsWith(".js.br")).map((f) => `/_vatts/${f.replace('.br', '')}`);
495
- styles = manifestFiles.filter((f) => f.endsWith('.css')).map((f) => `/_vatts/${f}`);
496
- }
497
- else {
498
- processDirectory(distDir, '/_vatts');
499
- processDirectory(assetsDir, '/_vatts/assets');
500
- scripts.sort((a, b) => {
501
- if (a.includes('main'))
502
- return -1;
503
- if (b.includes('main'))
504
- return 1;
505
- return a.localeCompare(b);
506
- });
507
- }
508
- if (scripts.length === 0)
509
- return null;
510
- return { scripts, styles };
511
- }
512
- catch (e) {
513
- console.error("Error loading assets:", e);
514
- return null;
515
- }
516
- }
517
160
  async function renderVue({ req, res, route, params, allRoutes }) {
518
161
  // ATENÇÃO: Polyfill executado aqui para garantir que window/document existam
519
162
  // antes de qualquer lógica de componente ser executada.
520
- polyfillBrowserEnv();
163
+ (0, common_1.polyfillBrowserEnv)();
521
164
  if (!vue) {
522
165
  res.statusCode = 500;
523
166
  res.end('Vue dependencies not installed.');
@@ -549,14 +192,14 @@ async function renderVue({ req, res, route, params, allRoutes }) {
549
192
  const hotReloadScript = includeScripts && !isProduction && hotReloadManager ? hotReloadManager.getClientScript() : '';
550
193
  let metaTagsHtml = (() => {
551
194
  try {
552
- return generateMetaTags(metadata);
195
+ return (0, common_1.generateMetaTags)(metadata);
553
196
  }
554
197
  catch {
555
198
  return '';
556
199
  }
557
200
  })();
558
201
  if (!includeScripts) {
559
- metaTagsHtml = stripScriptTags(metaTagsHtml);
202
+ metaTagsHtml = (0, common_1.stripScriptTags)(metaTagsHtml);
560
203
  }
561
204
  const htmlLang = metadata.language || 'pt-BR';
562
205
  const title = metadata.title || 'Vatts.js';
@@ -566,7 +209,7 @@ async function renderVue({ req, res, route, params, allRoutes }) {
566
209
  const componentPreloadsHtml = includeScripts
567
210
  ? (() => {
568
211
  try {
569
- const componentPreloads = extractComponentPreloads(route.componentPath ? path_1.default.resolve(process.cwd(), route.componentPath) : '');
212
+ const componentPreloads = (0, common_1.extractComponentPreloads)(route.componentPath ? path_1.default.resolve(process.cwd(), route.componentPath) : '');
570
213
  return componentPreloads.join('\n');
571
214
  }
572
215
  catch {
@@ -580,7 +223,7 @@ async function renderVue({ req, res, route, params, allRoutes }) {
580
223
  : '';
581
224
  const obfuscatedData = (() => {
582
225
  try {
583
- return obfuscateData({
226
+ return (0, common_1.obfuscateData)({
584
227
  routes: [],
585
228
  initialComponentPath: route.componentPath,
586
229
  initialParams: params,
@@ -615,7 +258,7 @@ async function renderVue({ req, res, route, params, allRoutes }) {
615
258
  setup() {
616
259
  return () => h(server_error_vue_1.default, {
617
260
  error,
618
- requestUrl: getRequestUrl(req),
261
+ requestUrl: (0, common_1.getRequestUrl)(req),
619
262
  hint: 'SSR failed to render this route. See the error below.',
620
263
  });
621
264
  },
@@ -629,7 +272,7 @@ async function renderVue({ req, res, route, params, allRoutes }) {
629
272
  }
630
273
  };
631
274
  try {
632
- assets = getBuildAssets(req);
275
+ assets = (0, common_1.getBuildAssets)();
633
276
  if (!assets || assets.scripts.length === 0) {
634
277
  const RootComponent = {
635
278
  setup() {
@@ -683,14 +326,14 @@ async function renderVue({ req, res, route, params, allRoutes }) {
683
326
  initialComponentPath: route.componentPath,
684
327
  initialParams: params,
685
328
  };
686
- const obfuscatedData = obfuscateData(initialData);
329
+ const obfuscatedData = (0, common_1.obfuscateData)(initialData);
687
330
  const hotReloadScript = !isProduction && hotReloadManager ? hotReloadManager.getClientScript() : '';
688
- const metaTagsHtml = generateMetaTags(metadata);
331
+ const metaTagsHtml = (0, common_1.generateMetaTags)(metadata);
689
332
  const htmlLang = metadata.language || 'pt-BR';
690
333
  // Otimização: Adiciona modulepreload para scripts principais do bundle
691
334
  const scriptPreloadsHtml = assets.scripts.map(src => `<link rel="modulepreload" href="${src}">`).join('\n');
692
335
  // Otimização: Intercepta assets do componente atual para preload
693
- const componentPreloads = extractComponentPreloads(route.componentPath ? path_1.default.resolve(process.cwd(), route.componentPath) : '');
336
+ const componentPreloads = (0, common_1.extractComponentPreloads)(route.componentPath ? path_1.default.resolve(process.cwd(), route.componentPath) : '');
694
337
  const componentPreloadsHtml = componentPreloads.join('\n');
695
338
  const stylesHtml = assets.styles.map(styleUrl => `<link rel="stylesheet" href="${styleUrl}">`).join('\n');
696
339
  const scriptsHtml = assets.scripts.map(src => `<script type="module" src="${src}"></script>`).join('\n');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vatts",
3
- "version": "2.1.2",
3
+ "version": "2.1.3-canary.1.0.0",
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": "mfraz",