hightjs 0.3.2 → 0.3.4
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/factory.js +8 -8
- package/dist/adapters/native.js +3 -3
- package/dist/auth/client.js +5 -5
- package/dist/auth/components.js +2 -2
- package/dist/auth/core.js +2 -2
- package/dist/auth/react.js +4 -4
- package/dist/auth/routes.js +1 -1
- package/dist/bin/hightjs.js +29 -328
- package/dist/builder.js +47 -21
- package/dist/client/DefaultNotFound.js +1 -1
- package/dist/client/entry.client.js +3 -3
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.js +90 -28
- package/dist/hotReload.d.ts +3 -1
- package/dist/hotReload.js +43 -51
- package/dist/index.d.ts +1 -1
- package/dist/index.js +16 -30
- package/dist/router.js +133 -62
- package/dist/types.d.ts +42 -0
- package/docs/config.md +201 -0
- package/example/hightjs.config.ts +81 -0
- package/example/package-lock.json +633 -3054
- package/example/package.json +1 -1
- package/package.json +1 -1
- package/src/adapters/factory.ts +8 -8
- package/src/adapters/native.ts +3 -3
- package/src/auth/client.ts +5 -5
- package/src/auth/components.tsx +2 -2
- package/src/auth/core.ts +2 -2
- package/src/auth/react.tsx +4 -4
- package/src/auth/routes.ts +1 -1
- package/src/bin/hightjs.js +30 -391
- package/src/builder.js +47 -22
- package/src/client/DefaultNotFound.tsx +1 -1
- package/src/client/entry.client.tsx +3 -3
- package/src/helpers.ts +105 -29
- package/src/hotReload.ts +45 -55
- package/src/index.ts +20 -33
- package/src/router.ts +140 -63
- package/src/types.ts +52 -0
- package/example/.hweb/entry.client.js +0 -24
- package/example/hweb-dist/main-5KKAYNUU.js +0 -1137
package/dist/builder.js
CHANGED
|
@@ -82,7 +82,7 @@ const postcssPlugin = {
|
|
|
82
82
|
plugins.push(pluginModule(pluginOptions || {}));
|
|
83
83
|
}
|
|
84
84
|
catch (error) {
|
|
85
|
-
Console.warn(`
|
|
85
|
+
Console.warn(`Unable to load plugin ${pluginName}:`, error.message);
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
}
|
|
@@ -96,8 +96,8 @@ const postcssPlugin = {
|
|
|
96
96
|
processedCss = result.css;
|
|
97
97
|
}
|
|
98
98
|
catch (postcssError) {
|
|
99
|
-
Console.warn(`
|
|
100
|
-
Console.warn(`
|
|
99
|
+
Console.warn(`Error processing CSS with PostCSS:`, postcssError.message);
|
|
100
|
+
Console.warn(`Using raw CSS without processing.`);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
return {
|
|
@@ -185,9 +185,6 @@ const reactResolvePlugin = {
|
|
|
185
185
|
async function buildWithChunks(entryPoint, outdir, isProduction = false) {
|
|
186
186
|
// limpar diretorio
|
|
187
187
|
fs.rmSync(outdir, { recursive: true, force: true });
|
|
188
|
-
if (!isProduction) {
|
|
189
|
-
console.log(`Iniciando o build com chunks de \"${entryPoint}\"...`);
|
|
190
|
-
}
|
|
191
188
|
try {
|
|
192
189
|
await esbuild.build({
|
|
193
190
|
entryPoints: [entryPoint],
|
|
@@ -214,12 +211,9 @@ async function buildWithChunks(entryPoint, outdir, isProduction = false) {
|
|
|
214
211
|
keepNames: true,
|
|
215
212
|
treeShaking: true,
|
|
216
213
|
});
|
|
217
|
-
if (!isProduction) {
|
|
218
|
-
console.log(`Build com chunks finalizado! Saída: \"${outdir}\".`);
|
|
219
|
-
}
|
|
220
214
|
}
|
|
221
215
|
catch (error) {
|
|
222
|
-
console.error('
|
|
216
|
+
console.error('An error occurred while building:', error);
|
|
223
217
|
process.exit(1);
|
|
224
218
|
}
|
|
225
219
|
}
|
|
@@ -234,6 +228,25 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
|
|
|
234
228
|
// limpar diretorio
|
|
235
229
|
fs.rmSync(outdir, { recursive: true, force: true });
|
|
236
230
|
try {
|
|
231
|
+
// Plugin para notificar quando o build termina
|
|
232
|
+
const buildCompletePlugin = {
|
|
233
|
+
name: 'build-complete',
|
|
234
|
+
setup(build) {
|
|
235
|
+
let isFirstBuild = true;
|
|
236
|
+
build.onEnd((result) => {
|
|
237
|
+
if (hotReloadManager) {
|
|
238
|
+
if (isFirstBuild) {
|
|
239
|
+
isFirstBuild = false;
|
|
240
|
+
hotReloadManager.onBuildComplete(true);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
// Notifica o hot reload manager que o build foi concluído
|
|
244
|
+
hotReloadManager.onBuildComplete(result.errors.length === 0);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
};
|
|
237
250
|
const context = await esbuild.context({
|
|
238
251
|
entryPoints: [entryPoint],
|
|
239
252
|
bundle: true,
|
|
@@ -243,7 +256,7 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
|
|
|
243
256
|
outdir: outdir,
|
|
244
257
|
loader: { '.js': 'jsx', '.ts': 'tsx' },
|
|
245
258
|
external: nodeBuiltIns,
|
|
246
|
-
plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin],
|
|
259
|
+
plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, buildCompletePlugin],
|
|
247
260
|
format: 'esm',
|
|
248
261
|
jsx: 'automatic',
|
|
249
262
|
define: {
|
|
@@ -262,7 +275,7 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
|
|
|
262
275
|
}
|
|
263
276
|
catch (error) {
|
|
264
277
|
console.error(error);
|
|
265
|
-
Console.error('
|
|
278
|
+
Console.error('Error starting watch mode with chunks:', error);
|
|
266
279
|
throw error;
|
|
267
280
|
}
|
|
268
281
|
}
|
|
@@ -277,9 +290,6 @@ async function build(entryPoint, outfile, isProduction = false) {
|
|
|
277
290
|
// limpar diretorio do outfile
|
|
278
291
|
const outdir = path.dirname(outfile);
|
|
279
292
|
fs.rmSync(outdir, { recursive: true, force: true });
|
|
280
|
-
if (!isProduction) {
|
|
281
|
-
console.log(`Iniciando o build de \"${entryPoint}\"...`);
|
|
282
|
-
}
|
|
283
293
|
try {
|
|
284
294
|
await esbuild.build({
|
|
285
295
|
entryPoints: [entryPoint],
|
|
@@ -309,12 +319,9 @@ async function build(entryPoint, outfile, isProduction = false) {
|
|
|
309
319
|
treeShaking: true,
|
|
310
320
|
drop: [], // Não remove nada automaticamente
|
|
311
321
|
});
|
|
312
|
-
if (!isProduction) {
|
|
313
|
-
console.log(`Build finalizado com sucesso! Saída: \"${outfile}\".`);
|
|
314
|
-
}
|
|
315
322
|
}
|
|
316
323
|
catch (error) {
|
|
317
|
-
console.error('
|
|
324
|
+
console.error('An error occurred during build:', error);
|
|
318
325
|
process.exit(1);
|
|
319
326
|
}
|
|
320
327
|
}
|
|
@@ -327,6 +334,25 @@ async function build(entryPoint, outfile, isProduction = false) {
|
|
|
327
334
|
*/
|
|
328
335
|
async function watch(entryPoint, outfile, hotReloadManager = null) {
|
|
329
336
|
try {
|
|
337
|
+
// Plugin para notificar quando o build termina
|
|
338
|
+
const buildCompletePlugin = {
|
|
339
|
+
name: 'build-complete',
|
|
340
|
+
setup(build) {
|
|
341
|
+
let isFirstBuild = true;
|
|
342
|
+
build.onEnd((result) => {
|
|
343
|
+
if (hotReloadManager) {
|
|
344
|
+
if (isFirstBuild) {
|
|
345
|
+
isFirstBuild = false;
|
|
346
|
+
hotReloadManager.onBuildComplete(true);
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
// Notifica o hot reload manager que o build foi concluído
|
|
350
|
+
hotReloadManager.onBuildComplete(result.errors.length === 0);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
};
|
|
330
356
|
const context = await esbuild.context({
|
|
331
357
|
entryPoints: [entryPoint],
|
|
332
358
|
bundle: true,
|
|
@@ -336,7 +362,7 @@ async function watch(entryPoint, outfile, hotReloadManager = null) {
|
|
|
336
362
|
outfile: outfile,
|
|
337
363
|
loader: { '.js': 'jsx', '.ts': 'tsx' },
|
|
338
364
|
external: nodeBuiltIns,
|
|
339
|
-
plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin],
|
|
365
|
+
plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, buildCompletePlugin],
|
|
340
366
|
format: 'iife',
|
|
341
367
|
globalName: 'HwebApp',
|
|
342
368
|
jsx: 'automatic',
|
|
@@ -358,7 +384,7 @@ async function watch(entryPoint, outfile, hotReloadManager = null) {
|
|
|
358
384
|
await context.watch();
|
|
359
385
|
}
|
|
360
386
|
catch (error) {
|
|
361
|
-
Console.error('
|
|
387
|
+
Console.error('Error starting watch mode:', error);
|
|
362
388
|
throw error;
|
|
363
389
|
}
|
|
364
390
|
}
|
|
@@ -265,7 +265,7 @@ function DevIndicator() {
|
|
|
265
265
|
function initializeClient() {
|
|
266
266
|
const initialData = window.__HWEB_INITIAL_DATA__;
|
|
267
267
|
if (!initialData) {
|
|
268
|
-
console.error('[hweb]
|
|
268
|
+
console.error('[hweb] Initial data not found on page.');
|
|
269
269
|
return;
|
|
270
270
|
}
|
|
271
271
|
// Cria o mapa de componentes dinamicamente a partir dos módulos carregados
|
|
@@ -276,7 +276,7 @@ function initializeClient() {
|
|
|
276
276
|
}
|
|
277
277
|
const container = document.getElementById('root');
|
|
278
278
|
if (!container) {
|
|
279
|
-
console.error('[hweb] Container #root
|
|
279
|
+
console.error('[hweb] Container #root not found.');
|
|
280
280
|
return;
|
|
281
281
|
}
|
|
282
282
|
try {
|
|
@@ -285,7 +285,7 @@ function initializeClient() {
|
|
|
285
285
|
root.render((0, jsx_runtime_1.jsx)(App, { componentMap: componentMap, routes: initialData.routes, initialComponentPath: initialData.initialComponentPath, initialParams: initialData.initialParams, layoutComponent: window.__HWEB_LAYOUT__ }));
|
|
286
286
|
}
|
|
287
287
|
catch (error) {
|
|
288
|
-
console.error('[hweb]
|
|
288
|
+
console.error('[hweb] Error rendering application:', error);
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
291
|
// Executa quando o DOM estiver pronto
|
package/dist/helpers.d.ts
CHANGED
package/dist/helpers.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
"use strict";
|
|
2
3
|
/*
|
|
3
4
|
* This file is part of the HightJS Project.
|
|
@@ -57,6 +58,7 @@ exports.app = app;
|
|
|
57
58
|
const http_1 = __importDefault(require("http"));
|
|
58
59
|
const os_1 = __importDefault(require("os"));
|
|
59
60
|
const url_1 = require("url"); // API moderna, substitui 'querystring'
|
|
61
|
+
const path_1 = __importDefault(require("path"));
|
|
60
62
|
// Helpers para integração com diferentes frameworks
|
|
61
63
|
const index_1 = __importStar(require("./index")); // Importando o tipo
|
|
62
64
|
const console_1 = __importStar(require("./api/console"));
|
|
@@ -81,28 +83,85 @@ function getLocalExternalIp() {
|
|
|
81
83
|
return 'localhost'; // Fallback
|
|
82
84
|
}
|
|
83
85
|
const sendBox = (options) => {
|
|
84
|
-
const isDev = options.dev ? "
|
|
86
|
+
const isDev = options.dev ? "Running in development mode" : null;
|
|
85
87
|
// 1. Verifica se o SSL está ativado (baseado na mesma lógica do initNativeServer)
|
|
86
88
|
const isSSL = options.ssl && options.ssl.key && options.ssl.cert;
|
|
87
89
|
const protocol = isSSL ? 'https' : 'http';
|
|
88
90
|
const localIp = getLocalExternalIp(); // Assume que getLocalExternalIp() existe
|
|
89
91
|
// 2. Monta as mensagens com o protocolo correto
|
|
90
92
|
const messages = [
|
|
91
|
-
` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} Local:
|
|
93
|
+
` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} Local: ${console_1.Colors.FgGreen}${protocol}://localhost:${options.port}${console_1.Colors.Reset}`,
|
|
92
94
|
];
|
|
93
95
|
// Só adiciona a rede se o IP local for encontrado
|
|
94
96
|
if (localIp) {
|
|
95
|
-
messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset}
|
|
97
|
+
messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} Network: ${console_1.Colors.FgGreen}${protocol}://${localIp}:${options.port}${console_1.Colors.Reset}`);
|
|
96
98
|
}
|
|
97
99
|
if (isDev) {
|
|
98
100
|
messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} ${isDev}`);
|
|
99
101
|
}
|
|
100
102
|
// Adiciona aviso de redirecionamento se estiver em modo SSL
|
|
101
103
|
if (isSSL && options.ssl?.redirectPort) {
|
|
102
|
-
messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} HTTP (
|
|
104
|
+
messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} HTTP (port ${options.ssl?.redirectPort}) is redirecting to HTTPS.`);
|
|
103
105
|
}
|
|
104
|
-
console_1.default.box(messages.join("\n"), { title: "
|
|
106
|
+
console_1.default.box(messages.join("\n"), { title: "Access on:" });
|
|
105
107
|
};
|
|
108
|
+
/**
|
|
109
|
+
* Carrega o arquivo de configuração hightjs.config.ts ou hightjs.config.js do projeto
|
|
110
|
+
* @param projectDir Diretório raiz do projeto
|
|
111
|
+
* @param phase Fase de execução ('development' ou 'production')
|
|
112
|
+
* @returns Configuração mesclada com os valores padrão
|
|
113
|
+
*/
|
|
114
|
+
async function loadHightConfig(projectDir, phase) {
|
|
115
|
+
const defaultConfig = {
|
|
116
|
+
maxHeadersCount: 100,
|
|
117
|
+
headersTimeout: 60000,
|
|
118
|
+
requestTimeout: 30000,
|
|
119
|
+
serverTimeout: 35000,
|
|
120
|
+
individualRequestTimeout: 30000,
|
|
121
|
+
maxUrlLength: 2048,
|
|
122
|
+
};
|
|
123
|
+
try {
|
|
124
|
+
// Tenta primeiro .ts, depois .js
|
|
125
|
+
const possiblePaths = [
|
|
126
|
+
path_1.default.join(projectDir, 'hightjs.config.ts'),
|
|
127
|
+
path_1.default.join(projectDir, 'hightjs.config.js'),
|
|
128
|
+
];
|
|
129
|
+
let configPath = null;
|
|
130
|
+
for (const p of possiblePaths) {
|
|
131
|
+
if (fs_1.default.existsSync(p)) {
|
|
132
|
+
configPath = p;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (!configPath) {
|
|
137
|
+
return defaultConfig;
|
|
138
|
+
}
|
|
139
|
+
// Remove do cache para permitir hot reload da configuração em dev
|
|
140
|
+
delete require.cache[require.resolve(configPath)];
|
|
141
|
+
const configModule = require(configPath);
|
|
142
|
+
const configExport = configModule.default || configModule;
|
|
143
|
+
let userConfig;
|
|
144
|
+
if (typeof configExport === 'function') {
|
|
145
|
+
// Suporta tanto função síncrona quanto assíncrona
|
|
146
|
+
userConfig = await Promise.resolve(configExport(phase, { defaultConfig }));
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
userConfig = configExport;
|
|
150
|
+
}
|
|
151
|
+
// Mescla a configuração do usuário com a padrão
|
|
152
|
+
const mergedConfig = { ...defaultConfig, ...userConfig };
|
|
153
|
+
const configFileName = path_1.default.basename(configPath);
|
|
154
|
+
console_1.default.info(`${console_1.Colors.FgCyan}[Config]${console_1.Colors.Reset} Loaded ${configFileName}`);
|
|
155
|
+
return mergedConfig;
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
if (error instanceof Error) {
|
|
159
|
+
console_1.default.warn(`${console_1.Colors.FgYellow}[Config]${console_1.Colors.Reset} Error loading hightjs.config: ${error.message}`);
|
|
160
|
+
console_1.default.warn(`${console_1.Colors.FgYellow}[Config]${console_1.Colors.Reset} Using default configuration`);
|
|
161
|
+
}
|
|
162
|
+
return defaultConfig;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
106
165
|
/**
|
|
107
166
|
* Middleware para parsing do body com proteções de segurança (versão melhorada).
|
|
108
167
|
* Rejeita a promise em caso de erro de parsing ou estouro de limite.
|
|
@@ -181,8 +240,12 @@ const parseBody = (req) => {
|
|
|
181
240
|
async function initNativeServer(hwebApp, options, port, hostname) {
|
|
182
241
|
const time = Date.now();
|
|
183
242
|
await hwebApp.prepare();
|
|
243
|
+
// Carrega a configuração do arquivo hightjs.config.js
|
|
244
|
+
const projectDir = options.dir || process.cwd();
|
|
245
|
+
const phase = options.dev ? 'development' : 'production';
|
|
246
|
+
const hightConfig = await loadHightConfig(projectDir, phase);
|
|
184
247
|
const handler = hwebApp.getRequestHandler();
|
|
185
|
-
const msg = console_1.default.dynamicLine(` ${console_1.Colors.BgYellow} ready ${console_1.Colors.Reset} ${console_1.Colors.Bright}
|
|
248
|
+
const msg = console_1.default.dynamicLine(` ${console_1.Colors.BgYellow} ready ${console_1.Colors.Reset} ${console_1.Colors.Bright}Starting HightJS on port ${options.port}${console_1.Colors.Reset}`);
|
|
186
249
|
// --- LÓGICA DO LISTENER (REUTILIZÁVEL) ---
|
|
187
250
|
// Extraímos a lógica principal para uma variável
|
|
188
251
|
// para que possa ser usada tanto pelo servidor HTTP quanto HTTPS.
|
|
@@ -197,15 +260,16 @@ async function initNativeServer(hwebApp, options, port, hostname) {
|
|
|
197
260
|
if (options.ssl) {
|
|
198
261
|
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
|
|
199
262
|
}
|
|
200
|
-
// Timeout por requisição
|
|
201
|
-
req.setTimeout(30000, () => {
|
|
263
|
+
// Timeout por requisição (usa configuração personalizada)
|
|
264
|
+
req.setTimeout(hightConfig.individualRequestTimeout || 30000, () => {
|
|
202
265
|
res.statusCode = 408; // Request Timeout
|
|
203
266
|
res.end('Request timeout');
|
|
204
267
|
});
|
|
205
268
|
try {
|
|
206
|
-
// Validação básica de URL
|
|
269
|
+
// Validação básica de URL (usa configuração personalizada)
|
|
207
270
|
const url = req.url || '/';
|
|
208
|
-
|
|
271
|
+
const maxUrlLength = hightConfig.maxUrlLength || 2048;
|
|
272
|
+
if (url.length > maxUrlLength) {
|
|
209
273
|
res.statusCode = 414; // URI Too Long
|
|
210
274
|
res.end('URL too long');
|
|
211
275
|
return;
|
|
@@ -220,10 +284,10 @@ async function initNativeServer(hwebApp, options, port, hostname) {
|
|
|
220
284
|
catch (error) {
|
|
221
285
|
// Log do erro no servidor
|
|
222
286
|
if (error instanceof Error) {
|
|
223
|
-
console_1.default.error(`
|
|
287
|
+
console_1.default.error(`Native server error: ${error.message}`);
|
|
224
288
|
}
|
|
225
289
|
else {
|
|
226
|
-
console_1.default.error('
|
|
290
|
+
console_1.default.error('Unknown native server error:', error);
|
|
227
291
|
}
|
|
228
292
|
// Tratamento de erro (idêntico ao seu original)
|
|
229
293
|
if (!res.headersSent) {
|
|
@@ -286,14 +350,14 @@ async function initNativeServer(hwebApp, options, port, hostname) {
|
|
|
286
350
|
// Cria o servidor HTTP nativo
|
|
287
351
|
server = http_1.default.createServer(requestListener); // (any para contornar HWebIncomingMessage)
|
|
288
352
|
}
|
|
289
|
-
// Configurações de segurança do servidor (
|
|
290
|
-
server.setTimeout(35000); // Timeout geral do servidor
|
|
291
|
-
server.maxHeadersCount = 100; // Limita número de headers
|
|
292
|
-
server.headersTimeout = 60000; // Timeout para headers
|
|
293
|
-
server.requestTimeout = 30000; // Timeout para requisições
|
|
353
|
+
// Configurações de segurança do servidor (usa configuração personalizada)
|
|
354
|
+
server.setTimeout(hightConfig.serverTimeout || 35000); // Timeout geral do servidor
|
|
355
|
+
server.maxHeadersCount = hightConfig.maxHeadersCount || 100; // Limita número de headers
|
|
356
|
+
server.headersTimeout = hightConfig.headersTimeout || 60000; // Timeout para headers
|
|
357
|
+
server.requestTimeout = hightConfig.requestTimeout || 30000; // Timeout para requisições
|
|
294
358
|
server.listen(port, hostname, () => {
|
|
295
359
|
sendBox({ ...options, port });
|
|
296
|
-
msg.end(` ${console_1.Colors.BgGreen} ready ${console_1.Colors.Reset} ${console_1.Colors.Bright}
|
|
360
|
+
msg.end(` ${console_1.Colors.BgGreen} ready ${console_1.Colors.Reset} ${console_1.Colors.Bright}Ready on port ${console_1.Colors.BgGreen} ${options.port} ${console_1.Colors.Reset}${console_1.Colors.Bright} in ${Date.now() - time}ms${console_1.Colors.Reset}\n`);
|
|
297
361
|
});
|
|
298
362
|
// Configura WebSocket para hot reload (Comum a ambos)
|
|
299
363
|
hwebApp.setupWebSocket(server);
|
|
@@ -325,7 +389,7 @@ function app(options = {}) {
|
|
|
325
389
|
serverApp.use(cookieParser());
|
|
326
390
|
}
|
|
327
391
|
catch (e) {
|
|
328
|
-
console_1.default.error("
|
|
392
|
+
console_1.default.error("Could not find cookie-parser");
|
|
329
393
|
}
|
|
330
394
|
serverApp.use(express.json());
|
|
331
395
|
serverApp.use(express.urlencoded({ extended: true }));
|
|
@@ -337,13 +401,13 @@ function app(options = {}) {
|
|
|
337
401
|
await serverApp.register(require('@fastify/cookie'));
|
|
338
402
|
}
|
|
339
403
|
catch (e) {
|
|
340
|
-
console_1.default.error("
|
|
404
|
+
console_1.default.error("Could not find @fastify/cookie");
|
|
341
405
|
}
|
|
342
406
|
try {
|
|
343
407
|
await serverApp.register(require('@fastify/formbody'));
|
|
344
408
|
}
|
|
345
409
|
catch (e) {
|
|
346
|
-
console_1.default.error("
|
|
410
|
+
console_1.default.error("Could not find @fastify/formbody");
|
|
347
411
|
}
|
|
348
412
|
await serverApp.register(async (fastify) => {
|
|
349
413
|
fastify.all('*', handler);
|
|
@@ -371,7 +435,7 @@ function app(options = {}) {
|
|
|
371
435
|
return data.version;
|
|
372
436
|
}
|
|
373
437
|
catch (error) {
|
|
374
|
-
console_1.default.error('
|
|
438
|
+
console_1.default.error('Could not check for the latest HightJS version:', error);
|
|
375
439
|
return currentVersion; // Retorna a versão atual em caso de erro
|
|
376
440
|
}
|
|
377
441
|
}
|
|
@@ -379,22 +443,20 @@ function app(options = {}) {
|
|
|
379
443
|
const isUpToDate = latestVersion === currentVersion;
|
|
380
444
|
let message;
|
|
381
445
|
if (!isUpToDate) {
|
|
382
|
-
message = `${console_1.Colors.FgGreen}
|
|
446
|
+
message = `${console_1.Colors.FgGreen} A new version is available (v${latestVersion})${console_1.Colors.FgMagenta}`;
|
|
383
447
|
}
|
|
384
448
|
else {
|
|
385
|
-
message = `${console_1.Colors.FgGreen}
|
|
449
|
+
message = `${console_1.Colors.FgGreen} You are on the latest version${console_1.Colors.FgMagenta}`;
|
|
386
450
|
}
|
|
387
451
|
console.log(`${console_1.Colors.FgMagenta}
|
|
388
452
|
__ ___ ${console_1.Colors.FgGreen} __ ${console_1.Colors.FgMagenta}
|
|
389
453
|
|__| | / _\` |__| | ${console_1.Colors.FgGreen} | /__\` ${console_1.Colors.FgMagenta} ${console_1.Colors.FgMagenta}HightJS ${console_1.Colors.FgGray}(v${require('../package.json').version}) - itsmuzin${console_1.Colors.FgMagenta}
|
|
390
|
-
| | | \\__> | | | ${console_1.Colors.FgGreen}\\__/ .__/ ${message}
|
|
391
|
-
|
|
392
|
-
|
|
454
|
+
| | | \\__> | | | ${console_1.Colors.FgGreen}\\__/ .__/ ${message}
|
|
393
455
|
${console_1.Colors.Reset}`);
|
|
394
456
|
const actualPort = options.port || 3000;
|
|
395
457
|
const actualHostname = options.hostname || "0.0.0.0";
|
|
396
458
|
if (framework !== 'native') {
|
|
397
|
-
console_1.default.warn(`
|
|
459
|
+
console_1.default.warn(`The "${framework}" framework was selected, but the init() method only works with the "native" framework. Starting native server...`);
|
|
398
460
|
}
|
|
399
461
|
return await initNativeServer(hwebApp, options, actualPort, actualHostname);
|
|
400
462
|
}
|
package/dist/hotReload.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export declare class HotReloadManager {
|
|
|
9
9
|
private isShuttingDown;
|
|
10
10
|
private debounceTimers;
|
|
11
11
|
private customHotReloadListener;
|
|
12
|
+
private isBuilding;
|
|
13
|
+
private buildCompleteResolve;
|
|
12
14
|
constructor(projectDir: string);
|
|
13
15
|
start(): Promise<void>;
|
|
14
16
|
handleUpgrade(request: IncomingMessage, socket: any, head: Buffer): void;
|
|
@@ -26,5 +28,5 @@ export declare class HotReloadManager {
|
|
|
26
28
|
onFrontendChange(callback: () => void): void;
|
|
27
29
|
setHotReloadListener(listener: (file: string) => Promise<void> | void): void;
|
|
28
30
|
removeHotReloadListener(): void;
|
|
29
|
-
|
|
31
|
+
onBuildComplete(success: boolean): void;
|
|
30
32
|
}
|
package/dist/hotReload.js
CHANGED
|
@@ -65,6 +65,8 @@ class HotReloadManager {
|
|
|
65
65
|
this.isShuttingDown = false;
|
|
66
66
|
this.debounceTimers = new Map();
|
|
67
67
|
this.customHotReloadListener = null;
|
|
68
|
+
this.isBuilding = false;
|
|
69
|
+
this.buildCompleteResolve = null;
|
|
68
70
|
this.projectDir = projectDir;
|
|
69
71
|
}
|
|
70
72
|
async start() {
|
|
@@ -198,30 +200,44 @@ class HotReloadManager {
|
|
|
198
200
|
// Limpa o cache do arquivo alterado
|
|
199
201
|
(0, router_1.clearFileCache)(filePath);
|
|
200
202
|
this.clearBackendCache(filePath);
|
|
201
|
-
//
|
|
202
|
-
const ext = path.extname(filePath);
|
|
203
|
-
if ([".ts", ".tsx", ".js", ".jsx"].includes(ext)) {
|
|
204
|
-
const result = await this.checkFrontendBuild(filePath);
|
|
205
|
-
if (result.error) {
|
|
206
|
-
this.notifyClients('src-error', { file: filePath, error: result.error });
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
// Se for arquivo de frontend, notifica o cliente para recarregar a página
|
|
203
|
+
// Se for arquivo de frontend, aguarda o build terminar antes de recarregar
|
|
211
204
|
if (isFrontendFile) {
|
|
212
|
-
console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `📄
|
|
213
|
-
|
|
214
|
-
this.
|
|
205
|
+
console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `📄 Waiting for frontend build...`);
|
|
206
|
+
// Marca que estamos esperando um build
|
|
207
|
+
this.isBuilding = true;
|
|
208
|
+
// Cria uma promise que será resolvida quando o build terminar
|
|
209
|
+
const buildPromise = new Promise((resolve) => {
|
|
210
|
+
this.buildCompleteResolve = resolve;
|
|
211
|
+
});
|
|
212
|
+
// Aguarda o build terminar (com timeout de 30 segundos)
|
|
213
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
214
|
+
setTimeout(() => reject(new Error('Build timeout')), 30000);
|
|
215
|
+
});
|
|
216
|
+
try {
|
|
217
|
+
await Promise.race([buildPromise, timeoutPromise]);
|
|
218
|
+
console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `✅ Build complete, reloading frontend...`);
|
|
219
|
+
this.frontendChangeCallback?.();
|
|
220
|
+
this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
console_1.default.logWithout(console_1.Levels.ERROR, console_1.Colors.BgRed, `⚠️ Timeout in build, reloading anyway...`);
|
|
224
|
+
this.frontendChangeCallback?.();
|
|
225
|
+
this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
this.isBuilding = false;
|
|
229
|
+
this.buildCompleteResolve = null;
|
|
230
|
+
}
|
|
215
231
|
}
|
|
216
232
|
// Se for arquivo de backend, recarrega o módulo e notifica
|
|
217
233
|
if (isBackendFile) {
|
|
218
|
-
console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `⚙️
|
|
234
|
+
console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `⚙️ Reloading backend...`);
|
|
219
235
|
this.backendApiChangeCallback?.();
|
|
220
236
|
this.notifyClients('backend-api-reload', { file: filePath, event: 'change' });
|
|
221
237
|
}
|
|
222
238
|
// Fallback: se não for nem frontend nem backend detectado, recarrega tudo
|
|
223
239
|
if (!isFrontendFile && !isBackendFile) {
|
|
224
|
-
console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `🔄
|
|
240
|
+
console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `🔄 Reloading application...`);
|
|
225
241
|
this.frontendChangeCallback?.();
|
|
226
242
|
this.backendApiChangeCallback?.();
|
|
227
243
|
this.notifyClients('src-reload', { file: filePath, event: 'change' });
|
|
@@ -233,7 +249,7 @@ class HotReloadManager {
|
|
|
233
249
|
}
|
|
234
250
|
catch (error) {
|
|
235
251
|
// @ts-ignore
|
|
236
|
-
console_1.default.logWithout(console_1.Levels.ERROR, `
|
|
252
|
+
console_1.default.logWithout(console_1.Levels.ERROR, `Error in custom listener: ${error.message}`);
|
|
237
253
|
}
|
|
238
254
|
}
|
|
239
255
|
}
|
|
@@ -249,7 +265,7 @@ class HotReloadManager {
|
|
|
249
265
|
ws.send(message);
|
|
250
266
|
}
|
|
251
267
|
catch (error) {
|
|
252
|
-
console_1.default.logWithout(console_1.Levels.ERROR, console_1.Colors.BgRed, `
|
|
268
|
+
console_1.default.logWithout(console_1.Levels.ERROR, console_1.Colors.BgRed, `Error sending WebSocket message: ${error}`);
|
|
253
269
|
deadClients.push(ws);
|
|
254
270
|
}
|
|
255
271
|
}
|
|
@@ -311,7 +327,7 @@ class HotReloadManager {
|
|
|
311
327
|
ws = new WebSocket('ws://localhost:3000/hweb-hotreload/');
|
|
312
328
|
|
|
313
329
|
ws.onopen = function() {
|
|
314
|
-
console.log('🔌 Hot-reload
|
|
330
|
+
console.log('🔌 Hot-reload connected');
|
|
315
331
|
isConnected = true;
|
|
316
332
|
reconnectAttempts = 0;
|
|
317
333
|
reconnectInterval = 1000;
|
|
@@ -331,13 +347,13 @@ class HotReloadManager {
|
|
|
331
347
|
window.location.reload();
|
|
332
348
|
break;
|
|
333
349
|
case 'server-restart':
|
|
334
|
-
console.log('🔄
|
|
350
|
+
console.log('🔄 Server restarting...');
|
|
335
351
|
break;
|
|
336
352
|
case 'server-ready':
|
|
337
353
|
setTimeout(() => window.location.reload(), 500);
|
|
338
354
|
break;
|
|
339
355
|
case 'frontend-error':
|
|
340
|
-
console.error('❌
|
|
356
|
+
console.error('❌ Frontend error:', message.data);
|
|
341
357
|
break;
|
|
342
358
|
}
|
|
343
359
|
} catch (e) {
|
|
@@ -362,7 +378,7 @@ class HotReloadManager {
|
|
|
362
378
|
};
|
|
363
379
|
|
|
364
380
|
} catch (error) {
|
|
365
|
-
console.error('
|
|
381
|
+
console.error('Error creating WebSocket:', error);
|
|
366
382
|
scheduleReconnect();
|
|
367
383
|
}
|
|
368
384
|
}
|
|
@@ -427,41 +443,17 @@ class HotReloadManager {
|
|
|
427
443
|
}
|
|
428
444
|
setHotReloadListener(listener) {
|
|
429
445
|
this.customHotReloadListener = listener;
|
|
430
|
-
console_1.default.info('🔌 Hot reload listener
|
|
446
|
+
console_1.default.info('🔌 Hot reload custom listener registered');
|
|
431
447
|
}
|
|
432
448
|
removeHotReloadListener() {
|
|
433
449
|
this.customHotReloadListener = null;
|
|
434
450
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
return new Promise((resolve) => {
|
|
440
|
-
const proc = spawn(process.execPath, [tsNodePath, '--transpile-only', filePath], {
|
|
441
|
-
cwd: this.projectDir,
|
|
442
|
-
env: process.env,
|
|
443
|
-
timeout: 10000 // Timeout de 10 segundos
|
|
444
|
-
});
|
|
445
|
-
let errorMsg = '';
|
|
446
|
-
proc.stderr.on('data', (data) => {
|
|
447
|
-
errorMsg += data.toString();
|
|
448
|
-
});
|
|
449
|
-
proc.on('close', (code) => {
|
|
450
|
-
if (code !== 0 && errorMsg) {
|
|
451
|
-
resolve({ error: errorMsg });
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
resolve({});
|
|
455
|
-
}
|
|
456
|
-
});
|
|
457
|
-
proc.on('error', (error) => {
|
|
458
|
-
resolve({ error: error.message });
|
|
459
|
-
});
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
catch (error) {
|
|
463
|
-
return { error: `Erro ao verificar build: ${error}` };
|
|
451
|
+
onBuildComplete(success) {
|
|
452
|
+
if (this.buildCompleteResolve) {
|
|
453
|
+
this.buildCompleteResolve();
|
|
454
|
+
this.buildCompleteResolve = null;
|
|
464
455
|
}
|
|
456
|
+
this.isBuilding = false;
|
|
465
457
|
}
|
|
466
458
|
}
|
|
467
459
|
exports.HotReloadManager = HotReloadManager;
|
package/dist/index.d.ts
CHANGED
|
@@ -8,11 +8,11 @@ export { FrameworkAdapterFactory } from './adapters/factory';
|
|
|
8
8
|
export type { GenericRequest, GenericResponse, CookieOptions } from './types/framework';
|
|
9
9
|
export { app } from './helpers';
|
|
10
10
|
export type { WebSocketContext, WebSocketHandler } from './types';
|
|
11
|
+
export type { HightConfig, HightConfigFunction } from './types';
|
|
11
12
|
export default function hweb(options: HightJSOptions): {
|
|
12
13
|
prepare: () => Promise<void>;
|
|
13
14
|
executeInstrumentation: () => void;
|
|
14
15
|
getRequestHandler: () => RequestHandler;
|
|
15
16
|
setupWebSocket: (server: any) => void;
|
|
16
|
-
build: () => Promise<void>;
|
|
17
17
|
stop: () => void;
|
|
18
18
|
};
|