hightjs 0.3.5 → 0.5.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.
Files changed (123) hide show
  1. package/README.md +48 -116
  2. package/dist/bin/hightjs.js +51 -23
  3. package/dist/builder.js +198 -8
  4. package/dist/client/DefaultNotFound.d.ts +1 -1
  5. package/dist/client/DefaultNotFound.js +72 -46
  6. package/dist/client/client.d.ts +3 -0
  7. package/dist/{client.js → client/client.js} +4 -4
  8. package/dist/client/entry.client.js +77 -9
  9. package/dist/global/global.d.ts +117 -0
  10. package/dist/{auth/types.js → global/global.js} +0 -1
  11. package/dist/helpers.js +80 -2
  12. package/dist/hotReload.js +84 -4
  13. package/dist/index.js +72 -61
  14. package/dist/loaders.d.ts +1 -0
  15. package/dist/loaders.js +46 -0
  16. package/dist/renderer.js +158 -4
  17. package/dist/types.d.ts +44 -0
  18. package/package.json +37 -30
  19. package/.idea/HightJS.iml +0 -9
  20. package/.idea/copilot.data.migration.agent.xml +0 -6
  21. package/.idea/copilot.data.migration.ask.xml +0 -6
  22. package/.idea/copilot.data.migration.ask2agent.xml +0 -6
  23. package/.idea/copilot.data.migration.edit.xml +0 -6
  24. package/.idea/copilotDiffState.xml +0 -67
  25. package/.idea/inspectionProfiles/Project_Default.xml +0 -13
  26. package/.idea/libraries/test_package.xml +0 -9
  27. package/.idea/libraries/ts_commonjs_default_export.xml +0 -9
  28. package/.idea/misc.xml +0 -7
  29. package/.idea/modules.xml +0 -8
  30. package/.idea/vcs.xml +0 -6
  31. package/dist/auth/client.d.ts +0 -24
  32. package/dist/auth/client.js +0 -146
  33. package/dist/auth/components.d.ts +0 -29
  34. package/dist/auth/components.js +0 -100
  35. package/dist/auth/core.d.ts +0 -55
  36. package/dist/auth/core.js +0 -189
  37. package/dist/auth/index.d.ts +0 -7
  38. package/dist/auth/index.js +0 -45
  39. package/dist/auth/jwt.d.ts +0 -41
  40. package/dist/auth/jwt.js +0 -185
  41. package/dist/auth/providers/credentials.d.ts +0 -60
  42. package/dist/auth/providers/credentials.js +0 -97
  43. package/dist/auth/providers/discord.d.ts +0 -63
  44. package/dist/auth/providers/discord.js +0 -190
  45. package/dist/auth/providers/google.d.ts +0 -63
  46. package/dist/auth/providers/google.js +0 -186
  47. package/dist/auth/providers/index.d.ts +0 -2
  48. package/dist/auth/providers/index.js +0 -35
  49. package/dist/auth/providers.d.ts +0 -3
  50. package/dist/auth/providers.js +0 -26
  51. package/dist/auth/react/index.d.ts +0 -6
  52. package/dist/auth/react/index.js +0 -48
  53. package/dist/auth/react.d.ts +0 -22
  54. package/dist/auth/react.js +0 -199
  55. package/dist/auth/routes.d.ts +0 -16
  56. package/dist/auth/routes.js +0 -152
  57. package/dist/auth/types.d.ts +0 -76
  58. package/dist/client.d.ts +0 -3
  59. package/docs/README.md +0 -58
  60. package/docs/arquivos-especiais.md +0 -10
  61. package/docs/autenticacao.md +0 -212
  62. package/docs/checklist.md +0 -9
  63. package/docs/cli.md +0 -72
  64. package/docs/config.md +0 -216
  65. package/docs/estrutura.md +0 -20
  66. package/docs/faq.md +0 -10
  67. package/docs/hot-reload.md +0 -5
  68. package/docs/integracoes.md +0 -240
  69. package/docs/middlewares.md +0 -73
  70. package/docs/rotas-backend.md +0 -45
  71. package/docs/rotas-frontend.md +0 -66
  72. package/docs/seguranca.md +0 -8
  73. package/docs/websocket.md +0 -45
  74. package/example/certs/cert.pem +0 -20
  75. package/example/certs/key.pem +0 -27
  76. package/example/hightjs.config.ts +0 -87
  77. package/example/package-lock.json +0 -1174
  78. package/example/package.json +0 -26
  79. package/example/postcss.config.js +0 -8
  80. package/example/src/auth.ts +0 -42
  81. package/example/src/web/backend/routes/auth.ts +0 -3
  82. package/example/src/web/backend/routes/version.ts +0 -13
  83. package/example/src/web/globals.css +0 -5
  84. package/example/src/web/layout.tsx +0 -100
  85. package/example/src/web/routes/index.tsx +0 -153
  86. package/example/src/web/routes/login.tsx +0 -175
  87. package/example/tailwind.config.js +0 -12
  88. package/example/tsconfig.json +0 -15
  89. package/src/adapters/express.ts +0 -87
  90. package/src/adapters/factory.ts +0 -112
  91. package/src/adapters/fastify.ts +0 -104
  92. package/src/adapters/native.ts +0 -234
  93. package/src/api/console.ts +0 -305
  94. package/src/api/http.ts +0 -535
  95. package/src/auth/client.ts +0 -171
  96. package/src/auth/components.tsx +0 -125
  97. package/src/auth/core.ts +0 -215
  98. package/src/auth/index.ts +0 -25
  99. package/src/auth/jwt.ts +0 -210
  100. package/src/auth/providers/credentials.ts +0 -139
  101. package/src/auth/providers/discord.ts +0 -239
  102. package/src/auth/providers/google.ts +0 -234
  103. package/src/auth/providers/index.ts +0 -20
  104. package/src/auth/providers.ts +0 -20
  105. package/src/auth/react/index.ts +0 -25
  106. package/src/auth/react.tsx +0 -234
  107. package/src/auth/routes.ts +0 -183
  108. package/src/auth/types.ts +0 -108
  109. package/src/bin/hightjs.js +0 -222
  110. package/src/builder.js +0 -411
  111. package/src/client/DefaultNotFound.tsx +0 -84
  112. package/src/client/clientRouter.ts +0 -153
  113. package/src/client/entry.client.tsx +0 -444
  114. package/src/client.ts +0 -24
  115. package/src/components/Link.tsx +0 -38
  116. package/src/helpers.ts +0 -542
  117. package/src/hotReload.ts +0 -489
  118. package/src/index.ts +0 -546
  119. package/src/renderer.tsx +0 -263
  120. package/src/router.ts +0 -730
  121. package/src/types/framework.ts +0 -58
  122. package/src/types.ts +0 -207
  123. package/tsconfig.json +0 -17
