nyte 1.0.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/LICENSE +13 -0
- package/README.md +59 -0
- package/dist/adapters/express.d.ts +7 -0
- package/dist/adapters/express.js +63 -0
- package/dist/adapters/factory.d.ts +23 -0
- package/dist/adapters/factory.js +121 -0
- package/dist/adapters/fastify.d.ts +25 -0
- package/dist/adapters/fastify.js +61 -0
- package/dist/adapters/native.d.ts +8 -0
- package/dist/adapters/native.js +200 -0
- package/dist/api/console.d.ts +81 -0
- package/dist/api/console.js +318 -0
- package/dist/api/http.d.ts +180 -0
- package/dist/api/http.js +469 -0
- package/dist/bin/nytejs.d.ts +2 -0
- package/dist/bin/nytejs.js +277 -0
- package/dist/builder.d.ts +32 -0
- package/dist/builder.js +634 -0
- package/dist/client/DefaultNotFound.d.ts +1 -0
- package/dist/client/DefaultNotFound.js +79 -0
- package/dist/client/client.d.ts +4 -0
- package/dist/client/client.js +27 -0
- package/dist/client/clientRouter.d.ts +58 -0
- package/dist/client/clientRouter.js +132 -0
- package/dist/client/entry.client.d.ts +1 -0
- package/dist/client/entry.client.js +455 -0
- package/dist/client/rpc.d.ts +8 -0
- package/dist/client/rpc.js +97 -0
- package/dist/components/Link.d.ts +7 -0
- package/dist/components/Link.js +13 -0
- package/dist/global/global.d.ts +117 -0
- package/dist/global/global.js +17 -0
- package/dist/helpers.d.ts +20 -0
- package/dist/helpers.js +604 -0
- package/dist/hotReload.d.ts +32 -0
- package/dist/hotReload.js +545 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +515 -0
- package/dist/loaders.d.ts +1 -0
- package/dist/loaders.js +138 -0
- package/dist/renderer.d.ts +14 -0
- package/dist/renderer.js +380 -0
- package/dist/router.d.ts +101 -0
- package/dist/router.js +659 -0
- package/dist/rpc/server.d.ts +11 -0
- package/dist/rpc/server.js +166 -0
- package/dist/rpc/types.d.ts +22 -0
- package/dist/rpc/types.js +20 -0
- package/dist/types/framework.d.ts +37 -0
- package/dist/types/framework.js +2 -0
- package/dist/types.d.ts +218 -0
- package/dist/types.js +2 -0
- package/package.json +87 -0
- package/src/adapters/express.ts +87 -0
- package/src/adapters/factory.ts +112 -0
- package/src/adapters/fastify.ts +104 -0
- package/src/adapters/native.ts +245 -0
- package/src/api/console.ts +348 -0
- package/src/api/http.ts +535 -0
- package/src/bin/nytejs.js +331 -0
- package/src/builder.js +690 -0
- package/src/client/DefaultNotFound.tsx +119 -0
- package/src/client/client.ts +24 -0
- package/src/client/clientRouter.ts +153 -0
- package/src/client/entry.client.tsx +529 -0
- package/src/client/rpc.ts +101 -0
- package/src/components/Link.tsx +38 -0
- package/src/global/global.ts +171 -0
- package/src/helpers.ts +657 -0
- package/src/hotReload.ts +566 -0
- package/src/index.ts +582 -0
- package/src/loaders.js +160 -0
- package/src/renderer.tsx +421 -0
- package/src/router.ts +732 -0
- package/src/rpc/server.ts +190 -0
- package/src/rpc/types.ts +45 -0
- package/src/types/framework.ts +58 -0
- package/src/types.ts +288 -0
package/src/loaders.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Nyte.js Project.
|
|
3
|
+
* Copyright (c) 2026 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
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const Module = require('module');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Carrega e processa o tsconfig.json para obter os aliases
|
|
24
|
+
*/
|
|
25
|
+
function loadTsConfigAliases() {
|
|
26
|
+
const projectDir = process.cwd();
|
|
27
|
+
const tsconfigPath = path.join(projectDir, 'tsconfig.json');
|
|
28
|
+
|
|
29
|
+
const aliases = {};
|
|
30
|
+
|
|
31
|
+
if (fs.existsSync(tsconfigPath)) {
|
|
32
|
+
try {
|
|
33
|
+
const tsconfigContent = fs.readFileSync(tsconfigPath, 'utf8');
|
|
34
|
+
|
|
35
|
+
// Remove comentários JSONC de forma mais robusta
|
|
36
|
+
let jsonContent = tsconfigContent
|
|
37
|
+
// Remove comentários de linha // (mas não em strings)
|
|
38
|
+
.replace(/(?:^|\s)\/\/.*$/gm, '')
|
|
39
|
+
// Remove comentários de bloco /* */
|
|
40
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
41
|
+
// Remove vírgulas finais (trailing commas) que JSON não aceita
|
|
42
|
+
.replace(/,(\s*[}\]])/g, '$1');
|
|
43
|
+
|
|
44
|
+
const tsconfig = JSON.parse(jsonContent);
|
|
45
|
+
|
|
46
|
+
if (tsconfig.compilerOptions?.paths) {
|
|
47
|
+
const baseUrl = tsconfig.compilerOptions.baseUrl || '.';
|
|
48
|
+
const basePath = path.resolve(projectDir, baseUrl);
|
|
49
|
+
|
|
50
|
+
// Converte os paths do tsconfig para aliases
|
|
51
|
+
for (const [alias, paths] of Object.entries(tsconfig.compilerOptions.paths)) {
|
|
52
|
+
if (Array.isArray(paths) && paths.length > 0) {
|
|
53
|
+
// Remove o /* do final
|
|
54
|
+
const cleanAlias = alias.replace(/\/\*$/, '');
|
|
55
|
+
const cleanPath = paths[0].replace(/\/\*$/, '');
|
|
56
|
+
aliases[cleanAlias] = path.resolve(basePath, cleanPath);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
// Silenciosamente ignora erros de parsing do tsconfig
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return aliases;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Registra loaders customizados para Node.js
|
|
70
|
+
* Permite importar arquivos não-JS diretamente no servidor
|
|
71
|
+
*/
|
|
72
|
+
function registerLoaders() {
|
|
73
|
+
// Registra resolver de aliases do tsconfig.json
|
|
74
|
+
const aliases = loadTsConfigAliases();
|
|
75
|
+
|
|
76
|
+
if (Object.keys(aliases).length > 0) {
|
|
77
|
+
// Guarda referência ao _resolveFilename atual (pode já ter sido modificado por source-map-support)
|
|
78
|
+
const originalResolveFilename = Module._resolveFilename;
|
|
79
|
+
|
|
80
|
+
Module._resolveFilename = function (request, parent, isMain, options) {
|
|
81
|
+
// Verifica se o request começa com algum alias
|
|
82
|
+
for (const [alias, aliasPath] of Object.entries(aliases)) {
|
|
83
|
+
if (request === alias || request.startsWith(alias + '/')) {
|
|
84
|
+
const relativePath = request.slice(alias.length);
|
|
85
|
+
const resolvedPath = path.join(aliasPath, relativePath);
|
|
86
|
+
|
|
87
|
+
// Tenta resolver com diferentes extensões
|
|
88
|
+
const extensions = ['.tsx', '.ts', '.jsx', '.js'];
|
|
89
|
+
|
|
90
|
+
// Primeiro tenta o caminho exato
|
|
91
|
+
if (fs.existsSync(resolvedPath)) {
|
|
92
|
+
const stats = fs.statSync(resolvedPath);
|
|
93
|
+
if (stats.isFile()) {
|
|
94
|
+
// Retorna o caminho resolvido diretamente
|
|
95
|
+
request = resolvedPath;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Tenta com extensões
|
|
101
|
+
let resolved = false;
|
|
102
|
+
for (const ext of extensions) {
|
|
103
|
+
const pathWithExt = resolvedPath + ext;
|
|
104
|
+
if (fs.existsSync(pathWithExt)) {
|
|
105
|
+
request = pathWithExt;
|
|
106
|
+
resolved = true;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (resolved) break;
|
|
112
|
+
|
|
113
|
+
// Tenta como diretório com index
|
|
114
|
+
for (const ext of extensions) {
|
|
115
|
+
const indexPath = path.join(resolvedPath, 'index' + ext);
|
|
116
|
+
if (fs.existsSync(indexPath)) {
|
|
117
|
+
request = indexPath;
|
|
118
|
+
resolved = true;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (resolved) break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Chama o resolver original (que pode ser do source-map-support)
|
|
128
|
+
return originalResolveFilename.call(this, request, parent, isMain, options);
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Loader para arquivos Markdown (.md)
|
|
133
|
+
require.extensions['.md'] = function (module, filename) {
|
|
134
|
+
const content = fs.readFileSync(filename, 'utf8');
|
|
135
|
+
module.exports = content;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// Loader para arquivos de texto (.txt)
|
|
139
|
+
require.extensions['.txt'] = function (module, filename) {
|
|
140
|
+
const content = fs.readFileSync(filename, 'utf8');
|
|
141
|
+
module.exports = content;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// Loader para arquivos JSON (já existe nativamente, mas garantimos consistência)
|
|
145
|
+
// require.extensions['.json'] já existe
|
|
146
|
+
|
|
147
|
+
// Loader para imagens - retorna o caminho do arquivo
|
|
148
|
+
const imageExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.avif', '.ico', '.bmp', '.svg'];
|
|
149
|
+
|
|
150
|
+
imageExtensions.forEach(ext => {
|
|
151
|
+
require.extensions[ext] = function (module, filename) {
|
|
152
|
+
// No servidor, retornamos o caminho do arquivo
|
|
153
|
+
// O frontend usará o plugin do esbuild para converter em base64
|
|
154
|
+
module.exports = filename;
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
module.exports = { registerLoaders };
|
|
160
|
+
|
package/src/renderer.tsx
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Nyte.js Project.
|
|
3
|
+
* Copyright (c) 2026 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
|
+
import React from 'react';
|
|
18
|
+
import { RouteConfig, Metadata } from './types';
|
|
19
|
+
import { getLayout } from './router';
|
|
20
|
+
import type { GenericRequest } from './types/framework';
|
|
21
|
+
import fs from 'fs';
|
|
22
|
+
import path from 'path';
|
|
23
|
+
|
|
24
|
+
// Função para gerar todas as meta tags
|
|
25
|
+
function generateMetaTags(metadata: Metadata): string {
|
|
26
|
+
const tags: string[] = [];
|
|
27
|
+
|
|
28
|
+
// Charset
|
|
29
|
+
tags.push(`<meta charset="${metadata.charset || 'UTF-8'}">`);
|
|
30
|
+
|
|
31
|
+
// Viewport
|
|
32
|
+
tags.push(`<meta name="viewport" content="${metadata.viewport || 'width=device-width, initial-scale=1.0'}">`);
|
|
33
|
+
|
|
34
|
+
// Description
|
|
35
|
+
if (metadata.description) {
|
|
36
|
+
tags.push(`<meta name="description" content="${metadata.description}">`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Keywords
|
|
40
|
+
if (metadata.keywords) {
|
|
41
|
+
const keywordsStr = Array.isArray(metadata.keywords)
|
|
42
|
+
? metadata.keywords.join(', ')
|
|
43
|
+
: metadata.keywords;
|
|
44
|
+
tags.push(`<meta name="keywords" content="${keywordsStr}">`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Author
|
|
48
|
+
if (metadata.author) {
|
|
49
|
+
tags.push(`<meta name="author" content="${metadata.author}">`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Theme color
|
|
53
|
+
if (metadata.themeColor) {
|
|
54
|
+
tags.push(`<meta name="theme-color" content="${metadata.themeColor}">`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Robots
|
|
58
|
+
if (metadata.robots) {
|
|
59
|
+
tags.push(`<meta name="robots" content="${metadata.robots}">`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Canonical
|
|
63
|
+
if (metadata.canonical) {
|
|
64
|
+
tags.push(`<link rel="canonical" href="${metadata.canonical}">`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Favicon
|
|
68
|
+
if (metadata.favicon) {
|
|
69
|
+
tags.push(`<link rel="icon" href="${metadata.favicon}">`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Apple Touch Icon
|
|
73
|
+
if (metadata.appleTouchIcon) {
|
|
74
|
+
tags.push(`<link rel="apple-touch-icon" href="${metadata.appleTouchIcon}">`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Manifest
|
|
78
|
+
if (metadata.manifest) {
|
|
79
|
+
tags.push(`<link rel="manifest" href="${metadata.manifest}">`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Open Graph
|
|
83
|
+
if (metadata.openGraph) {
|
|
84
|
+
const og = metadata.openGraph;
|
|
85
|
+
if (og.title) tags.push(`<meta property="og:title" content="${og.title}">`);
|
|
86
|
+
if (og.description) tags.push(`<meta property="og:description" content="${og.description}">`);
|
|
87
|
+
if (og.type) tags.push(`<meta property="og:type" content="${og.type}">`);
|
|
88
|
+
if (og.url) tags.push(`<meta property="og:url" content="${og.url}">`);
|
|
89
|
+
if (og.siteName) tags.push(`<meta property="og:site_name" content="${og.siteName}">`);
|
|
90
|
+
if (og.locale) tags.push(`<meta property="og:locale" content="${og.locale}">`);
|
|
91
|
+
|
|
92
|
+
if (og.image) {
|
|
93
|
+
if (typeof og.image === 'string') {
|
|
94
|
+
tags.push(`<meta property="og:image" content="${og.image}">`);
|
|
95
|
+
} else {
|
|
96
|
+
tags.push(`<meta property="og:image" content="${og.image.url}">`);
|
|
97
|
+
if (og.image.width) tags.push(`<meta property="og:image:width" content="${og.image.width}">`);
|
|
98
|
+
if (og.image.height) tags.push(`<meta property="og:image:height" content="${og.image.height}">`);
|
|
99
|
+
if (og.image.alt) tags.push(`<meta property="og:image:alt" content="${og.image.alt}">`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Twitter Card
|
|
105
|
+
if (metadata.twitter) {
|
|
106
|
+
const tw = metadata.twitter;
|
|
107
|
+
if (tw.card) tags.push(`<meta name="twitter:card" content="${tw.card}">`);
|
|
108
|
+
if (tw.site) tags.push(`<meta name="twitter:site" content="${tw.site}">`);
|
|
109
|
+
if (tw.creator) tags.push(`<meta name="twitter:creator" content="${tw.creator}">`);
|
|
110
|
+
if (tw.title) tags.push(`<meta name="twitter:title" content="${tw.title}">`);
|
|
111
|
+
if (tw.description) tags.push(`<meta name="twitter:description" content="${tw.description}">`);
|
|
112
|
+
if (tw.image) tags.push(`<meta name="twitter:image" content="${tw.image}">`);
|
|
113
|
+
if (tw.imageAlt) tags.push(`<meta name="twitter:image:alt" content="${tw.imageAlt}">`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Custom meta tags
|
|
117
|
+
if (metadata.other) {
|
|
118
|
+
for (const [key, value] of Object.entries(metadata.other)) {
|
|
119
|
+
tags.push(`<meta name="${key}" content="${value}">`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return tags.join('\n');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Função para ofuscar dados (não é criptografia, apenas ofuscação)
|
|
127
|
+
function obfuscateData(data: any): string {
|
|
128
|
+
// 1. Serializa para JSON minificado
|
|
129
|
+
const jsonStr = JSON.stringify(data);
|
|
130
|
+
|
|
131
|
+
// 2. Converte para base64
|
|
132
|
+
const base64 = Buffer.from(jsonStr).toString('base64');
|
|
133
|
+
|
|
134
|
+
// 3. Adiciona um hash fake no início para parecer um token
|
|
135
|
+
const hash = Buffer.from(Date.now().toString()).toString('base64').substring(0, 8);
|
|
136
|
+
|
|
137
|
+
return `${hash}.${base64}`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Função para criar script ofuscado
|
|
141
|
+
function createInitialDataScript(data: any): string {
|
|
142
|
+
const obfuscated = obfuscateData(data);
|
|
143
|
+
|
|
144
|
+
// Usa um atributo data-* ao invés de JSON visível
|
|
145
|
+
return `<script id="__nyte_data__" type="text/plain" data-h="${obfuscated}"></script>`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Interface para opções de renderização apenas do cliente
|
|
149
|
+
interface RenderOptions {
|
|
150
|
+
req: GenericRequest;
|
|
151
|
+
route: RouteConfig & { componentPath: string };
|
|
152
|
+
params: Record<string, string>;
|
|
153
|
+
allRoutes: (RouteConfig & { componentPath: string })[];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export async function render({ req, route, params, allRoutes }: RenderOptions): Promise<string> {
|
|
157
|
+
const { generateMetadata } = route;
|
|
158
|
+
|
|
159
|
+
// Pega a opção dev e hot reload manager do req
|
|
160
|
+
const isProduction = !(req as any).hwebDev;
|
|
161
|
+
const hotReloadManager = (req as any).hotReloadManager;
|
|
162
|
+
|
|
163
|
+
// Pega o layout se existir
|
|
164
|
+
const layout = getLayout();
|
|
165
|
+
|
|
166
|
+
let metadata: Metadata = { title: 'App hweb' };
|
|
167
|
+
|
|
168
|
+
// Primeiro usa o metadata do layout se existir
|
|
169
|
+
if (layout && layout.metadata) {
|
|
170
|
+
metadata = { ...metadata, ...layout.metadata };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Depois sobrescreve com metadata específico da rota se existir
|
|
174
|
+
if (generateMetadata) {
|
|
175
|
+
const routeMetadata = await Promise.resolve(generateMetadata(params, req));
|
|
176
|
+
metadata = { ...metadata, ...routeMetadata };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Prepara os dados para injetar na janela do navegador
|
|
180
|
+
const initialData = {
|
|
181
|
+
routes: allRoutes.map(r => ({ pattern: r.pattern, componentPath: r.componentPath })),
|
|
182
|
+
initialComponentPath: route.componentPath,
|
|
183
|
+
initialParams: params,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Cria script JSON limpo
|
|
187
|
+
const initialDataScript = createInitialDataScript(initialData);
|
|
188
|
+
|
|
189
|
+
// Script de hot reload apenas em desenvolvimento
|
|
190
|
+
const hotReloadScript = !isProduction && hotReloadManager
|
|
191
|
+
? hotReloadManager.getClientScript()
|
|
192
|
+
: '';
|
|
193
|
+
|
|
194
|
+
// Gera todas as meta tags
|
|
195
|
+
const metaTags = generateMetaTags(metadata);
|
|
196
|
+
|
|
197
|
+
// Determina quais arquivos JavaScript carregar
|
|
198
|
+
const jsFiles = getJavaScriptFiles(req);
|
|
199
|
+
|
|
200
|
+
const htmlLang = metadata.language || 'pt-BR';
|
|
201
|
+
|
|
202
|
+
// HTML base sem SSR - apenas o container e scripts para client-side rendering
|
|
203
|
+
return `<!DOCTYPE html>
|
|
204
|
+
<html lang="${htmlLang}">
|
|
205
|
+
<head>
|
|
206
|
+
${metaTags}
|
|
207
|
+
<title>${metadata.title || 'App hweb'}</title>
|
|
208
|
+
</head>
|
|
209
|
+
<body>
|
|
210
|
+
<div id="root"></div>
|
|
211
|
+
${initialDataScript}
|
|
212
|
+
${jsFiles}
|
|
213
|
+
${hotReloadScript}
|
|
214
|
+
</body>
|
|
215
|
+
</html>`;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Função para determinar quais arquivos JavaScript carregar
|
|
219
|
+
function getJavaScriptFiles(req: GenericRequest): string {
|
|
220
|
+
const projectDir = process.cwd();
|
|
221
|
+
const distDir = path.join(projectDir, '.nyte');
|
|
222
|
+
|
|
223
|
+
// Verifica se o diretório de build existe
|
|
224
|
+
if (!fs.existsSync(distDir)) {
|
|
225
|
+
// Diretório não existe - build ainda não foi executado
|
|
226
|
+
return getBuildingHTML();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
// Verifica se existe um manifesto de chunks (gerado pelo ESBuild com splitting)
|
|
231
|
+
const manifestPath = path.join(distDir, 'manifest.json');
|
|
232
|
+
|
|
233
|
+
if (fs.existsSync(manifestPath)) {
|
|
234
|
+
// Modo chunks - carrega todos os arquivos necessários
|
|
235
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
236
|
+
const scripts = Object.values(manifest)
|
|
237
|
+
.filter((file: any) => file.endsWith('.js'))
|
|
238
|
+
.map((file: any) => `<script src="/_nyte/${file}"></script>`)
|
|
239
|
+
.join('');
|
|
240
|
+
|
|
241
|
+
// Se não há arquivos JS no manifesto, build em andamento
|
|
242
|
+
if (!scripts) {
|
|
243
|
+
return getBuildingHTML();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return scripts;
|
|
247
|
+
} else {
|
|
248
|
+
// Verifica se existem múltiplos arquivos JS (chunks sem manifesto)
|
|
249
|
+
const jsFiles = fs.readdirSync(distDir)
|
|
250
|
+
.filter(file => file.endsWith('.js') && !file.endsWith('.map'))
|
|
251
|
+
.sort((a, b) => {
|
|
252
|
+
// Ordena para carregar arquivos principais primeiro
|
|
253
|
+
if (a.includes('main')) return -1;
|
|
254
|
+
if (b.includes('main')) return 1;
|
|
255
|
+
if (a.includes('vendor') || a.includes('react')) return -1;
|
|
256
|
+
if (b.includes('vendor') || b.includes('react')) return 1;
|
|
257
|
+
return a.localeCompare(b);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// @ts-ignore
|
|
261
|
+
if (jsFiles.length >= 1) {
|
|
262
|
+
// Modo chunks sem manifesto
|
|
263
|
+
return jsFiles
|
|
264
|
+
.map(file => `<script src="/_nyte/${file}"></script>`)
|
|
265
|
+
.join('');
|
|
266
|
+
} else {
|
|
267
|
+
// Nenhum arquivo JS encontrado - build em andamento ou erro
|
|
268
|
+
return getBuildingHTML();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
} catch (error) {
|
|
272
|
+
// Erro ao ler diretório - build em andamento ou erro
|
|
273
|
+
return getBuildingHTML();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Função para retornar HTML de "Build em andamento" com auto-refresh
|
|
278
|
+
function getBuildingHTML(): string {
|
|
279
|
+
return `
|
|
280
|
+
<style>
|
|
281
|
+
/*
|
|
282
|
+
* Estilo combinado:
|
|
283
|
+
* - Tema (light/dark) adaptativo como o Next.js
|
|
284
|
+
* - Ícone personalizado
|
|
285
|
+
* - Efeito Glassmorphism para o card
|
|
286
|
+
*/
|
|
287
|
+
|
|
288
|
+
html, body {
|
|
289
|
+
margin: 0;
|
|
290
|
+
padding: 0;
|
|
291
|
+
width: 100%;
|
|
292
|
+
height: 100%;
|
|
293
|
+
font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
|
294
|
+
-webkit-font-smoothing: antialiased;
|
|
295
|
+
-moz-osx-font-smoothing: grayscale;
|
|
296
|
+
box-sizing: border-box;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
*, *:before, *:after {
|
|
300
|
+
box-sizing: inherit;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/* Tema Claro (Default) */
|
|
304
|
+
body {
|
|
305
|
+
color: #000;
|
|
306
|
+
background: linear-gradient(to bottom, #e9e9e9, #ffffff);
|
|
307
|
+
background-attachment: fixed;
|
|
308
|
+
|
|
309
|
+
display: flex;
|
|
310
|
+
align-items: center;
|
|
311
|
+
justify-content: center;
|
|
312
|
+
min-height: 100vh;
|
|
313
|
+
text-align: center;
|
|
314
|
+
padding: 20px;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/* Contêiner com Glassmorphism */
|
|
318
|
+
.building-container {
|
|
319
|
+
width: 100%;
|
|
320
|
+
max-width: 500px;
|
|
321
|
+
padding: 40px 50px;
|
|
322
|
+
|
|
323
|
+
/* Efeito de vidro */
|
|
324
|
+
background: rgba(255, 255, 255, 0.15); /* Mais transparente no modo claro */
|
|
325
|
+
backdrop-filter: blur(12px); /* Um pouco mais de blur */
|
|
326
|
+
-webkit-backdrop-filter: blur(12px);
|
|
327
|
+
|
|
328
|
+
border-radius: 16px;
|
|
329
|
+
border: 1px solid rgba(255, 255, 255, 0.3); /* Borda mais visível no claro */
|
|
330
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); /* Sombra mais leve no claro */
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/* Ícone */
|
|
334
|
+
.building-icon {
|
|
335
|
+
width: 70px; /* Tamanho do ícone */
|
|
336
|
+
height: 70px;
|
|
337
|
+
margin-bottom: 20px; /* Espaço abaixo do ícone */
|
|
338
|
+
vertical-align: middle;
|
|
339
|
+
filter: drop-shadow(0 0 5px rgba(0,0,0,0.1)); /* Leve sombra para destacar */
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/* Título */
|
|
343
|
+
.building-title {
|
|
344
|
+
font-size: 2.8rem;
|
|
345
|
+
font-weight: 700;
|
|
346
|
+
margin-top: 0; /* Ajusta a margem superior após o ícone */
|
|
347
|
+
margin-bottom: 20px;
|
|
348
|
+
text-shadow: 0 0 10px rgba(0, 0, 0, 0.05); /* Sombra de texto sutil */
|
|
349
|
+
color: inherit; /* Garante que a cor se adapta ao tema */
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/* Texto de apoio */
|
|
353
|
+
.building-text {
|
|
354
|
+
font-size: 1.15rem;
|
|
355
|
+
margin-bottom: 35px;
|
|
356
|
+
font-weight: 400;
|
|
357
|
+
opacity: 0.9;
|
|
358
|
+
color: inherit; /* Garante que a cor se adapta ao tema */
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* Spinner adaptado para light/dark */
|
|
362
|
+
.spinner {
|
|
363
|
+
width: 50px;
|
|
364
|
+
height: 50px;
|
|
365
|
+
margin: 0 auto;
|
|
366
|
+
border-radius: 50%;
|
|
367
|
+
|
|
368
|
+
/* Estilo para Modo Claro */
|
|
369
|
+
border: 5px solid rgba(0, 0, 0, 0.1);
|
|
370
|
+
border-top-color: #000;
|
|
371
|
+
|
|
372
|
+
animation: spin 1s linear infinite;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/* Animação de rotação */
|
|
376
|
+
@keyframes spin {
|
|
377
|
+
0% { transform: rotate(0deg); }
|
|
378
|
+
100% { transform: rotate(360deg); }
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/* Tema Escuro (via @media query) */
|
|
382
|
+
@media (prefers-color-scheme: dark) {
|
|
383
|
+
body {
|
|
384
|
+
color: #fff;
|
|
385
|
+
background: linear-gradient(to bottom, #222, #000);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.building-container {
|
|
389
|
+
background: rgba(255, 255, 255, 0.05); /* Mais opaco no modo escuro */
|
|
390
|
+
border: 1px solid rgba(255, 255, 255, 0.1); /* Borda mais sutil no escuro */
|
|
391
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); /* Sombra mais forte no escuro */
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.building-title {
|
|
395
|
+
text-shadow: 0 0 10px rgba(255, 255, 255, 0.1);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.building-icon {
|
|
399
|
+
filter: drop-shadow(0 0 5px rgba(255,255,255,0.1));
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.spinner {
|
|
403
|
+
border: 5px solid rgba(255, 255, 255, 0.1);
|
|
404
|
+
border-top-color: #fff;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
</style>
|
|
408
|
+
<div class="building-container">
|
|
409
|
+
<!-- Ícone da imagem --><img src="https://repository-images.githubusercontent.com/1069175740/e5c59d3a-e1fd-446c-a89f-785ed08f6a16" alt="NyteJS Logo" class="building-icon">
|
|
410
|
+
|
|
411
|
+
<div class="building-title">Nyte.js</div>
|
|
412
|
+
<div class="building-text">Build in progress...</div>
|
|
413
|
+
<div class="spinner"></div>
|
|
414
|
+
</div>
|
|
415
|
+
<script>
|
|
416
|
+
// Auto-refresh a cada 2 segundos para verificar se o build terminou
|
|
417
|
+
setTimeout(() => {
|
|
418
|
+
window.location.reload();
|
|
419
|
+
}, 2000);
|
|
420
|
+
</script>`;
|
|
421
|
+
}
|