hightjs 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/builder.js CHANGED
@@ -234,6 +234,25 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
234
234
  // limpar diretorio
235
235
  fs.rmSync(outdir, { recursive: true, force: true });
236
236
  try {
237
+ // Plugin para notificar quando o build termina
238
+ const buildCompletePlugin = {
239
+ name: 'build-complete',
240
+ setup(build) {
241
+ let isFirstBuild = true;
242
+ build.onEnd((result) => {
243
+ if (hotReloadManager) {
244
+ if (isFirstBuild) {
245
+ isFirstBuild = false;
246
+ hotReloadManager.onBuildComplete(true);
247
+ }
248
+ else {
249
+ // Notifica o hot reload manager que o build foi concluído
250
+ hotReloadManager.onBuildComplete(result.errors.length === 0);
251
+ }
252
+ }
253
+ });
254
+ }
255
+ };
237
256
  const context = await esbuild.context({
238
257
  entryPoints: [entryPoint],
239
258
  bundle: true,
@@ -243,7 +262,7 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
243
262
  outdir: outdir,
244
263
  loader: { '.js': 'jsx', '.ts': 'tsx' },
245
264
  external: nodeBuiltIns,
246
- plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin],
265
+ plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, buildCompletePlugin],
247
266
  format: 'esm',
248
267
  jsx: 'automatic',
249
268
  define: {
@@ -327,6 +346,25 @@ async function build(entryPoint, outfile, isProduction = false) {
327
346
  */
328
347
  async function watch(entryPoint, outfile, hotReloadManager = null) {
329
348
  try {
349
+ // Plugin para notificar quando o build termina
350
+ const buildCompletePlugin = {
351
+ name: 'build-complete',
352
+ setup(build) {
353
+ let isFirstBuild = true;
354
+ build.onEnd((result) => {
355
+ if (hotReloadManager) {
356
+ if (isFirstBuild) {
357
+ isFirstBuild = false;
358
+ hotReloadManager.onBuildComplete(true);
359
+ }
360
+ else {
361
+ // Notifica o hot reload manager que o build foi concluído
362
+ hotReloadManager.onBuildComplete(result.errors.length === 0);
363
+ }
364
+ }
365
+ });
366
+ }
367
+ };
330
368
  const context = await esbuild.context({
331
369
  entryPoints: [entryPoint],
332
370
  bundle: true,
@@ -336,7 +374,7 @@ async function watch(entryPoint, outfile, hotReloadManager = null) {
336
374
  outfile: outfile,
337
375
  loader: { '.js': 'jsx', '.ts': 'tsx' },
338
376
  external: nodeBuiltIns,
339
- plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin],
377
+ plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, buildCompletePlugin],
340
378
  format: 'iife',
341
379
  globalName: 'HwebApp',
342
380
  jsx: 'automatic',
@@ -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
- private checkFrontendBuild;
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,20 +200,34 @@ class HotReloadManager {
198
200
  // Limpa o cache do arquivo alterado
199
201
  (0, router_1.clearFileCache)(filePath);
200
202
  this.clearBackendCache(filePath);
201
- // Checa build se for .ts/.tsx/.js/.jsx
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, `📄 Recarregando frontend...`);
213
- this.frontendChangeCallback?.();
214
- this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
205
+ console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `📄 Aguardando build do frontend...`);
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 concluído, recarregando 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 no build, recarregando mesmo assim...`);
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) {
@@ -432,36 +448,12 @@ class HotReloadManager {
432
448
  removeHotReloadListener() {
433
449
  this.customHotReloadListener = null;
434
450
  }
435
- async checkFrontendBuild(filePath) {
436
- try {
437
- const tsNodePath = require.resolve('ts-node');
438
- const { spawn } = require('child_process');
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hightjs",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "HightJS 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
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/builder.js CHANGED
@@ -251,6 +251,25 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
251
251
  // limpar diretorio
252
252
  fs.rmSync(outdir, { recursive: true, force: true });
253
253
  try {
254
+ // Plugin para notificar quando o build termina
255
+ const buildCompletePlugin = {
256
+ name: 'build-complete',
257
+ setup(build) {
258
+ let isFirstBuild = true;
259
+ build.onEnd((result) => {
260
+ if (hotReloadManager) {
261
+ if (isFirstBuild) {
262
+ isFirstBuild = false;
263
+ hotReloadManager.onBuildComplete(true);
264
+ } else {
265
+ // Notifica o hot reload manager que o build foi concluído
266
+ hotReloadManager.onBuildComplete(result.errors.length === 0);
267
+ }
268
+ }
269
+ });
270
+ }
271
+ };
272
+
254
273
  const context = await esbuild.context({
255
274
  entryPoints: [entryPoint],
256
275
  bundle: true,
@@ -260,7 +279,7 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
260
279
  outdir: outdir,
261
280
  loader: { '.js': 'jsx', '.ts': 'tsx' },
262
281
  external: nodeBuiltIns,
263
- plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin],
282
+ plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, buildCompletePlugin],
264
283
  format: 'esm',
265
284
  jsx: 'automatic',
266
285
  define: {
@@ -347,6 +366,25 @@ async function build(entryPoint, outfile, isProduction = false) {
347
366
  */
348
367
  async function watch(entryPoint, outfile, hotReloadManager = null) {
349
368
  try {
369
+ // Plugin para notificar quando o build termina
370
+ const buildCompletePlugin = {
371
+ name: 'build-complete',
372
+ setup(build) {
373
+ let isFirstBuild = true;
374
+ build.onEnd((result) => {
375
+ if (hotReloadManager) {
376
+ if (isFirstBuild) {
377
+ isFirstBuild = false;
378
+ hotReloadManager.onBuildComplete(true);
379
+ } else {
380
+ // Notifica o hot reload manager que o build foi concluído
381
+ hotReloadManager.onBuildComplete(result.errors.length === 0);
382
+ }
383
+ }
384
+ });
385
+ }
386
+ };
387
+
350
388
  const context = await esbuild.context({
351
389
  entryPoints: [entryPoint],
352
390
  bundle: true,
@@ -356,7 +394,7 @@ async function watch(entryPoint, outfile, hotReloadManager = null) {
356
394
  outfile: outfile,
357
395
  loader: { '.js': 'jsx', '.ts': 'tsx' },
358
396
  external: nodeBuiltIns,
359
- plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin],
397
+ plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, buildCompletePlugin],
360
398
  format: 'iife',
361
399
  globalName: 'HwebApp',
362
400
  jsx: 'automatic',
package/src/hotReload.ts CHANGED
@@ -39,6 +39,8 @@ export class HotReloadManager {
39
39
  private isShuttingDown: boolean = false;
40
40
  private debounceTimers: Map<string, NodeJS.Timeout> = new Map();
41
41
  private customHotReloadListener: ((file: string) => Promise<void> | void) | null = null;
42
+ private isBuilding: boolean = false;
43
+ private buildCompleteResolve: (() => void) | null = null;
42
44
 
43
45
  constructor(projectDir: string) {
44
46
  this.projectDir = projectDir;
@@ -200,21 +202,36 @@ export class HotReloadManager {
200
202
  clearFileCache(filePath);
201
203
  this.clearBackendCache(filePath);
202
204
 
203
- // Checa build se for .ts/.tsx/.js/.jsx
204
- const ext = path.extname(filePath);
205
- if ([".ts", ".tsx", ".js", ".jsx"].includes(ext)) {
206
- const result = await this.checkFrontendBuild(filePath);
207
- if (result.error) {
208
- this.notifyClients('src-error', { file: filePath, error: result.error });
209
- return;
210
- }
211
- }
212
-
213
- // Se for arquivo de frontend, notifica o cliente para recarregar a página
205
+ // Se for arquivo de frontend, aguarda o build terminar antes de recarregar
214
206
  if (isFrontendFile) {
215
- Console.logWithout(Levels.INFO, Colors.BgRed,`📄 Recarregando frontend...`);
216
- this.frontendChangeCallback?.();
217
- this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
207
+ Console.logWithout(Levels.INFO, Colors.BgRed,`📄 Aguardando build do frontend...`);
208
+
209
+ // Marca que estamos esperando um build
210
+ this.isBuilding = true;
211
+
212
+ // Cria uma promise que será resolvida quando o build terminar
213
+ const buildPromise = new Promise<void>((resolve) => {
214
+ this.buildCompleteResolve = resolve;
215
+ });
216
+
217
+ // Aguarda o build terminar (com timeout de 30 segundos)
218
+ const timeoutPromise = new Promise<void>((_, reject) => {
219
+ setTimeout(() => reject(new Error('Build timeout')), 30000);
220
+ });
221
+
222
+ try {
223
+ await Promise.race([buildPromise, timeoutPromise]);
224
+ Console.logWithout(Levels.INFO, Colors.BgRed,`✅ Build concluído, recarregando frontend...`);
225
+ this.frontendChangeCallback?.();
226
+ this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
227
+ } catch (error) {
228
+ Console.logWithout(Levels.ERROR, Colors.BgRed,`⚠️ Timeout no build, recarregando mesmo assim...`);
229
+ this.frontendChangeCallback?.();
230
+ this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
231
+ } finally {
232
+ this.isBuilding = false;
233
+ this.buildCompleteResolve = null;
234
+ }
218
235
  }
219
236
 
220
237
  // Se for arquivo de backend, recarrega o módulo e notifica
@@ -453,38 +470,11 @@ export class HotReloadManager {
453
470
  this.customHotReloadListener = null;
454
471
  }
455
472
 
456
- private async checkFrontendBuild(filePath: string) {
457
- try {
458
- const tsNodePath = require.resolve('ts-node');
459
- const { spawn } = require('child_process');
460
-
461
- return new Promise<{ error?: string }>((resolve) => {
462
- const proc = spawn(process.execPath, [tsNodePath, '--transpile-only', filePath], {
463
- cwd: this.projectDir,
464
- env: process.env,
465
- timeout: 10000 // Timeout de 10 segundos
466
- });
467
-
468
- let errorMsg = '';
469
-
470
- proc.stderr.on('data', (data: Buffer) => {
471
- errorMsg += data.toString();
472
- });
473
-
474
- proc.on('close', (code: number) => {
475
- if (code !== 0 && errorMsg) {
476
- resolve({ error: errorMsg });
477
- } else {
478
- resolve({});
479
- }
480
- });
481
-
482
- proc.on('error', (error: Error) => {
483
- resolve({ error: error.message });
484
- });
485
- });
486
- } catch (error) {
487
- return { error: `Erro ao verificar build: ${error}` };
473
+ onBuildComplete(success: boolean) {
474
+ if (this.buildCompleteResolve) {
475
+ this.buildCompleteResolve();
476
+ this.buildCompleteResolve = null;
488
477
  }
478
+ this.isBuilding = false;
489
479
  }
490
480
  }