vatts 1.1.4-alpha.9 → 1.2.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/express.js +2 -3
- package/dist/adapters/factory.js +1 -1
- package/dist/adapters/fastify.js +2 -3
- package/dist/adapters/native.js +6 -7
- package/dist/api/console.js +11 -9
- package/dist/api/framework.d.ts +2 -0
- package/dist/api/framework.js +37 -0
- package/dist/api/http.js +11 -11
- package/dist/bin/vatts.js +50 -87
- package/dist/builder.js +196 -113
- package/dist/client/clientRouter.js +1 -1
- package/dist/global/global.d.ts +177 -117
- package/dist/helpers.d.ts +8 -0
- package/dist/helpers.js +8 -3
- package/dist/hotReload.d.ts +6 -0
- package/dist/hotReload.js +128 -19
- package/dist/index.js +29 -12
- package/dist/loaders.js +110 -31
- package/dist/react/BuildingPage.d.ts +2 -0
- package/dist/{client → react}/BuildingPage.js +43 -3
- package/dist/react/DefaultNotFound.d.ts +2 -0
- package/dist/react/DefaultNotFound.js +242 -0
- package/dist/{client → react}/DevIndicator.js +57 -17
- package/dist/{client → react}/ErrorModal.js +77 -29
- package/dist/{components → react}/Link.d.ts +2 -2
- package/dist/{global/global.js → react/Link.js} +15 -0
- package/dist/{client → react}/client.d.ts +3 -3
- package/dist/{client → react}/client.js +3 -3
- package/dist/{client → react}/entry.client.js +10 -8
- package/dist/{client → react}/image/Image.js +5 -2
- package/dist/react/renderer-react.d.ts +15 -0
- package/dist/react/renderer-react.js +371 -0
- package/dist/renderer.d.ts +5 -2
- package/dist/renderer.js +14 -349
- package/dist/router.d.ts +1 -1
- package/dist/router.js +14 -8
- package/dist/types.d.ts +1 -2
- package/dist/vue/App.vue +180 -0
- package/dist/vue/BuildingPage.vue +272 -0
- package/dist/vue/DefaultNotFound.vue +307 -0
- package/dist/vue/DevIndicator.vue +210 -0
- package/dist/vue/ErrorModal.vue +301 -0
- package/dist/vue/Link.vue +23 -0
- package/dist/vue/client.d.ts +7 -0
- package/dist/vue/client.js +34 -0
- package/dist/vue/entry.client.d.ts +6 -0
- package/dist/vue/entry.client.js +99 -0
- package/dist/vue/image/Image.vue +107 -0
- package/dist/vue/renderer.vue.d.ts +15 -0
- package/dist/vue/renderer.vue.js +506 -0
- package/package.json +50 -14
- package/dist/client/BuildingPage.d.ts +0 -1
- package/dist/client/DefaultNotFound.d.ts +0 -1
- package/dist/client/DefaultNotFound.js +0 -170
- package/dist/components/Link.js +0 -13
- /package/dist/{client → react}/DevIndicator.d.ts +0 -0
- /package/dist/{client → react}/ErrorModal.d.ts +0 -0
- /package/dist/{client → react}/entry.client.d.ts +0 -0
- /package/dist/{client → react}/image/Image.d.ts +0 -0
package/dist/adapters/express.js
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ExpressAdapter = void 0;
|
|
4
4
|
class ExpressAdapter {
|
|
5
|
-
|
|
6
|
-
this.type = 'express';
|
|
7
|
-
}
|
|
5
|
+
type = 'express';
|
|
8
6
|
parseRequest(req) {
|
|
9
7
|
return {
|
|
10
8
|
method: req.method,
|
|
@@ -23,6 +21,7 @@ class ExpressAdapter {
|
|
|
23
21
|
}
|
|
24
22
|
exports.ExpressAdapter = ExpressAdapter;
|
|
25
23
|
class ExpressResponseWrapper {
|
|
24
|
+
res;
|
|
26
25
|
constructor(res) {
|
|
27
26
|
this.res = res;
|
|
28
27
|
}
|
package/dist/adapters/factory.js
CHANGED
|
@@ -42,6 +42,7 @@ const console_1 = __importStar(require("../api/console"));
|
|
|
42
42
|
* Factory para criar o adapter correto baseado no framework detectado
|
|
43
43
|
*/
|
|
44
44
|
class FrameworkAdapterFactory {
|
|
45
|
+
static adapter = null;
|
|
45
46
|
/**
|
|
46
47
|
* Detecta automaticamente o framework baseado na requisição/resposta
|
|
47
48
|
*/
|
|
@@ -118,4 +119,3 @@ class FrameworkAdapterFactory {
|
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
121
|
exports.FrameworkAdapterFactory = FrameworkAdapterFactory;
|
|
121
|
-
FrameworkAdapterFactory.adapter = null;
|
package/dist/adapters/fastify.js
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FastifyAdapter = void 0;
|
|
4
4
|
class FastifyAdapter {
|
|
5
|
-
|
|
6
|
-
this.type = 'fastify';
|
|
7
|
-
}
|
|
5
|
+
type = 'fastify';
|
|
8
6
|
parseRequest(req) {
|
|
9
7
|
return {
|
|
10
8
|
method: req.method,
|
|
@@ -23,6 +21,7 @@ class FastifyAdapter {
|
|
|
23
21
|
}
|
|
24
22
|
exports.FastifyAdapter = FastifyAdapter;
|
|
25
23
|
class FastifyResponseWrapper {
|
|
24
|
+
reply;
|
|
26
25
|
constructor(reply) {
|
|
27
26
|
this.reply = reply;
|
|
28
27
|
}
|
package/dist/adapters/native.js
CHANGED
|
@@ -24,9 +24,7 @@ function isValidCookieName(name) {
|
|
|
24
24
|
return validCookieNameRegex.test(name);
|
|
25
25
|
}
|
|
26
26
|
class NativeAdapter {
|
|
27
|
-
|
|
28
|
-
this.type = 'native';
|
|
29
|
-
}
|
|
27
|
+
type = 'native';
|
|
30
28
|
parseRequest(req) {
|
|
31
29
|
// URL absoluta é obrigatória para a API WHATWG
|
|
32
30
|
const fullUrl = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
|
|
@@ -70,12 +68,13 @@ class NativeAdapter {
|
|
|
70
68
|
}
|
|
71
69
|
exports.NativeAdapter = NativeAdapter;
|
|
72
70
|
class NativeResponseWrapper {
|
|
71
|
+
res;
|
|
72
|
+
statusCode = 200;
|
|
73
|
+
headers = {};
|
|
74
|
+
cookiesToSet = []; // Array para lidar corretamente com múltiplos cookies.
|
|
75
|
+
finished = false;
|
|
73
76
|
constructor(res) {
|
|
74
77
|
this.res = res;
|
|
75
|
-
this.statusCode = 200;
|
|
76
|
-
this.headers = {};
|
|
77
|
-
this.cookiesToSet = []; // Array para lidar corretamente com múltiplos cookies.
|
|
78
|
-
this.finished = false;
|
|
79
78
|
}
|
|
80
79
|
get raw() {
|
|
81
80
|
return this.res;
|
package/dist/api/console.js
CHANGED
|
@@ -27,9 +27,9 @@ const node_readline_1 = __importDefault(require("node:readline"));
|
|
|
27
27
|
* o conteúdo da linha.
|
|
28
28
|
*/
|
|
29
29
|
class DynamicLine {
|
|
30
|
+
// A ID é usada internamente pela classe Console para rastrear esta linha.
|
|
31
|
+
_id = Symbol();
|
|
30
32
|
constructor(initialContent) {
|
|
31
|
-
// A ID é usada internamente pela classe Console para rastrear esta linha.
|
|
32
|
-
this._id = Symbol();
|
|
33
33
|
// Registra esta nova linha na classe Console para que ela seja renderizada.
|
|
34
34
|
Console['registerDynamicLine'](this._id, initialContent);
|
|
35
35
|
}
|
|
@@ -87,6 +87,10 @@ var Levels;
|
|
|
87
87
|
Levels["SUCCESS"] = "SUCCESS";
|
|
88
88
|
})(Levels || (exports.Levels = Levels = {}));
|
|
89
89
|
class Console {
|
|
90
|
+
// Armazena o estado de todas as linhas dinâmicas ativas
|
|
91
|
+
static activeLines = [];
|
|
92
|
+
// Quantas linhas foram efetivamente renderizadas na última operação.
|
|
93
|
+
static lastRenderedLines = 0;
|
|
90
94
|
// --- MÉTODOS PRIVADOS PARA GERENCIAR A RENDERIZAÇÃO ---
|
|
91
95
|
static redrawDynamicLines() {
|
|
92
96
|
const stream = process.stdout;
|
|
@@ -117,9 +121,11 @@ class Console {
|
|
|
117
121
|
node_readline_1.default.cursorTo(stream, 0);
|
|
118
122
|
node_readline_1.default.clearScreenDown(stream);
|
|
119
123
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
stream.write
|
|
124
|
+
// MODIFICAÇÃO PRINCIPAL:
|
|
125
|
+
// Substituímos stream.write por console.log aqui.
|
|
126
|
+
// O console.log é interceptado pelos debuggers (VSCode, etc), o stream.write não.
|
|
127
|
+
// Removemos a quebra de linha final (\n$) pois o console.log já adiciona uma automaticamente.
|
|
128
|
+
console.log(content.replace(/\n$/, ''));
|
|
123
129
|
if (this.activeLines.length > 0) {
|
|
124
130
|
// ATUALIZADO: Garante que ao redesenhar após um log estático, o formato se mantém
|
|
125
131
|
stream.write(this.activeLines.map(l => this.formatLog('WAIT', l.content, Colors.FgRed)).join('\n') + '\n');
|
|
@@ -299,8 +305,4 @@ class Console {
|
|
|
299
305
|
return new DynamicLine(initialContent);
|
|
300
306
|
}
|
|
301
307
|
}
|
|
302
|
-
// Armazena o estado de todas as linhas dinâmicas ativas
|
|
303
|
-
Console.activeLines = [];
|
|
304
|
-
// Quantas linhas foram efetivamente renderizadas na última operação.
|
|
305
|
-
Console.lastRenderedLines = 0;
|
|
306
308
|
exports.default = Console;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.cachedFramework = void 0;
|
|
7
|
+
exports.default = detectFramework;
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
// Variável para armazenar o resultado em memória
|
|
11
|
+
exports.cachedFramework = null;
|
|
12
|
+
function detectFramework(projectDir = process.cwd()) {
|
|
13
|
+
// Se já tivermos um resultado, retorna ele direto sem ler o disco
|
|
14
|
+
if (exports.cachedFramework)
|
|
15
|
+
return exports.cachedFramework;
|
|
16
|
+
try {
|
|
17
|
+
const pkgPath = path_1.default.join(projectDir, 'package.json');
|
|
18
|
+
if (fs_1.default.existsSync(pkgPath)) {
|
|
19
|
+
const pkg = JSON.parse(fs_1.default.readFileSync(pkgPath, 'utf8'));
|
|
20
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
21
|
+
if (deps.react || deps['react-dom']) {
|
|
22
|
+
exports.cachedFramework = 'react';
|
|
23
|
+
return exports.cachedFramework;
|
|
24
|
+
}
|
|
25
|
+
if (deps.vue || deps['nuxt']) {
|
|
26
|
+
exports.cachedFramework = 'vue';
|
|
27
|
+
return exports.cachedFramework;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
// Ignora erro de leitura
|
|
33
|
+
}
|
|
34
|
+
// Salva o fallback no cache para evitar re-execução em caso de falha
|
|
35
|
+
exports.cachedFramework = 'react';
|
|
36
|
+
return exports.cachedFramework;
|
|
37
|
+
}
|
package/dist/api/http.js
CHANGED
|
@@ -3,6 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.VattsResponse = exports.VattsRequest = void 0;
|
|
4
4
|
// Input validation and sanitization utilities
|
|
5
5
|
class SecurityUtils {
|
|
6
|
+
static MAX_HEADER_LENGTH = 8192;
|
|
7
|
+
static MAX_COOKIE_LENGTH = 4096;
|
|
8
|
+
static MAX_URL_LENGTH = 2048;
|
|
9
|
+
static MAX_BODY_SIZE = 10 * 1024 * 1024; // 10MB
|
|
6
10
|
static sanitizeHeader(value) {
|
|
7
11
|
if (Array.isArray(value)) {
|
|
8
12
|
return value.map(v => this.sanitizeString(v, this.MAX_HEADER_LENGTH));
|
|
@@ -34,15 +38,13 @@ class SecurityUtils {
|
|
|
34
38
|
return length >= 0 && length <= this.MAX_BODY_SIZE;
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
|
-
SecurityUtils.MAX_HEADER_LENGTH = 8192;
|
|
38
|
-
SecurityUtils.MAX_COOKIE_LENGTH = 4096;
|
|
39
|
-
SecurityUtils.MAX_URL_LENGTH = 2048;
|
|
40
|
-
SecurityUtils.MAX_BODY_SIZE = 10 * 1024 * 1024; // 10MB
|
|
41
41
|
/**
|
|
42
42
|
* Abstração sobre a requisição HTTP de entrada.
|
|
43
43
|
* Funciona com qualquer framework web (Express, Fastify, etc.)
|
|
44
44
|
*/
|
|
45
45
|
class VattsRequest {
|
|
46
|
+
/** A requisição genérica parseada pelo adapter */
|
|
47
|
+
_req;
|
|
46
48
|
constructor(req) {
|
|
47
49
|
// Validate and sanitize request data
|
|
48
50
|
this._req = this.validateAndSanitizeRequest(req);
|
|
@@ -253,13 +255,11 @@ exports.VattsRequest = VattsRequest;
|
|
|
253
255
|
* Funciona com qualquer framework web (Express, Fastify, etc.)
|
|
254
256
|
*/
|
|
255
257
|
class VattsResponse {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
this._sent = false;
|
|
262
|
-
}
|
|
258
|
+
_status = 200;
|
|
259
|
+
_headers = {};
|
|
260
|
+
_cookies = [];
|
|
261
|
+
_body = null;
|
|
262
|
+
_sent = false;
|
|
263
263
|
/**
|
|
264
264
|
* Define o status HTTP da resposta
|
|
265
265
|
*/
|
package/dist/bin/vatts.js
CHANGED
|
@@ -16,48 +16,40 @@
|
|
|
16
16
|
* See the License for the specific language governing permissions and
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/
|
|
19
|
-
// Registra o ts-node para que o Node.js entenda TypeScript/TSX
|
|
20
19
|
require('ts-node').register();
|
|
21
|
-
// Registra loaders customizados para arquivos markdown, imagens, etc.
|
|
22
20
|
const { registerLoaders } = require('../loaders');
|
|
23
21
|
registerLoaders();
|
|
24
22
|
const { program } = require('commander');
|
|
25
23
|
const fs = require('fs');
|
|
26
24
|
const path = require('path');
|
|
27
25
|
const { Writable } = require('stream');
|
|
28
|
-
// Importa o Console do framework
|
|
29
26
|
const ConsoleModule = require('../api/console');
|
|
27
|
+
const { loadVattsConfig, config, setConfig } = require("../helpers");
|
|
28
|
+
const { default: detectFramework } = require("../api/framework");
|
|
29
|
+
const { renderAsStream } = require("../renderer");
|
|
30
30
|
const Console = ConsoleModule.default;
|
|
31
31
|
const { Levels, Colors } = ConsoleModule;
|
|
32
32
|
program
|
|
33
33
|
.version('1.0.0')
|
|
34
34
|
.description('CLI to manage the application.');
|
|
35
35
|
// --- Helpers ---
|
|
36
|
-
/**
|
|
37
|
-
* Função centralizada para iniciar a aplicação
|
|
38
|
-
* @param {object} options - Opções vindas do commander
|
|
39
|
-
* @param {boolean} isDev - Define se é modo de desenvolvimento
|
|
40
|
-
*/
|
|
41
36
|
function initializeApp(options, isDev) {
|
|
42
37
|
const appOptions = {
|
|
43
38
|
dev: isDev,
|
|
44
39
|
port: options.port,
|
|
45
40
|
hostname: options.hostname,
|
|
46
41
|
framework: 'native',
|
|
47
|
-
ssl: null,
|
|
42
|
+
ssl: null,
|
|
48
43
|
};
|
|
49
|
-
// 1. Verifica se a flag --ssl foi ativada
|
|
50
44
|
if (options.ssl) {
|
|
51
45
|
const sslDir = path.resolve(process.cwd(), 'certs');
|
|
52
46
|
const keyPath = path.join(sslDir, 'key.pem');
|
|
53
47
|
const certPath = path.join(sslDir, 'cert.pem');
|
|
54
|
-
// 2. Verifica se os arquivos existem
|
|
55
48
|
if (fs.existsSync(keyPath) && fs.existsSync(certPath)) {
|
|
56
49
|
appOptions.ssl = {
|
|
57
50
|
key: keyPath,
|
|
58
51
|
cert: certPath
|
|
59
52
|
};
|
|
60
|
-
// 3. Adiciona a porta de redirecionamento
|
|
61
53
|
appOptions.ssl.redirectPort = options.httpRedirectPort || 80;
|
|
62
54
|
}
|
|
63
55
|
else {
|
|
@@ -65,14 +57,10 @@ function initializeApp(options, isDev) {
|
|
|
65
57
|
process.exit(1);
|
|
66
58
|
}
|
|
67
59
|
}
|
|
68
|
-
// 4. Inicia o helper com as opções
|
|
69
60
|
const helperModule = require("../helpers");
|
|
70
61
|
const helper = helperModule.default(appOptions);
|
|
71
62
|
helper.init();
|
|
72
63
|
}
|
|
73
|
-
/**
|
|
74
|
-
* Função corrigida para copiar diretórios recursivamente.
|
|
75
|
-
*/
|
|
76
64
|
function copyDirRecursive(src, dest) {
|
|
77
65
|
try {
|
|
78
66
|
fs.mkdirSync(dest, { recursive: true });
|
|
@@ -94,136 +82,115 @@ function copyDirRecursive(src, dest) {
|
|
|
94
82
|
}
|
|
95
83
|
}
|
|
96
84
|
// --- Comandos ---
|
|
97
|
-
// Comando DEV
|
|
98
85
|
program
|
|
99
86
|
.command('dev')
|
|
100
87
|
.description('Starts the application in development mode.')
|
|
101
88
|
.option('-p, --port <number>', 'Specifies the port to run on', '3000')
|
|
102
89
|
.option('-H, --hostname <string>', 'Specifies the hostname to run on', '0.0.0.0')
|
|
103
|
-
.option('--ssl', 'Activates HTTPS/SSL mode
|
|
90
|
+
.option('--ssl', 'Activates HTTPS/SSL mode')
|
|
104
91
|
.option('--http-redirect-port <number>', 'Port for HTTP->HTTPS redirection', '80')
|
|
105
92
|
.action((options) => {
|
|
106
93
|
initializeApp(options, true);
|
|
107
94
|
});
|
|
108
|
-
// Comando START (Produção)
|
|
109
95
|
program
|
|
110
96
|
.command('start')
|
|
111
97
|
.description('Starts the application in production mode.')
|
|
112
98
|
.option('-p, --port <number>', 'Specifies the port to run on', '3000')
|
|
113
99
|
.option('-H, --hostname <string>', 'Specifies the hostname to run on', '0.0.0.0')
|
|
114
|
-
.option('--ssl', 'Activates HTTPS/SSL mode
|
|
100
|
+
.option('--ssl', 'Activates HTTPS/SSL mode')
|
|
115
101
|
.option('--http-redirect-port <number>', 'Port for HTTP->HTTPS redirection', '80')
|
|
116
102
|
.action((options) => {
|
|
117
103
|
initializeApp(options, false);
|
|
118
104
|
});
|
|
119
|
-
// Comando EXPORT
|
|
120
105
|
program
|
|
121
106
|
.command('export')
|
|
122
107
|
.description('Exports the application as static HTML to the "exported" folder.')
|
|
123
108
|
.option('-o, --output <path>', 'Specifies the output directory', 'exported')
|
|
124
|
-
.option('--assets-dir <path>', 'Directory
|
|
109
|
+
.option('--assets-dir <path>', 'Directory where the .vatts assets will be written', '.vatts')
|
|
125
110
|
.option('--no-html', 'Do not generate index.html (assets only)')
|
|
126
|
-
.option('--output-h-data <file>', 'Write the data-h value
|
|
111
|
+
.option('--output-h-data <file>', 'Write the data-h value into this file')
|
|
127
112
|
.action(async (options) => {
|
|
128
113
|
const projectDir = process.cwd();
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
? options.output.trim()
|
|
132
|
-
: 'exported';
|
|
133
|
-
const exportDir = path.isAbsolute(outputInput)
|
|
134
|
-
? path.resolve(outputInput)
|
|
135
|
-
: path.resolve(projectDir, outputInput);
|
|
136
|
-
const exportDirResolved = path.resolve(exportDir);
|
|
137
|
-
const exportDirRoot = path.parse(exportDirResolved).root;
|
|
114
|
+
const outputInput = (typeof options.output === 'string' && options.output.trim()) || 'exported';
|
|
115
|
+
const exportDirResolved = path.resolve(projectDir, outputInput);
|
|
138
116
|
const projectDirResolved = path.resolve(projectDir);
|
|
139
|
-
if (exportDirResolved ===
|
|
140
|
-
Console.error(`Refusing to use
|
|
141
|
-
process.exit(1);
|
|
142
|
-
}
|
|
143
|
-
const relExportToProject = path.relative(projectDirResolved, exportDirResolved);
|
|
144
|
-
if (relExportToProject === '' || relExportToProject === '.' || relExportToProject.startsWith('..')) {
|
|
145
|
-
Console.error(`Refusing to export to ${exportDirResolved}. Use a subfolder like "exported" or an explicit path inside the project.`);
|
|
117
|
+
if (exportDirResolved === path.parse(exportDirResolved).root) {
|
|
118
|
+
Console.error(`Refusing to use drive root: ${exportDirResolved}`);
|
|
146
119
|
process.exit(1);
|
|
147
120
|
}
|
|
148
|
-
|
|
149
|
-
const assetsDirInputRaw = typeof options.assetsDir === 'string' ? options.assetsDir : '.vatts';
|
|
150
|
-
const assetsDirInput = assetsDirInputRaw.trim().length ? assetsDirInputRaw.trim() : '.';
|
|
121
|
+
const assetsDirInput = (typeof options.assetsDir === 'string' && options.assetsDir.trim()) || '.vatts';
|
|
151
122
|
const assetsDirResolved = path.resolve(exportDirResolved, assetsDirInput);
|
|
152
123
|
const relAssetsToExport = path.relative(exportDirResolved, assetsDirResolved);
|
|
153
|
-
|
|
154
|
-
Console.error(`Invalid --assets-dir: must be inside output directory. Received: ${assetsDirInputRaw}`);
|
|
155
|
-
process.exit(1);
|
|
156
|
-
}
|
|
157
|
-
const assetsDirUrl = relAssetsToExport.split(path.sep).join('/').replace(/^\.?\/?/, '');
|
|
158
|
-
const assetsBaseHref = '/.' + (assetsDirUrl.length ? assetsDirUrl + '/' : '');
|
|
124
|
+
const assetsBaseHref = '/.' + (relAssetsToExport.split(path.sep).join('/').replace(/^\.?\/?/, '') || '');
|
|
159
125
|
Console.info('Starting export process...');
|
|
160
126
|
try {
|
|
161
|
-
|
|
127
|
+
let { loadVattsConfig, setConfig, config } = require("../helpers");
|
|
128
|
+
setConfig(await loadVattsConfig(projectDirResolved, 'production'));
|
|
162
129
|
if (fs.existsSync(exportDirResolved)) {
|
|
163
130
|
Console.info('Cleaning existing export folder...');
|
|
164
131
|
fs.rmSync(exportDirResolved, { recursive: true, force: true });
|
|
165
132
|
}
|
|
166
133
|
fs.mkdirSync(exportDirResolved, { recursive: true });
|
|
167
|
-
// 2. Build
|
|
168
134
|
Console.info('Building application...');
|
|
169
135
|
const helperModule = require("../helpers");
|
|
170
|
-
// Usando dev: false para produção
|
|
171
136
|
const app = helperModule.default({ dev: false, port: 3000, hostname: '0.0.0.0', framework: 'native' });
|
|
172
137
|
await app.prepare();
|
|
173
138
|
Console.success('Build complete.');
|
|
174
|
-
// 3. Copia JavaScript
|
|
175
139
|
const distDir = path.join(projectDirResolved, '.vatts');
|
|
176
140
|
if (fs.existsSync(distDir)) {
|
|
177
141
|
Console.info('Copying JavaScript files...');
|
|
178
|
-
|
|
179
|
-
copyDirRecursive(distDir, exportDistDir);
|
|
142
|
+
copyDirRecursive(distDir, assetsDirResolved);
|
|
180
143
|
}
|
|
181
|
-
// 4. Copia Public
|
|
182
144
|
const publicDir = path.join(projectDirResolved, 'public');
|
|
183
145
|
if (fs.existsSync(publicDir)) {
|
|
184
146
|
Console.info('Copying public files...');
|
|
185
147
|
copyDirRecursive(publicDir, exportDirResolved);
|
|
186
148
|
}
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
const shouldRenderHtml = Boolean(options.html) || shouldExtractHData;
|
|
149
|
+
const shouldExtractHData = !!options.outputHData;
|
|
150
|
+
const shouldRenderHtml = options.html !== false || shouldExtractHData;
|
|
190
151
|
if (shouldRenderHtml) {
|
|
191
|
-
const writeHtmlToDisk =
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
Console.info('Rendering HTML for h-data extraction...');
|
|
197
|
-
}
|
|
152
|
+
const writeHtmlToDisk = options.html !== false;
|
|
153
|
+
Console.info(writeHtmlToDisk ? 'Generating index.html...' : 'Rendering HTML for h-data extraction...');
|
|
154
|
+
const frameWork = detectFramework(projectDirResolved);
|
|
198
155
|
const { renderAsStream } = require('../renderer');
|
|
199
156
|
const { loadRoutes, loadLayout, loadNotFound } = require('../router');
|
|
200
157
|
const userWebDir = path.join(projectDirResolved, 'src', 'web');
|
|
201
158
|
const userWebRoutesDir = path.join(userWebDir, 'routes');
|
|
159
|
+
// Recarrega rotas para garantir estado limpo
|
|
202
160
|
const routes = loadRoutes(userWebRoutesDir);
|
|
203
161
|
loadLayout(userWebDir);
|
|
204
162
|
loadNotFound(userWebDir);
|
|
205
|
-
|
|
206
|
-
|
|
163
|
+
if (routes.length === 0) {
|
|
164
|
+
Console.warn('No routes found in src/web/routes. Skipping HTML generation.');
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
const rootRoute = routes.find(r => r.pattern === '/') || routes[0];
|
|
168
|
+
let htmlResult = '';
|
|
207
169
|
const mockReq = {
|
|
208
|
-
url: '/',
|
|
170
|
+
url: rootRoute.pattern || '/',
|
|
209
171
|
method: 'GET',
|
|
210
172
|
headers: { host: 'localhost' },
|
|
211
173
|
hwebDev: false,
|
|
212
174
|
hotReloadManager: null
|
|
213
175
|
};
|
|
214
|
-
let html = '';
|
|
215
|
-
let resolveStream;
|
|
216
|
-
const streamComplete = new Promise(r => resolveStream = r);
|
|
217
176
|
const mockRes = new Writable({
|
|
218
177
|
write(chunk, encoding, callback) {
|
|
219
|
-
|
|
178
|
+
htmlResult += chunk.toString();
|
|
220
179
|
callback();
|
|
221
180
|
}
|
|
222
181
|
});
|
|
182
|
+
// Extensão do mockRes para compatibilidade com o renderer
|
|
223
183
|
mockRes.setHeader = () => { };
|
|
184
|
+
mockRes.getHeader = () => { };
|
|
224
185
|
mockRes.statusCode = 200;
|
|
225
|
-
mockRes.
|
|
226
|
-
|
|
186
|
+
mockRes.end = (chunk) => {
|
|
187
|
+
if (chunk)
|
|
188
|
+
htmlResult += chunk.toString();
|
|
189
|
+
mockRes.emit('finish');
|
|
190
|
+
};
|
|
191
|
+
const streamComplete = new Promise((resolve, reject) => {
|
|
192
|
+
mockRes.on('finish', resolve);
|
|
193
|
+
mockRes.on('error', reject);
|
|
227
194
|
});
|
|
228
195
|
await renderAsStream({
|
|
229
196
|
req: mockReq,
|
|
@@ -234,23 +201,19 @@ program
|
|
|
234
201
|
});
|
|
235
202
|
await streamComplete;
|
|
236
203
|
if (shouldExtractHData) {
|
|
237
|
-
const m =
|
|
238
|
-
if (
|
|
239
|
-
|
|
204
|
+
const m = htmlResult.match(/data-h=["']([^"']*)["']/i);
|
|
205
|
+
if (m && m[1]) {
|
|
206
|
+
const outputHDataPath = path.resolve(projectDirResolved, options.outputHData.trim());
|
|
207
|
+
fs.mkdirSync(path.dirname(outputHDataPath), { recursive: true });
|
|
208
|
+
fs.writeFileSync(outputHDataPath, m[1], 'utf8');
|
|
209
|
+
Console.success(`h-data written to: ${path.relative(projectDirResolved, outputHDataPath)}`);
|
|
240
210
|
}
|
|
241
|
-
const hDataValue = m[1];
|
|
242
|
-
const outputHDataPathInput = options.outputHData.trim();
|
|
243
|
-
const outputHDataPath = path.isAbsolute(outputHDataPathInput)
|
|
244
|
-
? path.resolve(outputHDataPathInput)
|
|
245
|
-
: path.resolve(projectDirResolved, outputHDataPathInput);
|
|
246
|
-
fs.mkdirSync(path.dirname(outputHDataPath), { recursive: true });
|
|
247
|
-
fs.writeFileSync(outputHDataPath, hDataValue, 'utf8');
|
|
248
|
-
Console.success(`h-data written to: ${path.relative(projectDirResolved, outputHDataPath)}`);
|
|
249
211
|
}
|
|
250
212
|
if (writeHtmlToDisk) {
|
|
251
|
-
|
|
213
|
+
// Ajusta caminhos dos scripts para serem relativos ao assetsDir
|
|
214
|
+
const finalHtml = htmlResult.replace(/\/_vatts\//g, assetsBaseHref.endsWith('/') ? assetsBaseHref : assetsBaseHref + '/');
|
|
252
215
|
const indexPath = path.join(exportDirResolved, 'index.html');
|
|
253
|
-
fs.writeFileSync(indexPath,
|
|
216
|
+
fs.writeFileSync(indexPath, finalHtml, 'utf8');
|
|
254
217
|
Console.success('index.html generated.');
|
|
255
218
|
}
|
|
256
219
|
}
|