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.
- package/README.md +48 -116
- package/dist/bin/hightjs.js +51 -23
- package/dist/builder.js +198 -8
- package/dist/client/DefaultNotFound.d.ts +1 -1
- package/dist/client/DefaultNotFound.js +72 -46
- package/dist/client/client.d.ts +3 -0
- package/dist/{client.js → client/client.js} +4 -4
- package/dist/client/entry.client.js +77 -9
- package/dist/global/global.d.ts +117 -0
- package/dist/{auth/types.js → global/global.js} +0 -1
- package/dist/helpers.js +80 -2
- package/dist/hotReload.js +84 -4
- package/dist/index.js +72 -61
- package/dist/loaders.d.ts +1 -0
- package/dist/loaders.js +46 -0
- package/dist/renderer.js +158 -4
- package/dist/types.d.ts +44 -0
- package/package.json +37 -30
- package/.idea/HightJS.iml +0 -9
- package/.idea/copilot.data.migration.agent.xml +0 -6
- package/.idea/copilot.data.migration.ask.xml +0 -6
- package/.idea/copilot.data.migration.ask2agent.xml +0 -6
- package/.idea/copilot.data.migration.edit.xml +0 -6
- package/.idea/copilotDiffState.xml +0 -67
- package/.idea/inspectionProfiles/Project_Default.xml +0 -13
- package/.idea/libraries/test_package.xml +0 -9
- package/.idea/libraries/ts_commonjs_default_export.xml +0 -9
- package/.idea/misc.xml +0 -7
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
- package/dist/auth/client.d.ts +0 -24
- package/dist/auth/client.js +0 -146
- package/dist/auth/components.d.ts +0 -29
- package/dist/auth/components.js +0 -100
- package/dist/auth/core.d.ts +0 -55
- package/dist/auth/core.js +0 -189
- package/dist/auth/index.d.ts +0 -7
- package/dist/auth/index.js +0 -45
- package/dist/auth/jwt.d.ts +0 -41
- package/dist/auth/jwt.js +0 -185
- package/dist/auth/providers/credentials.d.ts +0 -60
- package/dist/auth/providers/credentials.js +0 -97
- package/dist/auth/providers/discord.d.ts +0 -63
- package/dist/auth/providers/discord.js +0 -190
- package/dist/auth/providers/google.d.ts +0 -63
- package/dist/auth/providers/google.js +0 -186
- package/dist/auth/providers/index.d.ts +0 -2
- package/dist/auth/providers/index.js +0 -35
- package/dist/auth/providers.d.ts +0 -3
- package/dist/auth/providers.js +0 -26
- package/dist/auth/react/index.d.ts +0 -6
- package/dist/auth/react/index.js +0 -48
- package/dist/auth/react.d.ts +0 -22
- package/dist/auth/react.js +0 -199
- package/dist/auth/routes.d.ts +0 -16
- package/dist/auth/routes.js +0 -152
- package/dist/auth/types.d.ts +0 -76
- package/dist/client.d.ts +0 -3
- package/docs/README.md +0 -58
- package/docs/arquivos-especiais.md +0 -10
- package/docs/autenticacao.md +0 -212
- package/docs/checklist.md +0 -9
- package/docs/cli.md +0 -72
- package/docs/config.md +0 -216
- package/docs/estrutura.md +0 -20
- package/docs/faq.md +0 -10
- package/docs/hot-reload.md +0 -5
- package/docs/integracoes.md +0 -240
- package/docs/middlewares.md +0 -73
- package/docs/rotas-backend.md +0 -45
- package/docs/rotas-frontend.md +0 -66
- package/docs/seguranca.md +0 -8
- package/docs/websocket.md +0 -45
- package/example/certs/cert.pem +0 -20
- package/example/certs/key.pem +0 -27
- package/example/hightjs.config.ts +0 -87
- package/example/package-lock.json +0 -1174
- package/example/package.json +0 -26
- package/example/postcss.config.js +0 -8
- package/example/src/auth.ts +0 -42
- package/example/src/web/backend/routes/auth.ts +0 -3
- package/example/src/web/backend/routes/version.ts +0 -13
- package/example/src/web/globals.css +0 -5
- package/example/src/web/layout.tsx +0 -100
- package/example/src/web/routes/index.tsx +0 -153
- package/example/src/web/routes/login.tsx +0 -175
- package/example/tailwind.config.js +0 -12
- package/example/tsconfig.json +0 -15
- package/src/adapters/express.ts +0 -87
- package/src/adapters/factory.ts +0 -112
- package/src/adapters/fastify.ts +0 -104
- package/src/adapters/native.ts +0 -234
- package/src/api/console.ts +0 -305
- package/src/api/http.ts +0 -535
- package/src/auth/client.ts +0 -171
- package/src/auth/components.tsx +0 -125
- package/src/auth/core.ts +0 -215
- package/src/auth/index.ts +0 -25
- package/src/auth/jwt.ts +0 -210
- package/src/auth/providers/credentials.ts +0 -139
- package/src/auth/providers/discord.ts +0 -239
- package/src/auth/providers/google.ts +0 -234
- package/src/auth/providers/index.ts +0 -20
- package/src/auth/providers.ts +0 -20
- package/src/auth/react/index.ts +0 -25
- package/src/auth/react.tsx +0 -234
- package/src/auth/routes.ts +0 -183
- package/src/auth/types.ts +0 -108
- package/src/bin/hightjs.js +0 -222
- package/src/builder.js +0 -411
- package/src/client/DefaultNotFound.tsx +0 -84
- package/src/client/clientRouter.ts +0 -153
- package/src/client/entry.client.tsx +0 -444
- package/src/client.ts +0 -24
- package/src/components/Link.tsx +0 -38
- package/src/helpers.ts +0 -542
- package/src/hotReload.ts +0 -489
- package/src/index.ts +0 -546
- package/src/renderer.tsx +0 -263
- package/src/router.ts +0 -730
- package/src/types/framework.ts +0 -58
- package/src/types.ts +0 -207
- 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="
|
|
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
|
[](https://www.npmjs.com/package/hightjs)
|
|
9
|
-
[](
|
|
10
|
-
|
|
9
|
+
[](../../LICENSE)
|
|
11
10
|
|
|
12
11
|
</div>
|
|
13
12
|
|
|
14
|
-
>
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
# Precisa de ajuda?
|
|
18
|
-
Caso tenha alguma dúvida, entre em contato por uma das redes abaixo:
|
|
19
|
-
|
|
20
|
-
[](https://discord.com/users/1264710048786026588)
|
|
21
|
-
[](mailto:murillofrazaocunha@gmail.com)
|
|
22
|
-
[](https://instagram.com/itsmuh_)
|
|
23
|
-
[](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
|
-
##
|
|
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
|
-
##
|
|
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
|
|
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
|
-
|
|
45
|
+
## 🚀 Quick Start
|
|
115
46
|
|
|
116
47
|
```bash
|
|
117
48
|
npx hight dev
|
|
118
49
|
```
|
|
119
50
|
|
|
120
|
-
|
|
51
|
+
Visit [http://localhost:3000](http://localhost:3000)
|
|
121
52
|
|
|
122
53
|
---
|
|
123
54
|
|
|
124
|
-
## 📚
|
|
55
|
+
## 📚 Documentation
|
|
125
56
|
|
|
126
|
-
|
|
57
|
+
For complete documentation, tutorials, and guides, visit:
|
|
127
58
|
|
|
128
|
-
|
|
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
|
-
|
|
134
|
-
-
|
|
135
|
-
-
|
|
136
|
-
-
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
74
|
+
If you have questions or need support, feel free to reach out:
|
|
75
|
+
|
|
76
|
+
[](https://discord.com/users/1264710048786026588)
|
|
77
|
+
[](mailto:murillofrazaocunha@gmail.com)
|
|
78
|
+
[](https://instagram.com/itsmuh_)
|
|
79
|
+
[](https://github.com/murillo-frazao-cunha)
|
|
148
80
|
|
|
149
81
|
---
|
|
150
82
|
|
|
151
|
-
## 🪪
|
|
83
|
+
## 🪪 License
|
|
152
84
|
|
|
153
85
|
Copyright 2025 itsmuzin
|
|
154
86
|
|
|
155
|
-
|
|
87
|
+
This project is licensed under the [Apache License 2.0](../../LICENSE).
|
|
156
88
|
|
|
157
89
|
---
|
|
158
90
|
|
package/dist/bin/hightjs.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1
|
+
export default function App(): import("react/jsx-runtime").JSX.Element;
|