hightjs 0.3.5 → 0.4.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 +1 -1
- package/dist/builder.js +60 -5
- package/dist/client/entry.client.js +59 -1
- package/dist/hotReload.js +83 -3
- package/dist/index.js +56 -45
- package/docs/checklist.md +1 -1
- package/docs/middlewares.md +1 -1
- package/docs/rotas-backend.md +3 -3
- package/docs/websocket.md +1 -1
- package/example/package-lock.json +1 -1
- package/example/src/backend/routes/auth.ts +3 -0
- package/example/src/{web/backend → backend}/routes/version.ts +1 -1
- package/example/src/web/components/Home.tsx +140 -0
- package/example/src/web/components/LoginPage.tsx +149 -0
- package/example/src/web/routes/index.tsx +1 -141
- package/example/src/web/routes/login.tsx +1 -146
- package/package.json +3 -1
- package/src/builder.js +66 -5
- package/src/client/entry.client.tsx +69 -2
- package/src/hotReload.ts +83 -3
- package/src/index.ts +66 -57
- package/example/src/web/backend/routes/auth.ts +0 -3
- /package/example/src/{auth.ts → backend/auth.ts} +0 -0
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ Caso tenha alguma dúvida, entre em contato por uma das redes abaixo:
|
|
|
34
34
|
|
|
35
35
|
## ✨ Principais Recursos
|
|
36
36
|
|
|
37
|
-
- **Roteamento automático** de páginas [`src/web/routes`] e APIs [`src/
|
|
37
|
+
- **Roteamento automático** de páginas [`src/web/routes`] e APIs [`src/backend/routes`]
|
|
38
38
|
- **React 19** com client-side hydration
|
|
39
39
|
- **TypeScript** first (totalmente tipado)
|
|
40
40
|
- **WebSockets** nativo nas rotas backend
|
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,41 @@ 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
|
+
};
|
|
178
215
|
/**
|
|
179
216
|
* Builds with code splitting into multiple chunks based on module types.
|
|
180
217
|
* @param {string} entryPoint - The path to the entry file.
|
|
@@ -183,8 +220,8 @@ const reactResolvePlugin = {
|
|
|
183
220
|
* @returns {Promise<void>}
|
|
184
221
|
*/
|
|
185
222
|
async function buildWithChunks(entryPoint, outdir, isProduction = false) {
|
|
186
|
-
// limpar diretorio
|
|
187
|
-
|
|
223
|
+
// limpar diretorio, menos a pasta temp
|
|
224
|
+
await cleanDirectoryExcept(outdir, 'temp');
|
|
188
225
|
try {
|
|
189
226
|
await esbuild.build({
|
|
190
227
|
entryPoints: [entryPoint],
|
|
@@ -226,7 +263,7 @@ async function buildWithChunks(entryPoint, outdir, isProduction = false) {
|
|
|
226
263
|
*/
|
|
227
264
|
async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
|
|
228
265
|
// limpar diretorio
|
|
229
|
-
|
|
266
|
+
await cleanDirectoryExcept(outdir, 'temp');
|
|
230
267
|
try {
|
|
231
268
|
// Plugin para notificar quando o build termina
|
|
232
269
|
const buildCompletePlugin = {
|
|
@@ -256,7 +293,7 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
|
|
|
256
293
|
outdir: outdir,
|
|
257
294
|
loader: { '.js': 'jsx', '.ts': 'tsx' },
|
|
258
295
|
external: nodeBuiltIns,
|
|
259
|
-
plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, buildCompletePlugin],
|
|
296
|
+
plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, hmrPlugin, buildCompletePlugin],
|
|
260
297
|
format: 'esm',
|
|
261
298
|
jsx: 'automatic',
|
|
262
299
|
define: {
|
|
@@ -289,7 +326,7 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
|
|
|
289
326
|
async function build(entryPoint, outfile, isProduction = false) {
|
|
290
327
|
// limpar diretorio do outfile
|
|
291
328
|
const outdir = path.dirname(outfile);
|
|
292
|
-
|
|
329
|
+
await cleanDirectoryExcept(outdir, 'temp');
|
|
293
330
|
try {
|
|
294
331
|
await esbuild.build({
|
|
295
332
|
entryPoints: [entryPoint],
|
|
@@ -388,4 +425,22 @@ async function watch(entryPoint, outfile, hotReloadManager = null) {
|
|
|
388
425
|
throw error;
|
|
389
426
|
}
|
|
390
427
|
}
|
|
428
|
+
/**
|
|
429
|
+
* Remove todo o conteúdo de um diretório,
|
|
430
|
+
* exceto a pasta (ou pastas) especificada(s) em excludeFolder.
|
|
431
|
+
*
|
|
432
|
+
* @param {string} dirPath - Caminho do diretório a limpar
|
|
433
|
+
* @param {string|string[]} excludeFolder - Nome ou nomes das pastas a manter
|
|
434
|
+
*/
|
|
435
|
+
async function cleanDirectoryExcept(dirPath, excludeFolder) {
|
|
436
|
+
const excludes = Array.isArray(excludeFolder) ? excludeFolder : [excludeFolder];
|
|
437
|
+
const items = await readdir(dirPath);
|
|
438
|
+
for (const item of items) {
|
|
439
|
+
if (excludes.includes(item))
|
|
440
|
+
continue; // pula as pastas excluídas
|
|
441
|
+
const itemPath = path.join(dirPath, item);
|
|
442
|
+
const info = await stat(itemPath);
|
|
443
|
+
await rm(itemPath, { recursive: info.isDirectory(), force: true });
|
|
444
|
+
}
|
|
445
|
+
}
|
|
391
446
|
module.exports = { build, watch, buildWithChunks, watchWithChunks };
|
|
@@ -55,6 +55,7 @@ const client_1 = require("react-dom/client");
|
|
|
55
55
|
const clientRouter_1 = require("./clientRouter");
|
|
56
56
|
function App({ componentMap, routes, initialComponentPath, initialParams, layoutComponent }) {
|
|
57
57
|
// Estado que guarda o componente a ser renderizado atualmente
|
|
58
|
+
const [hmrTimestamp, setHmrTimestamp] = (0, react_1.useState)(Date.now());
|
|
58
59
|
const [CurrentPageComponent, setCurrentPageComponent] = (0, react_1.useState)(() => {
|
|
59
60
|
// Se for a rota especial __404__, não busca no componentMap
|
|
60
61
|
if (initialComponentPath === '__404__') {
|
|
@@ -63,6 +64,62 @@ function App({ componentMap, routes, initialComponentPath, initialParams, layout
|
|
|
63
64
|
return componentMap[initialComponentPath];
|
|
64
65
|
});
|
|
65
66
|
const [params, setParams] = (0, react_1.useState)(initialParams);
|
|
67
|
+
// HMR: Escuta eventos de hot reload
|
|
68
|
+
(0, react_1.useEffect)(() => {
|
|
69
|
+
// Ativa o sistema de HMR
|
|
70
|
+
window.__HWEB_HMR__ = true;
|
|
71
|
+
const handleHMRUpdate = async (event) => {
|
|
72
|
+
const { file, timestamp } = event.detail;
|
|
73
|
+
const fileName = file ? file.split('/').pop()?.split('\\').pop() : 'unknown';
|
|
74
|
+
console.log('🔥 HMR: Hot reloading...', fileName);
|
|
75
|
+
try {
|
|
76
|
+
// Aguarda um pouco para o esbuild terminar de recompilar
|
|
77
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
78
|
+
// Re-importa o módulo principal com cache busting
|
|
79
|
+
const mainScript = document.querySelector('script[src*="main.js"]');
|
|
80
|
+
if (mainScript) {
|
|
81
|
+
const mainSrc = mainScript.src.split('?')[0];
|
|
82
|
+
const cacheBustedSrc = `${mainSrc}?t=${timestamp}`;
|
|
83
|
+
// Cria novo script
|
|
84
|
+
const newScript = document.createElement('script');
|
|
85
|
+
newScript.type = 'module';
|
|
86
|
+
newScript.src = cacheBustedSrc;
|
|
87
|
+
// Quando o novo script carregar, força re-render
|
|
88
|
+
newScript.onload = () => {
|
|
89
|
+
console.log('✅ HMR: Modules reloaded');
|
|
90
|
+
// Força re-render do componente
|
|
91
|
+
setHmrTimestamp(timestamp);
|
|
92
|
+
// Marca sucesso
|
|
93
|
+
window.__HMR_SUCCESS__ = true;
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
window.__HMR_SUCCESS__ = false;
|
|
96
|
+
}, 3000);
|
|
97
|
+
};
|
|
98
|
+
newScript.onerror = () => {
|
|
99
|
+
console.error('❌ HMR: Failed to reload modules');
|
|
100
|
+
window.__HMR_SUCCESS__ = false;
|
|
101
|
+
};
|
|
102
|
+
// Remove o script antigo e adiciona o novo
|
|
103
|
+
// (não remove para não quebrar o app)
|
|
104
|
+
document.head.appendChild(newScript);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// Se não encontrou o script, apenas força re-render
|
|
108
|
+
console.log('⚡ HMR: Forcing re-render');
|
|
109
|
+
setHmrTimestamp(timestamp);
|
|
110
|
+
window.__HMR_SUCCESS__ = true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
console.error('❌ HMR Error:', error);
|
|
115
|
+
window.__HMR_SUCCESS__ = false;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
window.addEventListener('hmr:component-update', handleHMRUpdate);
|
|
119
|
+
return () => {
|
|
120
|
+
window.removeEventListener('hmr:component-update', handleHMRUpdate);
|
|
121
|
+
};
|
|
122
|
+
}, []);
|
|
66
123
|
const findRouteForPath = (0, react_1.useCallback)((path) => {
|
|
67
124
|
for (const route of routes) {
|
|
68
125
|
const regexPattern = route.pattern
|
|
@@ -138,7 +195,8 @@ function App({ componentMap, routes, initialComponentPath, initialParams, layout
|
|
|
138
195
|
}
|
|
139
196
|
}
|
|
140
197
|
// Renderiza o componente atual (sem Context, usa o router diretamente)
|
|
141
|
-
|
|
198
|
+
// Usa key com timestamp para forçar re-mount durante HMR
|
|
199
|
+
const PageContent = (0, jsx_runtime_1.jsx)(CurrentPageComponent, { params: params }, `page-${hmrTimestamp}`);
|
|
142
200
|
// SEMPRE usa o layout - se não existir, cria um wrapper padrão
|
|
143
201
|
const content = layoutComponent
|
|
144
202
|
? react_1.default.createElement(layoutComponent, { children: PageContent })
|
package/dist/hotReload.js
CHANGED
|
@@ -195,7 +195,7 @@ class HotReloadManager {
|
|
|
195
195
|
filePath.includes('not-found.tsx') ||
|
|
196
196
|
filePath.endsWith('.tsx') ||
|
|
197
197
|
filePath.endsWith('.jsx');
|
|
198
|
-
const isBackendFile = filePath.includes(path.join('src', '
|
|
198
|
+
const isBackendFile = filePath.includes(path.join('src', 'backend')) ||
|
|
199
199
|
(filePath.includes(path.join('src', 'web')) && !isFrontendFile);
|
|
200
200
|
// Limpa o cache do arquivo alterado
|
|
201
201
|
(0, router_1.clearFileCache)(filePath);
|
|
@@ -342,10 +342,11 @@ class HotReloadManager {
|
|
|
342
342
|
|
|
343
343
|
switch(message.type) {
|
|
344
344
|
case 'frontend-reload':
|
|
345
|
-
|
|
345
|
+
handleFrontendReload(message.data);
|
|
346
346
|
break;
|
|
347
347
|
case 'backend-api-reload':
|
|
348
|
-
//
|
|
348
|
+
// Backend sempre precisa recarregar
|
|
349
|
+
console.log('🔄 Backend changed, reloading...');
|
|
349
350
|
window.location.reload();
|
|
350
351
|
break;
|
|
351
352
|
case 'server-restart':
|
|
@@ -357,12 +358,91 @@ class HotReloadManager {
|
|
|
357
358
|
case 'frontend-error':
|
|
358
359
|
console.error('❌ Frontend error:', message.data);
|
|
359
360
|
break;
|
|
361
|
+
case 'hmr-update':
|
|
362
|
+
handleHMRUpdate(message.data);
|
|
363
|
+
break;
|
|
360
364
|
}
|
|
361
365
|
} catch (e) {
|
|
362
366
|
console.error('Erro ao processar mensagem do hot-reload:', e);
|
|
363
367
|
}
|
|
364
368
|
};
|
|
365
369
|
|
|
370
|
+
function handleFrontendReload(data) {
|
|
371
|
+
if (!data || !data.file) {
|
|
372
|
+
window.location.reload();
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const file = data.file.toLowerCase();
|
|
377
|
+
|
|
378
|
+
// Mudanças que exigem reload completo
|
|
379
|
+
const needsFullReload =
|
|
380
|
+
file.includes('layout.tsx') ||
|
|
381
|
+
file.includes('layout.jsx') ||
|
|
382
|
+
file.includes('not-found.tsx') ||
|
|
383
|
+
file.includes('not-found.jsx') ||
|
|
384
|
+
file.endsWith('.css');
|
|
385
|
+
|
|
386
|
+
if (needsFullReload) {
|
|
387
|
+
console.log('⚡ Layout/CSS changed, full reload...');
|
|
388
|
+
window.location.reload();
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Mudanças em rotas: tenta HMR
|
|
393
|
+
if (file.includes('/routes/') || file.includes('\\\\routes\\\\')) {
|
|
394
|
+
console.log('⚡ Route component changed, hot reloading...');
|
|
395
|
+
|
|
396
|
+
// Dispara evento para forçar re-render
|
|
397
|
+
const event = new CustomEvent('hmr:component-update', {
|
|
398
|
+
detail: { file: data.file, timestamp: Date.now() }
|
|
399
|
+
});
|
|
400
|
+
window.dispatchEvent(event);
|
|
401
|
+
|
|
402
|
+
// Aguarda 500ms para ver se o HMR foi bem-sucedido
|
|
403
|
+
setTimeout(() => {
|
|
404
|
+
const hmrSuccess = window.__HMR_SUCCESS__;
|
|
405
|
+
if (!hmrSuccess) {
|
|
406
|
+
console.log('⚠️ HMR failed, falling back to full reload');
|
|
407
|
+
window.location.reload();
|
|
408
|
+
} else {
|
|
409
|
+
console.log('✅ HMR successful!');
|
|
410
|
+
}
|
|
411
|
+
}, 500);
|
|
412
|
+
} else {
|
|
413
|
+
// Outros arquivos: reload completo por segurança
|
|
414
|
+
window.location.reload();
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function handleHMRUpdate(data) {
|
|
419
|
+
console.log('🔥 HMR Update:', data);
|
|
420
|
+
|
|
421
|
+
// Dispara evento customizado para o React capturar
|
|
422
|
+
const event = new CustomEvent('hmr:update', {
|
|
423
|
+
detail: data
|
|
424
|
+
});
|
|
425
|
+
window.dispatchEvent(event);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function attemptHMR(changedFile) {
|
|
429
|
+
// Tenta fazer Hot Module Replacement
|
|
430
|
+
// Dispara evento para o React App capturar
|
|
431
|
+
const event = new CustomEvent('hmr:component-update', {
|
|
432
|
+
detail: { file: changedFile, timestamp: Date.now() }
|
|
433
|
+
});
|
|
434
|
+
window.dispatchEvent(event);
|
|
435
|
+
|
|
436
|
+
// Fallback: se após 2s não houve sucesso, reload
|
|
437
|
+
setTimeout(() => {
|
|
438
|
+
const hmrSuccess = window.__HMR_SUCCESS__;
|
|
439
|
+
if (!hmrSuccess) {
|
|
440
|
+
console.log('⚠️ HMR failed, falling back to full reload');
|
|
441
|
+
window.location.reload();
|
|
442
|
+
}
|
|
443
|
+
}, 2000);
|
|
444
|
+
}
|
|
445
|
+
|
|
366
446
|
ws.onclose = function(event) {
|
|
367
447
|
isConnected = false;
|
|
368
448
|
|
package/dist/index.js
CHANGED
|
@@ -110,48 +110,49 @@ function isLargeProject(projectDir) {
|
|
|
110
110
|
}
|
|
111
111
|
// Função para gerar o arquivo de entrada para o esbuild
|
|
112
112
|
function createEntryFile(projectDir, routes) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
113
|
+
try {
|
|
114
|
+
const tempDir = path_1.default.join(projectDir, '.hight', 'temp');
|
|
115
|
+
fs_1.default.mkdirSync(tempDir, { recursive: true });
|
|
116
|
+
const entryFilePath = path_1.default.join(tempDir, 'entry.client.js');
|
|
117
|
+
// Verifica se há layout
|
|
118
|
+
const layout = (0, router_1.getLayout)();
|
|
119
|
+
// Verifica se há notFound personalizado
|
|
120
|
+
const notFound = (0, router_1.getNotFound)();
|
|
121
|
+
// Gera imports dinâmicos para cada componente
|
|
122
|
+
const imports = routes
|
|
123
|
+
.map((route, index) => {
|
|
124
|
+
const relativePath = path_1.default.relative(tempDir, route.componentPath).replace(/\\/g, '/');
|
|
125
|
+
return `import route${index} from '${relativePath}';`;
|
|
126
|
+
})
|
|
127
|
+
.join('\n');
|
|
128
|
+
// Import do layout se existir
|
|
129
|
+
const layoutImport = layout
|
|
130
|
+
? `import LayoutComponent from '${path_1.default.relative(tempDir, layout.componentPath).replace(/\\/g, '/')}';`
|
|
131
|
+
: '';
|
|
132
|
+
// Import do notFound se existir
|
|
133
|
+
const notFoundImport = notFound
|
|
134
|
+
? `import NotFoundComponent from '${path_1.default.relative(tempDir, notFound.componentPath).replace(/\\/g, '/')}';`
|
|
135
|
+
: '';
|
|
136
|
+
// Registra os componentes no window para o cliente acessar
|
|
137
|
+
const componentRegistration = routes
|
|
138
|
+
.map((route, index) => ` '${route.componentPath}': route${index}.component || route${index}.default?.component,`)
|
|
139
|
+
.join('\n');
|
|
140
|
+
// Registra o layout se existir
|
|
141
|
+
const layoutRegistration = layout
|
|
142
|
+
? `window.__HWEB_LAYOUT__ = LayoutComponent.default || LayoutComponent;`
|
|
143
|
+
: `window.__HWEB_LAYOUT__ = null;`;
|
|
144
|
+
// Registra o notFound se existir
|
|
145
|
+
const notFoundRegistration = notFound
|
|
146
|
+
? `window.__HWEB_NOT_FOUND__ = NotFoundComponent.default || NotFoundComponent;`
|
|
147
|
+
: `window.__HWEB_NOT_FOUND__ = null;`;
|
|
148
|
+
// Caminho correto para o entry.client.tsx
|
|
149
|
+
const sdkDir = path_1.default.dirname(__dirname); // Vai para a pasta pai de src (onde está o hweb-sdk)
|
|
150
|
+
const entryClientPath = path_1.default.join(sdkDir, 'src', 'client', 'entry.client.tsx');
|
|
151
|
+
const relativeEntryPath = path_1.default.relative(tempDir, entryClientPath).replace(/\\/g, '/');
|
|
152
|
+
// Import do DefaultNotFound do SDK
|
|
153
|
+
const defaultNotFoundPath = path_1.default.join(sdkDir, 'src', 'client', 'DefaultNotFound.tsx');
|
|
154
|
+
const relativeDefaultNotFoundPath = path_1.default.relative(tempDir, defaultNotFoundPath).replace(/\\/g, '/');
|
|
155
|
+
const entryContent = `// Arquivo gerado automaticamente pelo hweb
|
|
155
156
|
${imports}
|
|
156
157
|
${layoutImport}
|
|
157
158
|
${notFoundImport}
|
|
@@ -174,8 +175,18 @@ window.__HWEB_DEFAULT_NOT_FOUND__ = DefaultNotFound;
|
|
|
174
175
|
// Importa e executa o entry.client.tsx
|
|
175
176
|
import '${relativeEntryPath}';
|
|
176
177
|
`;
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
try {
|
|
179
|
+
fs_1.default.writeFileSync(entryFilePath, entryContent);
|
|
180
|
+
}
|
|
181
|
+
catch (e) {
|
|
182
|
+
console.error("sdfijnsdfnijfsdijnfsdnijsdfnijfsdnijfsdnijfsdn", e);
|
|
183
|
+
}
|
|
184
|
+
return entryFilePath;
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
console_1.default.error("Error creating entry file:", e);
|
|
188
|
+
throw e;
|
|
189
|
+
}
|
|
179
190
|
}
|
|
180
191
|
function hweb(options) {
|
|
181
192
|
const { dev = true, dir = process.cwd(), port = 3000 } = options;
|
|
@@ -183,7 +194,7 @@ function hweb(options) {
|
|
|
183
194
|
process.hight = options;
|
|
184
195
|
const userWebDir = path_1.default.join(dir, 'src', 'web');
|
|
185
196
|
const userWebRoutesDir = path_1.default.join(userWebDir, 'routes');
|
|
186
|
-
const userBackendRoutesDir = path_1.default.join(
|
|
197
|
+
const userBackendRoutesDir = path_1.default.join(dir, 'src', 'backend', 'routes');
|
|
187
198
|
/**
|
|
188
199
|
* Executa middlewares sequencialmente e depois o handler final
|
|
189
200
|
* @param middlewares Array de middlewares para executar
|
package/docs/checklist.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# ✅ Checklist Mental
|
|
2
2
|
|
|
3
3
|
1. Precisa de página? Crie em `src/web/routes/...`
|
|
4
|
-
2. Precisa de endpoint? Crie em `src/
|
|
4
|
+
2. Precisa de endpoint? Crie em `src/backend/routes/...`
|
|
5
5
|
3. Precisa proteger? Use autenticação nas rotas
|
|
6
6
|
4. Precisa middleware? `middleware.ts` ou `middleware: []` na rota
|
|
7
7
|
5. Metadata? `generateMetadata` ou `metadata` no layout
|
package/docs/middlewares.md
CHANGED
package/docs/rotas-backend.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# 🌐 Rotas Backend
|
|
2
2
|
|
|
3
|
-
Qualquer arquivo em `src/
|
|
3
|
+
Qualquer arquivo em `src/backend/routes` vira endpoint backend.
|
|
4
4
|
O _pattern_ pode ser qualquer caminho, não só `/api/...`!
|
|
5
5
|
|
|
6
6
|
## Exemplo Simples
|
|
7
7
|
|
|
8
|
-
`src/
|
|
8
|
+
`src/backend/routes/version.ts`:
|
|
9
9
|
|
|
10
10
|
```ts
|
|
11
11
|
import { HightJSRequest, HightJSResponse, BackendRouteConfig } from 'hightjs';
|
|
@@ -29,7 +29,7 @@ Defina `GET`, `POST`, `PUT`, `DELETE` (ou só os necessários).
|
|
|
29
29
|
|
|
30
30
|
## Rotas Dinâmicas Backend
|
|
31
31
|
|
|
32
|
-
`src/
|
|
32
|
+
`src/backend/routes/users/[id].ts` → `/users/123`
|
|
33
33
|
|
|
34
34
|
```ts
|
|
35
35
|
import { BackendRouteConfig, HightJSResponse } from "hightjs";
|
package/docs/websocket.md
CHANGED