package/README.md CHANGED
@@ -1,158 +1,90 @@
1
1
  <div align="center">
2
2
  <picture>
3
3
  <source media="(prefers-color-scheme: dark)" srcset="https://repository-images.githubusercontent.com/1069175740/e5c59d3a-e1fd-446c-a89f-785ed08f6a16">
4
- <img alt="Next.js logo" src="https://repository-images.githubusercontent.com/1069175740/e5c59d3a-e1fd-446c-a89f-785ed08f6a16" height="128">
4
+ <img alt="HightJS logo" src="https://repository-images.githubusercontent.com/1069175740/e5c59d3a-e1fd-446c-a89f-785ed08f6a16" height="128">
5
5
  </picture>
6
6
  <h1>HightJS</h1>
7
7
 
8
8
  [![NPM](https://img.shields.io/npm/v/hightjs.svg?style=for-the-badge&labelColor=000000)](https://www.npmjs.com/package/hightjs)
9
- [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg?style=for-the-badge&labelColor=000000)](./LICENSE)
10
-
9
+ [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg?style=for-the-badge&labelColor=000000)](../../LICENSE)
11
10
 
12
11
  </div>
13
12
 
14
- > Um framework web fullstack moderno para Node.js, focado em simplicidade, DX e velocidade. Bundler via esbuild, hot reload, roteamento automático, APIs, autenticação JWT, CLI e muito mais.
15
- ---
16
-
17
- # Precisa de ajuda?
18
- Caso tenha alguma dúvida, entre em contato por uma das redes abaixo:
19
-
20
- [![Discord](https://img.shields.io/badge/Discord-mulinfrc-5865F2?style=for-the-badge&logo=discord&logoColor=white)](https://discord.com/users/1264710048786026588)
21
- [![Gmail](https://img.shields.io/badge/Gmail-D14836?style=for-the-badge&logo=gmail&logoColor=white)](mailto:murillofrazaocunha@gmail.com)
22
- [![Instagram](https://img.shields.io/badge/Instagram-E4405F?style=for-the-badge&logo=instagram&logoColor=white)](https://instagram.com/itsmuh_)
23
- [![GitHub](https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white)](https://github.com/murillo-frazao-cunha)
13
+ > A modern full-stack web framework for Node.js, focused on simplicity, developer experience, and speed.
24
14
 
25
15
  ---
26
16
 
27
- ## 📑 Índice
17
+ ## Features
18
+
19
+ - **🚀 Blazing Fast** - Built on esbuild for lightning-fast builds and hot reload
20
+ - **📁 File-based Routing** - Automatic routing for pages (`src/web/routes`) and APIs (`src/backend/routes`)
21
+ - **⚛️ React 19** - Latest React with client-side hydration and streaming SSR
22
+ - **📘 TypeScript First** - Fully typed out of the box
23
+ - **🎨 Asset Imports** - Import images, markdown, SVG, JSON, fonts, audio, video directly
24
+ - **🔌 WebSockets** - Native WebSocket support in backend routes
25
+ - **🎯 Dynamic Routes** - Support for dynamic parameters in frontend and backend
26
+ - **🛡️ Middleware** - Per-folder and per-route middleware support
27
+ - **🔄 Hot Reload** - Native hot reload via internal WebSocket in dev mode
28
+ - **🎭 Layouts** - Global layouts and custom 404 pages
29
+ - **📝 Dynamic Metadata** - Per-page metadata generation
30
+ - **📦 Smart Bundling** - Single bundle or code splitting
31
+ - **🔒 Built-in SSL** - HTTPS out-of-the-box in Native mode
32
+ - **🔐 Authentication** - JWT authentication built-in (HWebAuth)
33
+ - **⚙️ CLI** - Own CLI (`hight`) for dev and production
34
+ - **📂 Static Files** - Serve static files from `public/`
35
+ - **🛡️ Security** - Built-in sanitization and rate limiting
28
36
 
29
- - [✨ Principais Recursos](#-principais-recursos)
30
- - [🚀 Início Rápido](#-início-rápido)
31
- - [📚 Documentação](#-documentação)
32
- - [🪪 Licença](#-licença)
33
37
  ---
34
38
 
35
- ## Principais Recursos
36
-
37
- - **Roteamento automático** de páginas [`src/web/routes`] e APIs [`src/web/backend/routes`]
38
- - **React 19** com client-side hydration
39
- - **TypeScript** first (totalmente tipado)
40
- - **WebSockets** nativo nas rotas backend
41
- - **Rotas dinâmicas** com parâmetros (frontend e backend)
42
- - **Middlewares** por pasta ou rota
43
- - **Hot Reload** nativo (WebSocket interno) em dev
44
- - **Layouts globais** e página 404 customizada
45
- - **Metadata** dinâmica por página
46
- - **Build inteligente** (single bundle ou chunks)
47
- - **SSL integrado** no modo Native (HTTPS out-of-the-box)
48
- - **Autenticação** JWT embutida (HWebAuth)
49
- - **CLI própria** (`hight`) para dev e produção
50
- - **Entrega de estáticos** (`public/`)
51
- - Segurança, saneamento e limitações nativas
52
-
53
- ---
54
-
55
- ## 🚀 Início Rápido
56
-
57
- > O mínimo para rodar!
39
+ ## 📦 Installation
58
40
 
59
41
  ```bash
60
- npm init -y
61
- npm install typescript --save-dev
62
- npx tsc --init
63
- npm install hightjs react@19 react-dom@19 ts-node
64
- npm install --save-dev @types/react
65
- ```
66
-
67
- Crie um `tsconfig.json` na raiz do projeto:
68
-
69
- ```json
70
- {
71
- "compilerOptions": {
72
- "target": "ES6",
73
- "module": "CommonJS",
74
- "jsx": "react",
75
- "strict": true,
76
- "esModuleInterop": true,
77
- "resolveJsonModule": true,
78
- "skipLibCheck": true,
79
- "forceConsistentCasingInFileNames": true,
80
- "outDir": "./dist",
81
- "moduleResolution": "nodenext"
82
- },
83
- "include": ["src/**/*"]
84
- }
85
- ```
86
-
87
- Estrutura mínima:
88
-
89
- ```
90
- src/
91
- web/
92
- routes/
93
- index.tsx
94
- ```
95
-
96
- Exemplo de página inicial em `src/web/routes/index.tsx`:
97
-
98
- ```tsx
99
- import { RouteConfig } from 'hightjs/client';
100
- import React from 'react';
101
-
102
- function Home() {
103
- return <h1>Bem-vindo ao HightJS 🚀</h1>;
104
- }
105
-
106
- export const config: RouteConfig = {
107
- pattern: '/',
108
- component: Home,
109
- generateMetadata: () => ({ title: 'HightJS | Home' })
110
- };
111
- export default config;
42
+ npm install hightjs react@19 react-dom@19
112
43
  ```
113
44
 
114
- Rode em modo dev:
45
+ ## 🚀 Quick Start
115
46
 
116
47
  ```bash
117
48
  npx hight dev
118
49
  ```
119
50
 
120
- Acesse: [http://localhost:3000](http://localhost:3000)
51
+ Visit [http://localhost:3000](http://localhost:3000)
121
52
 
122
53
  ---
123
54
 
124
- ## 📚 Documentação
55
+ ## 📚 Documentation
125
56
 
126
- Documentação completa disponível na pasta `docs/`:
57
+ For complete documentation, tutorials, and guides, visit:
127
58
 
128
- ### Fundamentos
129
- - [📦 Estrutura Recomendada](./docs/estrutura.md)
130
- - [🖥️ Rotas Frontend](./docs/rotas-frontend.md)
131
- - [🌐 Rotas Backend](./docs/rotas-backend.md)
59
+ **[https://docs.hgo.me](https://docs.hgo.me)**
132
60
 
133
- ### Recursos Avançados
134
- - [🛜 WebSocket](./docs/websocket.md)
135
- - [🧩 Middlewares](./docs/middlewares.md)
136
- - [🔐 Autenticação](./docs/autenticacao.md)
61
+ Learn about:
62
+ - Getting started
63
+ - Routing (frontend & backend)
64
+ - Authentication
65
+ - Middleware
66
+ - Layouts & Metadata
67
+ - Static export
68
+ - And much more!
137
69
 
138
- ### Ferramentas e Configuração
139
- - [🛠️ CLI](./docs/cli.md)
140
- - [📂 Arquivos Especiais](./docs/arquivos-especiais.md)
141
- - [🔌 Integrações](./docs/integracoes.md)
142
- - [🔐 Segurança Interna](./docs/seguranca.md)
143
- - [♻️ Hot Reload](./docs/hot-reload.md)
70
+ ---
71
+
72
+ ## 💬 Need Help?
144
73
 
145
- ### Ajuda
146
- - [❓ FAQ Rápido](./docs/faq.md)
147
- - [✅ Checklist Mental](./docs/checklist.md)
74
+ If you have questions or need support, feel free to reach out:
75
+
76
+ [![Discord](https://img.shields.io/badge/Discord-mulinfrc-5865F2?style=for-the-badge&logo=discord&logoColor=white)](https://discord.com/users/1264710048786026588)
77
+ [![Gmail](https://img.shields.io/badge/Gmail-D14836?style=for-the-badge&logo=gmail&logoColor=white)](mailto:murillofrazaocunha@gmail.com)
78
+ [![Instagram](https://img.shields.io/badge/Instagram-E4405F?style=for-the-badge&logo=instagram&logoColor=white)](https://instagram.com/itsmuh_)
79
+ [![GitHub](https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white)](https://github.com/murillo-frazao-cunha)
148
80
 
149
81
  ---
150
82
 
151
- ## 🪪 Licença
83
+ ## 🪪 License
152
84
 
153
85
  Copyright 2025 itsmuzin
154
86
 
155
- Este projeto está licenciado sob a [Licença Apache 2.0](LICENSE).
87
+ This project is licensed under the [Apache License 2.0](../../LICENSE).
156
88
 
157
89
  ---
158
90
 
@@ -18,6 +18,9 @@
18
18
  */
19
19
  // Registra o ts-node para que o Node.js entenda TypeScript/TSX
20
20
  require('ts-node').register();
21
+ // Registra loaders customizados para arquivos markdown, imagens, etc.
22
+ const { registerLoaders } = require('../loaders');
23
+ registerLoaders();
21
24
  const { program } = require('commander');
22
25
  program
23
26
  .version('1.0.0')
@@ -90,14 +93,44 @@ program
90
93
  .action((options) => {
91
94
  initializeApp(options, false); // Chama a função com dev: false
92
95
  });
93
- // --- Comando EXPORT ---
96
+ /**
97
+ * Função corrigida para copiar diretórios recursivamente.
98
+ * Ela agora verifica se um item é um arquivo ou um diretório.
99
+ */
100
+ function copyDirRecursive(src, dest) {
101
+ try {
102
+ // Garante que o diretório de destino exista
103
+ fs.mkdirSync(dest, { recursive: true });
104
+ // Usamos { withFileTypes: true } para evitar uma chamada extra de fs.statSync
105
+ const entries = fs.readdirSync(src, { withFileTypes: true });
106
+ for (let entry of entries) {
107
+ const srcPath = path.join(src, entry.name);
108
+ const destPath = path.join(dest, entry.name);
109
+ if (entry.isDirectory()) {
110
+ // Se for um diretório, chama a si mesma (recursão)
111
+ copyDirRecursive(srcPath, destPath);
112
+ }
113
+ else {
114
+ // Se for um arquivo, apenas copia
115
+ fs.copyFileSync(srcPath, destPath);
116
+ }
117
+ }
118
+ }
119
+ catch (error) {
120
+ console.error(`❌ Erro ao copiar ${src} para ${dest}:`, error);
121
+ // Lança o erro para parar o processo de exportação se a cópia falhar
122
+ throw error;
123
+ }
124
+ }
125
+ // --- INÍCIO DO SEU CÓDIGO (AGORA CORRIGIDO) ---
94
126
  program
95
127
  .command('export')
96
128
  .description('Exports the application as static HTML to the "exported" folder.')
97
129
  .option('-o, --output <path>', 'Specifies the output directory', 'exported')
98
130
  .action(async (options) => {
99
131
  const projectDir = process.cwd();
100
- const exportDir = path.join(projectDir, options.output);
132
+ // Usar path.resolve é mais seguro para garantir um caminho absoluto
133
+ const exportDir = path.resolve(projectDir, options.output);
101
134
  console.log('🚀 Starting export...\n');
102
135
  try {
103
136
  // 1. Cria a pasta exported (limpa se já existir)
@@ -109,43 +142,36 @@ program
109
142
  console.log('✅ Export folder created\n');
110
143
  // 2. Inicializa e prepara o build
111
144
  console.log('🔨 Building application...');
145
+ // ATENÇÃO: Ajuste o caminho deste 'require' conforme a estrutura do seu projeto!
112
146
  const teste = require("../helpers");
113
147
  const app = teste.default({ dev: false, port: 3000, hostname: '0.0.0.0', framework: 'native' });
114
148
  await app.prepare();
115
149
  console.log('✅ Build complete\n');
116
- // 3. Copia a pasta .hight para exported
150
+ // 3. Copia a pasta .hight para exported (*** CORRIGIDO ***)
117
151
  const distDir = path.join(projectDir, '.hight');
118
152
  if (fs.existsSync(distDir)) {
119
153
  console.log('📦 Copying JavaScript files...');
120
154
  const exportDistDir = path.join(exportDir, '.hight');
121
- fs.mkdirSync(exportDistDir, { recursive: true });
122
- const files = fs.readdirSync(distDir);
123
- files.forEach(file => {
124
- fs.copyFileSync(path.join(distDir, file), path.join(exportDistDir, file));
125
- });
155
+ // --- Lógica de cópia substituída ---
156
+ // A função copyDirRecursive agora lida com tudo (arquivos e subpastas)
157
+ copyDirRecursive(distDir, exportDistDir);
158
+ // --- Fim da substituição ---
126
159
  console.log('✅ JavaScript files copied\n');
127
160
  }
128
- // 4. Copia a pasta public se existir
161
+ // 4. Copia a pasta public se existir (*** CORRIGIDO ***)
129
162
  const publicDir = path.join(projectDir, 'public');
130
163
  if (fs.existsSync(publicDir)) {
131
164
  console.log('📁 Copying public files...');
132
165
  const exportPublicDir = path.join(exportDir, 'public');
133
- function copyRecursive(src, dest) {
134
- if (fs.statSync(src).isDirectory()) {
135
- fs.mkdirSync(dest, { recursive: true });
136
- fs.readdirSync(src).forEach(file => {
137
- copyRecursive(path.join(src, file), path.join(dest, file));
138
- });
139
- }
140
- else {
141
- fs.copyFileSync(src, dest);
142
- }
143
- }
144
- copyRecursive(publicDir, exportPublicDir);
166
+ // --- Lógica de cópia substituída ---
167
+ // Reutilizamos a mesma função corrigida
168
+ copyDirRecursive(publicDir, exportPublicDir);
169
+ // --- Fim da substituição ---
145
170
  console.log('✅ Public files copied\n');
146
171
  }
147
172
  // 5. Gera o index.html
148
173
  console.log('📝 Generating index.html...');
174
+ // ATENÇÃO: Ajuste os caminhos destes 'requires' conforme a estrutura do seu projeto!
149
175
  const { render } = require('../renderer');
150
176
  const { loadRoutes, loadLayout, loadNotFound } = require('../router');
151
177
  // Carrega as rotas para gerar o HTML
@@ -170,15 +196,17 @@ program
170
196
  params: {},
171
197
  allRoutes: routes
172
198
  });
199
+ const scriptReplaced = html.replace('/_hight/', './.hight/');
173
200
  const indexPath = path.join(exportDir, 'index.html');
174
- fs.writeFileSync(indexPath, html, 'utf8');
201
+ fs.writeFileSync(indexPath, scriptReplaced, 'utf8');
175
202
  console.log('✅ index.html generated\n');
176
203
  }
177
204
  console.log('🎉 Export completed successfully!');
178
205
  console.log(`📂 Files exported to: ${exportDir}\n`);
179
206
  }
180
207
  catch (error) {
181
- console.error('❌ Error during export:', error.message);
208
+ // Logar o erro completo (com stack trace) é mais útil
209
+ console.error('❌ Error during export:', error);
182
210
  process.exit(1);
183
211
  }
184
212
  });
package/dist/builder.js CHANGED
@@ -19,6 +19,8 @@ const esbuild = require('esbuild');
19
19
  const path = require('path');
20
20
  const Console = require("./api/console").default;
21
21
  const fs = require('fs');
22
+ const { readdir, stat } = require("node:fs/promises");
23
+ const { rm } = require("fs-extra");
22
24
  // Lista de módulos nativos do Node.js para marcar como externos (apenas os built-ins do Node)
23
25
  const nodeBuiltIns = [
24
26
  'assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns',
@@ -175,6 +177,177 @@ const reactResolvePlugin = {
175
177
  });
176
178
  }
177
179
  };
180
+ /**
181
+ * Plugin para adicionar suporte a HMR (Hot Module Replacement)
182
+ */
183
+ const hmrPlugin = {
184
+ name: 'hmr-plugin',
185
+ setup(build) {
186
+ // Adiciona runtime de HMR para arquivos TSX/JSX
187
+ build.onLoad({ filter: /\.(tsx|jsx)$/ }, async (args) => {
188
+ // Ignora arquivos de node_modules
189
+ if (args.path.includes('node_modules')) {
190
+ return null;
191
+ }
192
+ const fs = require('fs');
193
+ const contents = await fs.promises.readFile(args.path, 'utf8');
194
+ // Adiciona código de HMR apenas em componentes de rota
195
+ if (args.path.includes('/routes/') || args.path.includes('\\routes\\')) {
196
+ const hmrCode = `
197
+ // HMR Runtime
198
+ if (typeof window !== 'undefined' && window.__HWEB_HMR__) {
199
+ const moduleId = ${JSON.stringify(args.path)};
200
+ if (!window.__HWEB_HMR_MODULES__) {
201
+ window.__HWEB_HMR_MODULES__ = new Map();
202
+ }
203
+ window.__HWEB_HMR_MODULES__.set(moduleId, module.exports);
204
+ }
205
+ `;
206
+ return {
207
+ contents: contents + '\n' + hmrCode,
208
+ loader: 'tsx'
209
+ };
210
+ }
211
+ return null;
212
+ });
213
+ }
214
+ };
215
+ /**
216
+ * Plugin para suportar importação de arquivos Markdown (.md)
217
+ */
218
+ const markdownPlugin = {
219
+ name: 'markdown-plugin',
220
+ setup(build) {
221
+ build.onLoad({ filter: /\.md$/ }, async (args) => {
222
+ const fs = require('fs');
223
+ const content = await fs.promises.readFile(args.path, 'utf8');
224
+ return {
225
+ contents: `export default ${JSON.stringify(content)};`,
226
+ loader: 'js'
227
+ };
228
+ });
229
+ }
230
+ };
231
+ /**
232
+ * Plugin para suportar importação de arquivos de imagem e outros assets
233
+ */
234
+ const assetsPlugin = {
235
+ name: 'assets-plugin',
236
+ setup(build) {
237
+ // Suporte para imagens (PNG, JPG, JPEG, GIF, SVG, WEBP, etc)
238
+ build.onLoad({ filter: /\.(png|jpe?g|gif|webp|avif|ico|bmp|tiff?)$/i }, async (args) => {
239
+ const fs = require('fs');
240
+ const buffer = await fs.promises.readFile(args.path);
241
+ const base64 = buffer.toString('base64');
242
+ const ext = path.extname(args.path).slice(1).toLowerCase();
243
+ // Mapeamento de extensões para MIME types
244
+ const mimeTypes = {
245
+ 'png': 'image/png',
246
+ 'jpg': 'image/jpeg',
247
+ 'jpeg': 'image/jpeg',
248
+ 'gif': 'image/gif',
249
+ 'webp': 'image/webp',
250
+ 'avif': 'image/avif',
251
+ 'ico': 'image/x-icon',
252
+ 'bmp': 'image/bmp',
253
+ 'tif': 'image/tiff',
254
+ 'tiff': 'image/tiff'
255
+ };
256
+ const mimeType = mimeTypes[ext] || 'application/octet-stream';
257
+ return {
258
+ contents: `export default "data:${mimeType};base64,${base64}";`,
259
+ loader: 'js'
260
+ };
261
+ });
262
+ // Suporte especial para SVG (pode ser usado como string ou data URL)
263
+ build.onLoad({ filter: /\.svg$/i }, async (args) => {
264
+ const fs = require('fs');
265
+ const content = await fs.promises.readFile(args.path, 'utf8');
266
+ const base64 = Buffer.from(content).toString('base64');
267
+ return {
268
+ contents: `
269
+ export default "data:image/svg+xml;base64,${base64}";
270
+ export const svgContent = ${JSON.stringify(content)};
271
+ `,
272
+ loader: 'js'
273
+ };
274
+ });
275
+ // Suporte para arquivos JSON
276
+ build.onLoad({ filter: /\.json$/i }, async (args) => {
277
+ const fs = require('fs');
278
+ const content = await fs.promises.readFile(args.path, 'utf8');
279
+ return {
280
+ contents: `export default ${content};`,
281
+ loader: 'js'
282
+ };
283
+ });
284
+ // Suporte para arquivos de texto (.txt)
285
+ build.onLoad({ filter: /\.txt$/i }, async (args) => {
286
+ const fs = require('fs');
287
+ const content = await fs.promises.readFile(args.path, 'utf8');
288
+ return {
289
+ contents: `export default ${JSON.stringify(content)};`,
290
+ loader: 'js'
291
+ };
292
+ });
293
+ // Suporte para arquivos de fonte (WOFF, WOFF2, TTF, OTF, EOT)
294
+ build.onLoad({ filter: /\.(woff2?|ttf|otf|eot)$/i }, async (args) => {
295
+ const fs = require('fs');
296
+ const buffer = await fs.promises.readFile(args.path);
297
+ const base64 = buffer.toString('base64');
298
+ const ext = path.extname(args.path).slice(1).toLowerCase();
299
+ const mimeTypes = {
300
+ 'woff': 'font/woff',
301
+ 'woff2': 'font/woff2',
302
+ 'ttf': 'font/ttf',
303
+ 'otf': 'font/otf',
304
+ 'eot': 'application/vnd.ms-fontobject'
305
+ };
306
+ const mimeType = mimeTypes[ext] || 'application/octet-stream';
307
+ return {
308
+ contents: `export default "data:${mimeType};base64,${base64}";`,
309
+ loader: 'js'
310
+ };
311
+ });
312
+ // Suporte para arquivos de áudio (MP3, WAV, OGG, etc)
313
+ build.onLoad({ filter: /\.(mp3|wav|ogg|m4a|aac|flac)$/i }, async (args) => {
314
+ const fs = require('fs');
315
+ const buffer = await fs.promises.readFile(args.path);
316
+ const base64 = buffer.toString('base64');
317
+ const ext = path.extname(args.path).slice(1).toLowerCase();
318
+ const mimeTypes = {
319
+ 'mp3': 'audio/mpeg',
320
+ 'wav': 'audio/wav',
321
+ 'ogg': 'audio/ogg',
322
+ 'm4a': 'audio/mp4',
323
+ 'aac': 'audio/aac',
324
+ 'flac': 'audio/flac'
325
+ };
326
+ const mimeType = mimeTypes[ext] || 'audio/mpeg';
327
+ return {
328
+ contents: `export default "data:${mimeType};base64,${base64}";`,
329
+ loader: 'js'
330
+ };
331
+ });
332
+ // Suporte para arquivos de vídeo (MP4, WEBM, OGV)
333
+ build.onLoad({ filter: /\.(mp4|webm|ogv)$/i }, async (args) => {
334
+ const fs = require('fs');
335
+ const buffer = await fs.promises.readFile(args.path);
336
+ const base64 = buffer.toString('base64');
337
+ const ext = path.extname(args.path).slice(1).toLowerCase();
338
+ const mimeTypes = {
339
+ 'mp4': 'video/mp4',
340
+ 'webm': 'video/webm',
341
+ 'ogv': 'video/ogg'
342
+ };
343
+ const mimeType = mimeTypes[ext] || 'video/mp4';
344
+ return {
345
+ contents: `export default "data:${mimeType};base64,${base64}";`,
346
+ loader: 'js'
347
+ };
348
+ });
349
+ }
350
+ };
178
351
  /**
179
352
  * Builds with code splitting into multiple chunks based on module types.
180
353
  * @param {string} entryPoint - The path to the entry file.
@@ -183,8 +356,8 @@ const reactResolvePlugin = {
183
356
  * @returns {Promise<void>}
184
357
  */
185
358
  async function buildWithChunks(entryPoint, outdir, isProduction = false) {
186
- // limpar diretorio
187
- fs.rmSync(outdir, { recursive: true, force: true });
359
+ // limpar diretorio, menos a pasta temp
360
+ await cleanDirectoryExcept(outdir, 'temp');
188
361
  try {
189
362
  await esbuild.build({
190
363
  entryPoints: [entryPoint],
@@ -195,7 +368,7 @@ async function buildWithChunks(entryPoint, outdir, isProduction = false) {
195
368
  outdir: outdir,
196
369
  loader: { '.js': 'jsx', '.ts': 'tsx' },
197
370
  external: nodeBuiltIns,
198
- plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin],
371
+ plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, markdownPlugin, assetsPlugin],
199
372
  format: 'esm', // ESM suporta melhor o code splitting
200
373
  jsx: 'automatic',
201
374
  define: {
@@ -226,7 +399,7 @@ async function buildWithChunks(entryPoint, outdir, isProduction = false) {
226
399
  */
227
400
  async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
228
401
  // limpar diretorio
229
- fs.rmSync(outdir, { recursive: true, force: true });
402
+ await cleanDirectoryExcept(outdir, 'temp');
230
403
  try {
231
404
  // Plugin para notificar quando o build termina
232
405
  const buildCompletePlugin = {
@@ -256,7 +429,7 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
256
429
  outdir: outdir,
257
430
  loader: { '.js': 'jsx', '.ts': 'tsx' },
258
431
  external: nodeBuiltIns,
259
- plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, buildCompletePlugin],
432
+ plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, hmrPlugin, buildCompletePlugin, markdownPlugin, assetsPlugin],
260
433
  format: 'esm',
261
434
  jsx: 'automatic',
262
435
  define: {
@@ -289,7 +462,7 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
289
462
  async function build(entryPoint, outfile, isProduction = false) {
290
463
  // limpar diretorio do outfile
291
464
  const outdir = path.dirname(outfile);
292
- fs.rmSync(outdir, { recursive: true, force: true });
465
+ await cleanDirectoryExcept(outdir, 'temp');
293
466
  try {
294
467
  await esbuild.build({
295
468
  entryPoints: [entryPoint],
@@ -300,7 +473,7 @@ async function build(entryPoint, outfile, isProduction = false) {
300
473
  outfile: outfile,
301
474
  loader: { '.js': 'jsx', '.ts': 'tsx' },
302
475
  external: nodeBuiltIns,
303
- plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin],
476
+ plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, markdownPlugin, assetsPlugin],
304
477
  format: 'iife',
305
478
  globalName: 'HwebApp',
306
479
  jsx: 'automatic',
@@ -362,7 +535,6 @@ async function watch(entryPoint, outfile, hotReloadManager = null) {
362
535
  outfile: outfile,
363
536
  loader: { '.js': 'jsx', '.ts': 'tsx' },
364
537
  external: nodeBuiltIns,
365
- plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, buildCompletePlugin],
366
538
  format: 'iife',
367
539
  globalName: 'HwebApp',
368
540
  jsx: 'automatic',
@@ -388,4 +560,22 @@ async function watch(entryPoint, outfile, hotReloadManager = null) {
388
560
  throw error;
389
561
  }
390
562
  }
563
+ /**
564
+ * Remove todo o conteúdo de um diretório,
565
+ * exceto a pasta (ou pastas) especificada(s) em excludeFolder.
566
+ *
567
+ * @param {string} dirPath - Caminho do diretório a limpar
568
+ * @param {string|string[]} excludeFolder - Nome ou nomes das pastas a manter
569
+ */
570
+ async function cleanDirectoryExcept(dirPath, excludeFolder) {
571
+ const excludes = Array.isArray(excludeFolder) ? excludeFolder : [excludeFolder];
572
+ const items = await readdir(dirPath);
573
+ for (const item of items) {
574
+ if (excludes.includes(item))
575
+ continue; // pula as pastas excluídas
576
+ const itemPath = path.join(dirPath, item);
577
+ const info = await stat(itemPath);
578
+ await rm(itemPath, { recursive: info.isDirectory(), force: true });
579
+ }
580
+ }
391
581
  module.exports = { build, watch, buildWithChunks, watchWithChunks };
@@ -1 +1 @@
1
- export default function DefaultNotFound(): import("react/jsx-runtime").JSX.Element;
1
+ export default function App(): import("react/jsx-runtime").JSX.Element;