hightjs 0.4.0 → 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 +139 -4
- 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 +39 -29
- 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 +2 -2
- package/dist/index.js +16 -16
- 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 +36 -31
- 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/backend/auth.ts +0 -42
- package/example/src/backend/routes/auth.ts +0 -3
- package/example/src/backend/routes/version.ts +0 -13
- package/example/src/web/components/Home.tsx +0 -140
- package/example/src/web/components/LoginPage.tsx +0 -149
- package/example/src/web/globals.css +0 -5
- package/example/src/web/layout.tsx +0 -100
- package/example/src/web/routes/index.tsx +0 -13
- package/example/src/web/routes/login.tsx +0 -30
- 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 -472
- package/src/client/DefaultNotFound.tsx +0 -84
- package/src/client/clientRouter.ts +0 -153
- package/src/client/entry.client.tsx +0 -511
- package/src/client.ts +0 -24
- package/src/components/Link.tsx +0 -38
- package/src/helpers.ts +0 -542
- package/src/hotReload.ts +0 -569
- package/src/index.ts +0 -555
- 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/src/bin/hightjs.js
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/*
|
|
4
|
-
* This file is part of the HightJS Project.
|
|
5
|
-
* Copyright (c) 2025 itsmuzin
|
|
6
|
-
*
|
|
7
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
-
* you may not use this file except in compliance with the License.
|
|
9
|
-
* You may obtain a copy of the License at
|
|
10
|
-
*
|
|
11
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
-
*
|
|
13
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
-
* See the License for the specific language governing permissions and
|
|
17
|
-
* limitations under the License.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// Registra o ts-node para que o Node.js entenda TypeScript/TSX
|
|
22
|
-
require('ts-node').register();
|
|
23
|
-
|
|
24
|
-
const { program } = require('commander');
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
program
|
|
28
|
-
.version('1.0.0')
|
|
29
|
-
.description('CLI to manage the application.');
|
|
30
|
-
|
|
31
|
-
// --- Comando DEV ---
|
|
32
|
-
const fs = require('fs');
|
|
33
|
-
const path = require('path');
|
|
34
|
-
// 'program' já deve estar definido no seu arquivo
|
|
35
|
-
// const { program } = require('commander');
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Função centralizada para iniciar a aplicação
|
|
39
|
-
* @param {object} options - Opções vindas do commander
|
|
40
|
-
* @param {boolean} isDev - Define se é modo de desenvolvimento
|
|
41
|
-
*/
|
|
42
|
-
function initializeApp(options, isDev) {
|
|
43
|
-
const appOptions = {
|
|
44
|
-
dev: isDev,
|
|
45
|
-
port: options.port,
|
|
46
|
-
hostname: options.hostname,
|
|
47
|
-
framework: 'native',
|
|
48
|
-
ssl: null, // Default
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// 1. Verifica se a flag --ssl foi ativada
|
|
52
|
-
if (options.ssl) {
|
|
53
|
-
const C = require("../api/console")
|
|
54
|
-
const { Levels } = C;
|
|
55
|
-
const Console = C.default
|
|
56
|
-
const sslDir = path.resolve(process.cwd(), 'certs');
|
|
57
|
-
const keyPath = path.join(sslDir, 'key.pem'); // Padrão 1: key.pem
|
|
58
|
-
const certPath = path.join(sslDir, 'cert.pem'); // Padrão 2: cert.pem
|
|
59
|
-
// (Você pode mudar para 'cert.key' se preferir, apenas ajuste os nomes aqui)
|
|
60
|
-
|
|
61
|
-
// 2. Verifica se os arquivos existem
|
|
62
|
-
if (fs.existsSync(keyPath) && fs.existsSync(certPath)) {
|
|
63
|
-
appOptions.ssl = {
|
|
64
|
-
key: keyPath,
|
|
65
|
-
cert: certPath
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// 3. Adiciona a porta de redirecionamento (útil para o initNativeServer)
|
|
69
|
-
appOptions.ssl.redirectPort = options.httpRedirectPort || 80;
|
|
70
|
-
|
|
71
|
-
} else {
|
|
72
|
-
Console.logWithout(Levels.ERROR, null, `Ensure that './certs/key.pem' and './certs/cert.pem' exist.`, `--ssl flag was used, but the files were not found.`)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
process.exit(1); // Encerra o processo com erro
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// 4. Inicia o helper com as opções
|
|
80
|
-
const teste = require("../helpers");
|
|
81
|
-
const t = teste.default(appOptions);
|
|
82
|
-
t.init();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// --- Comando DEV ---
|
|
86
|
-
program
|
|
87
|
-
.command('dev')
|
|
88
|
-
.description('Starts the application in development mode.')
|
|
89
|
-
.option('-p, --port <number>', 'Specifies the port to run on', '3000')
|
|
90
|
-
.option('-H, --hostname <string>', 'Specifies the hostname to run on', '0.0.0.0')
|
|
91
|
-
.option('--ssl', 'Activates HTTPS/SSL mode (requires ./ssl/key.pem and ./ssl/cert.pem)')
|
|
92
|
-
.option('--http-redirect-port <number>', 'Port for HTTP->HTTPS redirection', '80')
|
|
93
|
-
.action((options) => {
|
|
94
|
-
initializeApp(options, true); // Chama a função com dev: true
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// --- Comando START (Produção) ---
|
|
98
|
-
program
|
|
99
|
-
.command('start')
|
|
100
|
-
.description('Starts the application in production mode.')
|
|
101
|
-
.option('-p, --port <number>', 'Specifies the port to run on', '3000')
|
|
102
|
-
.option('-H, --hostname <string>', 'Specifies the hostname to run on', '0.0.0.0')
|
|
103
|
-
.option('--ssl', 'Activates HTTPS/SSL mode (requires ./ssl/key.pem and ./ssl/cert.pem)')
|
|
104
|
-
.option('--http-redirect-port <number>', 'Port for HTTP->HTTPS redirection', '80')
|
|
105
|
-
.action((options) => {
|
|
106
|
-
initializeApp(options, false); // Chama a função com dev: false
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// --- Comando EXPORT ---
|
|
110
|
-
program
|
|
111
|
-
.command('export')
|
|
112
|
-
.description('Exports the application as static HTML to the "exported" folder.')
|
|
113
|
-
.option('-o, --output <path>', 'Specifies the output directory', 'exported')
|
|
114
|
-
.action(async (options) => {
|
|
115
|
-
const projectDir = process.cwd();
|
|
116
|
-
const exportDir = path.join(projectDir, options.output);
|
|
117
|
-
|
|
118
|
-
console.log('🚀 Starting export...\n');
|
|
119
|
-
|
|
120
|
-
try {
|
|
121
|
-
// 1. Cria a pasta exported (limpa se já existir)
|
|
122
|
-
if (fs.existsSync(exportDir)) {
|
|
123
|
-
console.log('🗑️ Cleaning existing export folder...');
|
|
124
|
-
fs.rmSync(exportDir, { recursive: true, force: true });
|
|
125
|
-
}
|
|
126
|
-
fs.mkdirSync(exportDir, { recursive: true });
|
|
127
|
-
console.log('✅ Export folder created\n');
|
|
128
|
-
|
|
129
|
-
// 2. Inicializa e prepara o build
|
|
130
|
-
console.log('🔨 Building application...');
|
|
131
|
-
const teste = require("../helpers");
|
|
132
|
-
const app = teste.default({ dev: false, port: 3000, hostname: '0.0.0.0', framework: 'native' });
|
|
133
|
-
await app.prepare();
|
|
134
|
-
console.log('✅ Build complete\n');
|
|
135
|
-
|
|
136
|
-
// 3. Copia a pasta .hight para exported
|
|
137
|
-
const distDir = path.join(projectDir, '.hight');
|
|
138
|
-
if (fs.existsSync(distDir)) {
|
|
139
|
-
console.log('📦 Copying JavaScript files...');
|
|
140
|
-
const exportDistDir = path.join(exportDir, '.hight');
|
|
141
|
-
fs.mkdirSync(exportDistDir, { recursive: true });
|
|
142
|
-
|
|
143
|
-
const files = fs.readdirSync(distDir);
|
|
144
|
-
files.forEach(file => {
|
|
145
|
-
fs.copyFileSync(
|
|
146
|
-
path.join(distDir, file),
|
|
147
|
-
path.join(exportDistDir, file)
|
|
148
|
-
);
|
|
149
|
-
});
|
|
150
|
-
console.log('✅ JavaScript files copied\n');
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// 4. Copia a pasta public se existir
|
|
154
|
-
const publicDir = path.join(projectDir, 'public');
|
|
155
|
-
if (fs.existsSync(publicDir)) {
|
|
156
|
-
console.log('📁 Copying public files...');
|
|
157
|
-
const exportPublicDir = path.join(exportDir, 'public');
|
|
158
|
-
|
|
159
|
-
function copyRecursive(src, dest) {
|
|
160
|
-
if (fs.statSync(src).isDirectory()) {
|
|
161
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
162
|
-
fs.readdirSync(src).forEach(file => {
|
|
163
|
-
copyRecursive(path.join(src, file), path.join(dest, file));
|
|
164
|
-
});
|
|
165
|
-
} else {
|
|
166
|
-
fs.copyFileSync(src, dest);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
copyRecursive(publicDir, exportPublicDir);
|
|
171
|
-
console.log('✅ Public files copied\n');
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// 5. Gera o index.html
|
|
175
|
-
console.log('📝 Generating index.html...');
|
|
176
|
-
const { render } = require('../renderer');
|
|
177
|
-
const { loadRoutes, loadLayout, loadNotFound } = require('../router');
|
|
178
|
-
|
|
179
|
-
// Carrega as rotas para gerar o HTML
|
|
180
|
-
const userWebDir = path.join(projectDir, 'src', 'web');
|
|
181
|
-
const userWebRoutesDir = path.join(userWebDir, 'routes');
|
|
182
|
-
|
|
183
|
-
const routes = loadRoutes(userWebRoutesDir);
|
|
184
|
-
loadLayout(userWebDir);
|
|
185
|
-
loadNotFound(userWebDir);
|
|
186
|
-
|
|
187
|
-
// Gera HTML para a rota raiz
|
|
188
|
-
const rootRoute = routes.find(r => r.pattern === '/') || routes[0];
|
|
189
|
-
|
|
190
|
-
if (rootRoute) {
|
|
191
|
-
const mockReq = {
|
|
192
|
-
url: '/',
|
|
193
|
-
method: 'GET',
|
|
194
|
-
headers: { host: 'localhost' },
|
|
195
|
-
hwebDev: false,
|
|
196
|
-
hotReloadManager: null
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
const html = await render({
|
|
200
|
-
req: mockReq,
|
|
201
|
-
route: rootRoute,
|
|
202
|
-
params: {},
|
|
203
|
-
allRoutes: routes
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
const indexPath = path.join(exportDir, 'index.html');
|
|
207
|
-
fs.writeFileSync(indexPath, html, 'utf8');
|
|
208
|
-
console.log('✅ index.html generated\n');
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
console.log('🎉 Export completed successfully!');
|
|
212
|
-
console.log(`📂 Files exported to: ${exportDir}\n`);
|
|
213
|
-
|
|
214
|
-
} catch (error) {
|
|
215
|
-
console.error('❌ Error during export:', error.message);
|
|
216
|
-
process.exit(1);
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
// Faz o "parse" dos argumentos passados na linha de comando
|
|
222
|
-
program.parse(process.argv);
|
package/src/builder.js
DELETED
|
@@ -1,472 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This file is part of the HightJS Project.
|
|
3
|
-
* Copyright (c) 2025 itsmuzin
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/
|
|
17
|
-
const esbuild = require('esbuild');
|
|
18
|
-
const path = require('path');
|
|
19
|
-
const Console = require("./api/console").default
|
|
20
|
-
const fs = require('fs');
|
|
21
|
-
const {readdir, stat} = require("node:fs/promises");
|
|
22
|
-
const {rm} = require("fs-extra");
|
|
23
|
-
// Lista de módulos nativos do Node.js para marcar como externos (apenas os built-ins do Node)
|
|
24
|
-
const nodeBuiltIns = [
|
|
25
|
-
'assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns',
|
|
26
|
-
'domain', 'events', 'fs', 'http', 'https', 'net', 'os', 'path', 'punycode',
|
|
27
|
-
'querystring', 'readline', 'stream', 'string_decoder', 'tls', 'tty', 'url',
|
|
28
|
-
'util', 'v8', 'vm', 'zlib', 'module', 'worker_threads', 'perf_hooks'
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Plugin para processar CSS com PostCSS e Tailwind
|
|
33
|
-
*/
|
|
34
|
-
const postcssPlugin = {
|
|
35
|
-
name: 'postcss-plugin',
|
|
36
|
-
setup(build) {
|
|
37
|
-
build.onLoad({ filter: /\.css$/ }, async (args) => {
|
|
38
|
-
const fs = require('fs');
|
|
39
|
-
const path = require('path');
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
// Lê o CSS original
|
|
43
|
-
let css = await fs.promises.readFile(args.path, 'utf8');
|
|
44
|
-
|
|
45
|
-
// Verifica se tem PostCSS config no projeto
|
|
46
|
-
const projectDir = process.cwd();
|
|
47
|
-
const postcssConfigPath = path.join(projectDir, 'postcss.config.js');
|
|
48
|
-
const postcssConfigMjsPath = path.join(projectDir, 'postcss.config.mjs');
|
|
49
|
-
|
|
50
|
-
let processedCss = css;
|
|
51
|
-
|
|
52
|
-
if (fs.existsSync(postcssConfigPath) || fs.existsSync(postcssConfigMjsPath)) {
|
|
53
|
-
try {
|
|
54
|
-
// Importa PostCSS do projeto (não do SDK)
|
|
55
|
-
const postcssPath = path.join(projectDir, 'node_modules', 'postcss');
|
|
56
|
-
const postcss = require(postcssPath);
|
|
57
|
-
|
|
58
|
-
// Carrega a config do PostCSS
|
|
59
|
-
const configPath = fs.existsSync(postcssConfigPath) ? postcssConfigPath : postcssConfigMjsPath;
|
|
60
|
-
delete require.cache[require.resolve(configPath)];
|
|
61
|
-
const config = require(configPath);
|
|
62
|
-
const postcssConfig = config.default || config;
|
|
63
|
-
|
|
64
|
-
// Resolve plugins do projeto
|
|
65
|
-
const plugins = [];
|
|
66
|
-
|
|
67
|
-
if (postcssConfig.plugins) {
|
|
68
|
-
if (Array.isArray(postcssConfig.plugins)) {
|
|
69
|
-
// Formato array: ["@tailwindcss/postcss"]
|
|
70
|
-
plugins.push(...postcssConfig.plugins.map(plugin => {
|
|
71
|
-
if (typeof plugin === 'string') {
|
|
72
|
-
try {
|
|
73
|
-
// Tenta resolver do node_modules do projeto primeiro
|
|
74
|
-
return require.resolve(plugin, { paths: [projectDir] });
|
|
75
|
-
} catch {
|
|
76
|
-
// Fallback para require direto
|
|
77
|
-
return require(plugin);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return plugin;
|
|
81
|
-
}));
|
|
82
|
-
} else {
|
|
83
|
-
// Formato objeto: { tailwindcss: {}, autoprefixer: {} }
|
|
84
|
-
for (const [pluginName, pluginOptions] of Object.entries(postcssConfig.plugins)) {
|
|
85
|
-
try {
|
|
86
|
-
// Resolve o plugin do projeto
|
|
87
|
-
const resolvedPath = require.resolve(pluginName, { paths: [projectDir] });
|
|
88
|
-
const pluginModule = require(resolvedPath);
|
|
89
|
-
plugins.push(pluginModule(pluginOptions || {}));
|
|
90
|
-
} catch (error) {
|
|
91
|
-
Console.warn(`Unable to load plugin ${pluginName}:`, error.message);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Processa o CSS com PostCSS
|
|
98
|
-
const result = await postcss(plugins)
|
|
99
|
-
.process(css, {
|
|
100
|
-
from: args.path,
|
|
101
|
-
to: args.path.replace(/\.css$/, '.processed.css')
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
processedCss = result.css;
|
|
105
|
-
|
|
106
|
-
} catch (postcssError) {
|
|
107
|
-
Console.warn(`Error processing CSS with PostCSS:`, postcssError.message);
|
|
108
|
-
Console.warn(`Using raw CSS without processing.`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
contents: `
|
|
114
|
-
const css = ${JSON.stringify(processedCss)};
|
|
115
|
-
if (typeof document !== 'undefined') {
|
|
116
|
-
const style = document.createElement('style');
|
|
117
|
-
style.textContent = css;
|
|
118
|
-
document.head.appendChild(style);
|
|
119
|
-
}
|
|
120
|
-
export default css;
|
|
121
|
-
`,
|
|
122
|
-
loader: 'js'
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
} catch (error) {
|
|
126
|
-
Console.error(`Erro ao processar CSS ${args.path}:`, error);
|
|
127
|
-
return {
|
|
128
|
-
contents: `export default "";`,
|
|
129
|
-
loader: 'js'
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Plugin para resolver dependências npm no frontend
|
|
138
|
-
*/
|
|
139
|
-
const npmDependenciesPlugin = {
|
|
140
|
-
name: 'npm-dependencies',
|
|
141
|
-
setup(build) {
|
|
142
|
-
// Permite que dependências npm sejam bundladas (não marcadas como external)
|
|
143
|
-
build.onResolve({ filter: /^[^./]/ }, (args) => {
|
|
144
|
-
// Se for um módulo built-in do Node.js, marca como external
|
|
145
|
-
if (nodeBuiltIns.includes(args.path)) {
|
|
146
|
-
return { path: args.path, external: true };
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Para dependências npm (axios, lodash, react, react-dom, etc), deixa o esbuild resolver normalmente
|
|
150
|
-
// Isso permite que sejam bundladas no frontend
|
|
151
|
-
return null;
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Plugin para garantir que React seja corretamente resolvido
|
|
158
|
-
*/
|
|
159
|
-
const reactResolvePlugin = {
|
|
160
|
-
name: 'react-resolve',
|
|
161
|
-
setup(build) {
|
|
162
|
-
// Força o uso de uma única instância do React do projeto
|
|
163
|
-
build.onResolve({ filter: /^react$/ }, (args) => {
|
|
164
|
-
const reactPath = require.resolve('react', { paths: [process.cwd()] });
|
|
165
|
-
return {
|
|
166
|
-
path: reactPath
|
|
167
|
-
};
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
build.onResolve({ filter: /^react-dom$/ }, (args) => {
|
|
171
|
-
const reactDomPath = require.resolve('react-dom', { paths: [process.cwd()] });
|
|
172
|
-
return {
|
|
173
|
-
path: reactDomPath
|
|
174
|
-
};
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
build.onResolve({ filter: /^react\/jsx-runtime$/ }, (args) => {
|
|
178
|
-
const jsxRuntimePath = require.resolve('react/jsx-runtime', { paths: [process.cwd()] });
|
|
179
|
-
return {
|
|
180
|
-
path: jsxRuntimePath
|
|
181
|
-
};
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
// Também resolve react-dom/client para React 18+
|
|
185
|
-
build.onResolve({ filter: /^react-dom\/client$/ }, (args) => {
|
|
186
|
-
const clientPath = require.resolve('react-dom/client', { paths: [process.cwd()] });
|
|
187
|
-
return {
|
|
188
|
-
path: clientPath
|
|
189
|
-
};
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Plugin para adicionar suporte a HMR (Hot Module Replacement)
|
|
196
|
-
*/
|
|
197
|
-
const hmrPlugin = {
|
|
198
|
-
name: 'hmr-plugin',
|
|
199
|
-
setup(build) {
|
|
200
|
-
// Adiciona runtime de HMR para arquivos TSX/JSX
|
|
201
|
-
build.onLoad({ filter: /\.(tsx|jsx)$/ }, async (args) => {
|
|
202
|
-
// Ignora arquivos de node_modules
|
|
203
|
-
if (args.path.includes('node_modules')) {
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const fs = require('fs');
|
|
208
|
-
const contents = await fs.promises.readFile(args.path, 'utf8');
|
|
209
|
-
|
|
210
|
-
// Adiciona código de HMR apenas em componentes de rota
|
|
211
|
-
if (args.path.includes('/routes/') || args.path.includes('\\routes\\')) {
|
|
212
|
-
const hmrCode = `
|
|
213
|
-
// HMR Runtime
|
|
214
|
-
if (typeof window !== 'undefined' && window.__HWEB_HMR__) {
|
|
215
|
-
const moduleId = ${JSON.stringify(args.path)};
|
|
216
|
-
if (!window.__HWEB_HMR_MODULES__) {
|
|
217
|
-
window.__HWEB_HMR_MODULES__ = new Map();
|
|
218
|
-
}
|
|
219
|
-
window.__HWEB_HMR_MODULES__.set(moduleId, module.exports);
|
|
220
|
-
}
|
|
221
|
-
`;
|
|
222
|
-
return {
|
|
223
|
-
contents: contents + '\n' + hmrCode,
|
|
224
|
-
loader: 'tsx'
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return null;
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Builds with code splitting into multiple chunks based on module types.
|
|
235
|
-
* @param {string} entryPoint - The path to the entry file.
|
|
236
|
-
* @param {string} outdir - The directory for output files.
|
|
237
|
-
* @param {boolean} isProduction - Se está em modo produção ou não.
|
|
238
|
-
* @returns {Promise<void>}
|
|
239
|
-
*/
|
|
240
|
-
async function buildWithChunks(entryPoint, outdir, isProduction = false) {
|
|
241
|
-
// limpar diretorio, menos a pasta temp
|
|
242
|
-
await cleanDirectoryExcept(outdir, 'temp');
|
|
243
|
-
|
|
244
|
-
try {
|
|
245
|
-
await esbuild.build({
|
|
246
|
-
entryPoints: [entryPoint],
|
|
247
|
-
bundle: true,
|
|
248
|
-
minify: isProduction,
|
|
249
|
-
sourcemap: !isProduction,
|
|
250
|
-
platform: 'browser',
|
|
251
|
-
outdir: outdir,
|
|
252
|
-
loader: { '.js': 'jsx', '.ts': 'tsx' },
|
|
253
|
-
external: nodeBuiltIns,
|
|
254
|
-
plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin],
|
|
255
|
-
format: 'esm', // ESM suporta melhor o code splitting
|
|
256
|
-
jsx: 'automatic',
|
|
257
|
-
define: {
|
|
258
|
-
'process.env.NODE_ENV': isProduction ? '"production"' : '"development"'
|
|
259
|
-
},
|
|
260
|
-
conditions: ['development'],
|
|
261
|
-
mainFields: ['browser', 'module', 'main'],
|
|
262
|
-
resolveExtensions: ['.tsx', '.ts', '.jsx', '.js'],
|
|
263
|
-
splitting: true,
|
|
264
|
-
chunkNames: 'chunks/[name]-[hash]',
|
|
265
|
-
// Força o nome do entry para main(.js) ou main-[hash].js em prod
|
|
266
|
-
entryNames: isProduction ? 'main-[hash]' : 'main',
|
|
267
|
-
keepNames: true,
|
|
268
|
-
treeShaking: true,
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
} catch (error) {
|
|
272
|
-
console.error('An error occurred while building:', error);
|
|
273
|
-
process.exit(1);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Watches with code splitting enabled
|
|
279
|
-
* @param {string} entryPoint - The path to the entry file.
|
|
280
|
-
* @param {string} outdir - The directory for output files.
|
|
281
|
-
* @param {Object} hotReloadManager - Manager de hot reload (opcional).
|
|
282
|
-
* @returns {Promise<void>}
|
|
283
|
-
*/
|
|
284
|
-
async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
|
|
285
|
-
// limpar diretorio
|
|
286
|
-
await cleanDirectoryExcept(outdir, 'temp');
|
|
287
|
-
try {
|
|
288
|
-
// Plugin para notificar quando o build termina
|
|
289
|
-
const buildCompletePlugin = {
|
|
290
|
-
name: 'build-complete',
|
|
291
|
-
setup(build) {
|
|
292
|
-
let isFirstBuild = true;
|
|
293
|
-
build.onEnd((result) => {
|
|
294
|
-
if (hotReloadManager) {
|
|
295
|
-
if (isFirstBuild) {
|
|
296
|
-
isFirstBuild = false;
|
|
297
|
-
hotReloadManager.onBuildComplete(true);
|
|
298
|
-
} else {
|
|
299
|
-
// Notifica o hot reload manager que o build foi concluído
|
|
300
|
-
hotReloadManager.onBuildComplete(result.errors.length === 0);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
const context = await esbuild.context({
|
|
308
|
-
entryPoints: [entryPoint],
|
|
309
|
-
bundle: true,
|
|
310
|
-
minify: false,
|
|
311
|
-
sourcemap: true,
|
|
312
|
-
platform: 'browser',
|
|
313
|
-
outdir: outdir,
|
|
314
|
-
loader: { '.js': 'jsx', '.ts': 'tsx' },
|
|
315
|
-
external: nodeBuiltIns,
|
|
316
|
-
plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, hmrPlugin, buildCompletePlugin],
|
|
317
|
-
format: 'esm',
|
|
318
|
-
jsx: 'automatic',
|
|
319
|
-
define: {
|
|
320
|
-
'process.env.NODE_ENV': '"development"'
|
|
321
|
-
},
|
|
322
|
-
conditions: ['development'],
|
|
323
|
-
mainFields: ['browser', 'module', 'main'],
|
|
324
|
-
resolveExtensions: ['.tsx', '.ts', '.jsx', '.js'],
|
|
325
|
-
splitting: true,
|
|
326
|
-
chunkNames: 'chunks/[name]-[hash]',
|
|
327
|
-
entryNames: 'main',
|
|
328
|
-
keepNames: true,
|
|
329
|
-
treeShaking: true,
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
await context.watch();
|
|
333
|
-
} catch (error) {
|
|
334
|
-
console.error(error)
|
|
335
|
-
Console.error('Error starting watch mode with chunks:', error);
|
|
336
|
-
throw error;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* Builds a single entry point into a single output file.
|
|
342
|
-
* @param {string} entryPoint - The path to the entry file.
|
|
343
|
-
* @param {string} outfile - The full path to the output file.
|
|
344
|
-
* @param {boolean} isProduction - Se está em modo produção ou não.
|
|
345
|
-
* @returns {Promise<void>}
|
|
346
|
-
*/
|
|
347
|
-
async function build(entryPoint, outfile, isProduction = false) {
|
|
348
|
-
// limpar diretorio do outfile
|
|
349
|
-
const outdir = path.dirname(outfile);
|
|
350
|
-
await cleanDirectoryExcept(outdir, 'temp');
|
|
351
|
-
|
|
352
|
-
try {
|
|
353
|
-
await esbuild.build({
|
|
354
|
-
entryPoints: [entryPoint],
|
|
355
|
-
bundle: true,
|
|
356
|
-
minify: isProduction,
|
|
357
|
-
sourcemap: !isProduction, // Só gera sourcemap em dev
|
|
358
|
-
platform: 'browser',
|
|
359
|
-
outfile: outfile,
|
|
360
|
-
loader: { '.js': 'jsx', '.ts': 'tsx' },
|
|
361
|
-
external: nodeBuiltIns,
|
|
362
|
-
plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin],
|
|
363
|
-
format: 'iife',
|
|
364
|
-
globalName: 'HwebApp',
|
|
365
|
-
jsx: 'automatic',
|
|
366
|
-
define: {
|
|
367
|
-
'process.env.NODE_ENV': isProduction ? '"production"' : '"development"'
|
|
368
|
-
},
|
|
369
|
-
// Configurações específicas para React 19
|
|
370
|
-
conditions: ['development'],
|
|
371
|
-
mainFields: ['browser', 'module', 'main'],
|
|
372
|
-
resolveExtensions: ['.tsx', '.ts', '.jsx', '.js'],
|
|
373
|
-
// Garante que não há duplicação de dependências
|
|
374
|
-
splitting: false,
|
|
375
|
-
// Preserva nomes de funções e comportamento
|
|
376
|
-
keepNames: true,
|
|
377
|
-
// Remove otimizações que podem causar problemas com hooks
|
|
378
|
-
treeShaking: true,
|
|
379
|
-
drop: [], // Não remove nada automaticamente
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
} catch (error) {
|
|
383
|
-
console.error('An error occurred during build:', error);
|
|
384
|
-
process.exit(1);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Watches an entry point and its dependencies, rebuilding to a single output file.
|
|
390
|
-
* @param {string} entryPoint - The path to the entry file.
|
|
391
|
-
* @param {string} outfile - The full path to the output file.
|
|
392
|
-
* @param {Object} hotReloadManager - Manager de hot reload (opcional).
|
|
393
|
-
* @returns {Promise<void>}
|
|
394
|
-
*/
|
|
395
|
-
async function watch(entryPoint, outfile, hotReloadManager = null) {
|
|
396
|
-
try {
|
|
397
|
-
// Plugin para notificar quando o build termina
|
|
398
|
-
const buildCompletePlugin = {
|
|
399
|
-
name: 'build-complete',
|
|
400
|
-
setup(build) {
|
|
401
|
-
let isFirstBuild = true;
|
|
402
|
-
build.onEnd((result) => {
|
|
403
|
-
if (hotReloadManager) {
|
|
404
|
-
if (isFirstBuild) {
|
|
405
|
-
isFirstBuild = false;
|
|
406
|
-
hotReloadManager.onBuildComplete(true);
|
|
407
|
-
} else {
|
|
408
|
-
// Notifica o hot reload manager que o build foi concluído
|
|
409
|
-
hotReloadManager.onBuildComplete(result.errors.length === 0);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
};
|
|
415
|
-
|
|
416
|
-
const context = await esbuild.context({
|
|
417
|
-
entryPoints: [entryPoint],
|
|
418
|
-
bundle: true,
|
|
419
|
-
minify: false,
|
|
420
|
-
sourcemap: true,
|
|
421
|
-
platform: 'browser',
|
|
422
|
-
outfile: outfile,
|
|
423
|
-
loader: { '.js': 'jsx', '.ts': 'tsx' },
|
|
424
|
-
external: nodeBuiltIns,
|
|
425
|
-
plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, buildCompletePlugin],
|
|
426
|
-
format: 'iife',
|
|
427
|
-
globalName: 'HwebApp',
|
|
428
|
-
jsx: 'automatic',
|
|
429
|
-
define: {
|
|
430
|
-
'process.env.NODE_ENV': '"development"'
|
|
431
|
-
},
|
|
432
|
-
// Configurações específicas para React 19 (mesmo que no build)
|
|
433
|
-
conditions: ['development'],
|
|
434
|
-
mainFields: ['browser', 'module', 'main'],
|
|
435
|
-
resolveExtensions: ['.tsx', '.ts', '.jsx', '.js'],
|
|
436
|
-
// Garante que não há duplicação de dependências
|
|
437
|
-
splitting: false,
|
|
438
|
-
// Preserva nomes de funções e comportamento
|
|
439
|
-
keepNames: true,
|
|
440
|
-
// Remove otimizações que podem causar problemas com hooks
|
|
441
|
-
treeShaking: true,
|
|
442
|
-
});
|
|
443
|
-
|
|
444
|
-
// Configura o watcher do esbuild
|
|
445
|
-
await context.watch();
|
|
446
|
-
} catch (error) {
|
|
447
|
-
Console.error('Error starting watch mode:', error);
|
|
448
|
-
throw error;
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* Remove todo o conteúdo de um diretório,
|
|
453
|
-
* exceto a pasta (ou pastas) especificada(s) em excludeFolder.
|
|
454
|
-
*
|
|
455
|
-
* @param {string} dirPath - Caminho do diretório a limpar
|
|
456
|
-
* @param {string|string[]} excludeFolder - Nome ou nomes das pastas a manter
|
|
457
|
-
*/
|
|
458
|
-
async function cleanDirectoryExcept(dirPath, excludeFolder) {
|
|
459
|
-
const excludes = Array.isArray(excludeFolder) ? excludeFolder : [excludeFolder];
|
|
460
|
-
|
|
461
|
-
const items = await readdir(dirPath);
|
|
462
|
-
|
|
463
|
-
for (const item of items) {
|
|
464
|
-
if (excludes.includes(item)) continue; // pula as pastas excluídas
|
|
465
|
-
|
|
466
|
-
const itemPath = path.join(dirPath, item);
|
|
467
|
-
const info = await stat(itemPath);
|
|
468
|
-
|
|
469
|
-
await rm(itemPath, { recursive: info.isDirectory(), force: true });
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
module.exports = { build, watch, buildWithChunks, watchWithChunks };
|