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.
Files changed (78) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +59 -0
  3. package/dist/adapters/express.d.ts +7 -0
  4. package/dist/adapters/express.js +63 -0
  5. package/dist/adapters/factory.d.ts +23 -0
  6. package/dist/adapters/factory.js +121 -0
  7. package/dist/adapters/fastify.d.ts +25 -0
  8. package/dist/adapters/fastify.js +61 -0
  9. package/dist/adapters/native.d.ts +8 -0
  10. package/dist/adapters/native.js +200 -0
  11. package/dist/api/console.d.ts +81 -0
  12. package/dist/api/console.js +318 -0
  13. package/dist/api/http.d.ts +180 -0
  14. package/dist/api/http.js +469 -0
  15. package/dist/bin/nytejs.d.ts +2 -0
  16. package/dist/bin/nytejs.js +277 -0
  17. package/dist/builder.d.ts +32 -0
  18. package/dist/builder.js +634 -0
  19. package/dist/client/DefaultNotFound.d.ts +1 -0
  20. package/dist/client/DefaultNotFound.js +79 -0
  21. package/dist/client/client.d.ts +4 -0
  22. package/dist/client/client.js +27 -0
  23. package/dist/client/clientRouter.d.ts +58 -0
  24. package/dist/client/clientRouter.js +132 -0
  25. package/dist/client/entry.client.d.ts +1 -0
  26. package/dist/client/entry.client.js +455 -0
  27. package/dist/client/rpc.d.ts +8 -0
  28. package/dist/client/rpc.js +97 -0
  29. package/dist/components/Link.d.ts +7 -0
  30. package/dist/components/Link.js +13 -0
  31. package/dist/global/global.d.ts +117 -0
  32. package/dist/global/global.js +17 -0
  33. package/dist/helpers.d.ts +20 -0
  34. package/dist/helpers.js +604 -0
  35. package/dist/hotReload.d.ts +32 -0
  36. package/dist/hotReload.js +545 -0
  37. package/dist/index.d.ts +18 -0
  38. package/dist/index.js +515 -0
  39. package/dist/loaders.d.ts +1 -0
  40. package/dist/loaders.js +138 -0
  41. package/dist/renderer.d.ts +14 -0
  42. package/dist/renderer.js +380 -0
  43. package/dist/router.d.ts +101 -0
  44. package/dist/router.js +659 -0
  45. package/dist/rpc/server.d.ts +11 -0
  46. package/dist/rpc/server.js +166 -0
  47. package/dist/rpc/types.d.ts +22 -0
  48. package/dist/rpc/types.js +20 -0
  49. package/dist/types/framework.d.ts +37 -0
  50. package/dist/types/framework.js +2 -0
  51. package/dist/types.d.ts +218 -0
  52. package/dist/types.js +2 -0
  53. package/package.json +87 -0
  54. package/src/adapters/express.ts +87 -0
  55. package/src/adapters/factory.ts +112 -0
  56. package/src/adapters/fastify.ts +104 -0
  57. package/src/adapters/native.ts +245 -0
  58. package/src/api/console.ts +348 -0
  59. package/src/api/http.ts +535 -0
  60. package/src/bin/nytejs.js +331 -0
  61. package/src/builder.js +690 -0
  62. package/src/client/DefaultNotFound.tsx +119 -0
  63. package/src/client/client.ts +24 -0
  64. package/src/client/clientRouter.ts +153 -0
  65. package/src/client/entry.client.tsx +529 -0
  66. package/src/client/rpc.ts +101 -0
  67. package/src/components/Link.tsx +38 -0
  68. package/src/global/global.ts +171 -0
  69. package/src/helpers.ts +657 -0
  70. package/src/hotReload.ts +566 -0
  71. package/src/index.ts +582 -0
  72. package/src/loaders.js +160 -0
  73. package/src/renderer.tsx +421 -0
  74. package/src/router.ts +732 -0
  75. package/src/rpc/server.ts +190 -0
  76. package/src/rpc/types.ts +45 -0
  77. package/src/types/framework.ts +58 -0
  78. package/src/types.ts +288 -0
@@ -0,0 +1,634 @@
1
+ "use strict";
2
+ /*
3
+ * This file is part of the Nyte.js Project.
4
+ * Copyright (c) 2026 itsmuzin
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+ const esbuild = require('esbuild');
19
+ const path = require('path');
20
+ const Console = require("./api/console").default;
21
+ const fs = require('fs');
22
+ const { readdir, stat } = require("node:fs/promises");
23
+ const { rm } = require("fs-extra");
24
+ // Lista de módulos nativos do Node.js para marcar como externos (apenas os built-ins do Node)
25
+ const nodeBuiltIns = [
26
+ 'assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns',
27
+ 'domain', 'events', 'fs', 'http', 'https', 'net', 'os', 'path', 'punycode',
28
+ 'querystring', 'readline', 'stream', 'string_decoder', 'tls', 'tty', 'url',
29
+ 'util', 'v8', 'vm', 'zlib', 'module', 'worker_threads', 'perf_hooks'
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
+ try {
41
+ // Lê o CSS original
42
+ let css = await fs.promises.readFile(args.path, 'utf8');
43
+ // Verifica se tem PostCSS config no projeto
44
+ const projectDir = process.cwd();
45
+ const postcssConfigPath = path.join(projectDir, 'postcss.config.js');
46
+ const postcssConfigMjsPath = path.join(projectDir, 'postcss.config.mjs');
47
+ let processedCss = css;
48
+ if (fs.existsSync(postcssConfigPath) || fs.existsSync(postcssConfigMjsPath)) {
49
+ try {
50
+ // Importa PostCSS do projeto (não do SDK)
51
+ const postcssPath = path.join(projectDir, 'node_modules', 'postcss');
52
+ const postcss = require(postcssPath);
53
+ // Carrega a config do PostCSS
54
+ const configPath = fs.existsSync(postcssConfigPath) ? postcssConfigPath : postcssConfigMjsPath;
55
+ delete require.cache[require.resolve(configPath)];
56
+ const config = require(configPath);
57
+ const postcssConfig = config.default || config;
58
+ // Resolve plugins do projeto
59
+ const plugins = [];
60
+ if (postcssConfig.plugins) {
61
+ if (Array.isArray(postcssConfig.plugins)) {
62
+ // Formato array: ["@tailwindcss/postcss"]
63
+ plugins.push(...postcssConfig.plugins.map(plugin => {
64
+ if (typeof plugin === 'string') {
65
+ try {
66
+ // Tenta resolver do node_modules do projeto primeiro
67
+ return require.resolve(plugin, { paths: [projectDir] });
68
+ }
69
+ catch {
70
+ // Fallback para require direto
71
+ return require(plugin);
72
+ }
73
+ }
74
+ return plugin;
75
+ }));
76
+ }
77
+ else {
78
+ // Formato objeto: { tailwindcss: {}, autoprefixer: {} }
79
+ for (const [pluginName, pluginOptions] of Object.entries(postcssConfig.plugins)) {
80
+ try {
81
+ // Resolve o plugin do projeto
82
+ const resolvedPath = require.resolve(pluginName, { paths: [projectDir] });
83
+ const pluginModule = require(resolvedPath);
84
+ plugins.push(pluginModule(pluginOptions || {}));
85
+ }
86
+ catch (error) {
87
+ Console.warn(`Unable to load plugin ${pluginName}:`, error.message);
88
+ }
89
+ }
90
+ }
91
+ }
92
+ // Processa o CSS com PostCSS
93
+ const result = await postcss(plugins)
94
+ .process(css, {
95
+ from: args.path,
96
+ to: args.path.replace(/\.css$/, '.processed.css')
97
+ });
98
+ processedCss = result.css;
99
+ }
100
+ catch (postcssError) {
101
+ Console.warn(`Error processing CSS with PostCSS:`, postcssError.message);
102
+ Console.warn(`Using raw CSS without processing.`);
103
+ }
104
+ }
105
+ return {
106
+ contents: `
107
+ const css = ${JSON.stringify(processedCss)};
108
+ if (typeof document !== 'undefined') {
109
+ const style = document.createElement('style');
110
+ style.textContent = css;
111
+ document.head.appendChild(style);
112
+ }
113
+ export default css;
114
+ `,
115
+ loader: 'js'
116
+ };
117
+ }
118
+ catch (error) {
119
+ Console.error(`Erro ao processar CSS ${args.path}:`, error);
120
+ return {
121
+ contents: `export default "";`,
122
+ loader: 'js'
123
+ };
124
+ }
125
+ });
126
+ }
127
+ };
128
+ /**
129
+ * Plugin para resolver dependências npm no frontend
130
+ */
131
+ const npmDependenciesPlugin = {
132
+ name: 'npm-dependencies',
133
+ setup(build) {
134
+ // Permite que dependências npm sejam bundladas (não marcadas como external)
135
+ build.onResolve({ filter: /^[^./]/ }, (args) => {
136
+ // Se for um módulo built-in do Node.js, marca como external
137
+ if (nodeBuiltIns.includes(args.path)) {
138
+ return { path: args.path, external: true };
139
+ }
140
+ // Para dependências npm (axios, lodash, react, react-dom, etc), deixa o esbuild resolver normalmente
141
+ // Isso permite que sejam bundladas no frontend
142
+ return null;
143
+ });
144
+ }
145
+ };
146
+ /**
147
+ * Plugin para resolver aliases do tsconfig.json (como @/)
148
+ */
149
+ const aliasResolvePlugin = {
150
+ name: 'alias-resolve',
151
+ setup(build) {
152
+ const projectDir = process.cwd();
153
+ const tsconfigPath = path.join(projectDir, 'tsconfig.json');
154
+ let aliases = {};
155
+ // Lê o tsconfig.json para pegar os paths
156
+ if (fs.existsSync(tsconfigPath)) {
157
+ try {
158
+ const tsconfigContent = fs.readFileSync(tsconfigPath, 'utf8');
159
+ // Remove comentários do JSON (tsconfig pode ter comentários)
160
+ const jsonContent = tsconfigContent.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
161
+ const tsconfig = JSON.parse(jsonContent);
162
+ if (tsconfig.compilerOptions?.paths) {
163
+ const baseUrl = tsconfig.compilerOptions.baseUrl || '.';
164
+ const basePath = path.resolve(projectDir, baseUrl);
165
+ // Converte os paths do tsconfig para aliases
166
+ for (const [alias, paths] of Object.entries(tsconfig.compilerOptions.paths)) {
167
+ if (Array.isArray(paths) && paths.length > 0) {
168
+ // Remove o /* do final do alias e do path
169
+ const cleanAlias = alias.replace(/\/\*$/, '');
170
+ const cleanPath = paths[0].replace(/\/\*$/, '');
171
+ aliases[cleanAlias] = path.resolve(basePath, cleanPath);
172
+ }
173
+ }
174
+ }
175
+ }
176
+ catch (error) {
177
+ Console.warn('Error reading tsconfig.json for aliases:', error.message);
178
+ }
179
+ }
180
+ // Se tem aliases configurados, resolve eles
181
+ if (Object.keys(aliases).length > 0) {
182
+ build.onResolve({ filter: /.*/ }, (args) => {
183
+ // Verifica se o import começa com algum alias
184
+ for (const [alias, aliasPath] of Object.entries(aliases)) {
185
+ if (args.path === alias || args.path.startsWith(alias + '/')) {
186
+ const relativePath = args.path.slice(alias.length);
187
+ const resolvedPath = path.join(aliasPath, relativePath);
188
+ return {
189
+ path: resolvedPath
190
+ };
191
+ }
192
+ }
193
+ return null;
194
+ });
195
+ }
196
+ }
197
+ };
198
+ /**
199
+ * Plugin para garantir que React seja corretamente resolvido
200
+ */
201
+ const reactResolvePlugin = {
202
+ name: 'react-resolve',
203
+ setup(build) {
204
+ // Força o uso de uma única instância do React do projeto
205
+ build.onResolve({ filter: /^react$/ }, (args) => {
206
+ const reactPath = require.resolve('react', { paths: [process.cwd()] });
207
+ return {
208
+ path: reactPath
209
+ };
210
+ });
211
+ build.onResolve({ filter: /^react-dom$/ }, (args) => {
212
+ const reactDomPath = require.resolve('react-dom', { paths: [process.cwd()] });
213
+ return {
214
+ path: reactDomPath
215
+ };
216
+ });
217
+ build.onResolve({ filter: /^react\/jsx-runtime$/ }, (args) => {
218
+ const jsxRuntimePath = require.resolve('react/jsx-runtime', { paths: [process.cwd()] });
219
+ return {
220
+ path: jsxRuntimePath
221
+ };
222
+ });
223
+ // Também resolve react-dom/client para React 18+
224
+ build.onResolve({ filter: /^react-dom\/client$/ }, (args) => {
225
+ const clientPath = require.resolve('react-dom/client', { paths: [process.cwd()] });
226
+ return {
227
+ path: clientPath
228
+ };
229
+ });
230
+ }
231
+ };
232
+ /**
233
+ * Plugin para adicionar suporte a HMR (Hot Module Replacement)
234
+ */
235
+ const hmrPlugin = {
236
+ name: 'hmr-plugin',
237
+ setup(build) {
238
+ // Adiciona runtime de HMR para arquivos TSX/JSX
239
+ build.onLoad({ filter: /\.(tsx|jsx)$/ }, async (args) => {
240
+ // Ignora arquivos de node_modules
241
+ if (args.path.includes('node_modules')) {
242
+ return null;
243
+ }
244
+ const fs = require('fs');
245
+ const contents = await fs.promises.readFile(args.path, 'utf8');
246
+ // Adiciona código de HMR apenas em componentes de rota
247
+ if (args.path.includes('/routes/') || args.path.includes('\\routes\\')) {
248
+ const hmrCode = `
249
+ // HMR Runtime
250
+ if (typeof window !== 'undefined' && window.__HWEB_HMR__) {
251
+ const moduleId = ${JSON.stringify(args.path)};
252
+ if (!window.__HWEB_HMR_MODULES__) {
253
+ window.__HWEB_HMR_MODULES__ = new Map();
254
+ }
255
+ window.__HWEB_HMR_MODULES__.set(moduleId, module.exports);
256
+ }
257
+ `;
258
+ return {
259
+ contents: contents + '\n' + hmrCode,
260
+ loader: 'tsx'
261
+ };
262
+ }
263
+ return null;
264
+ });
265
+ }
266
+ };
267
+ /**
268
+ * Plugin para suportar importação de arquivos Markdown (.md)
269
+ */
270
+ const markdownPlugin = {
271
+ name: 'markdown-plugin',
272
+ setup(build) {
273
+ build.onLoad({ filter: /\.md$/ }, async (args) => {
274
+ const fs = require('fs');
275
+ const content = await fs.promises.readFile(args.path, 'utf8');
276
+ return {
277
+ contents: `export default ${JSON.stringify(content)};`,
278
+ loader: 'js'
279
+ };
280
+ });
281
+ }
282
+ };
283
+ /**
284
+ * Plugin para suportar importação de arquivos de imagem e outros assets
285
+ */
286
+ const assetsPlugin = {
287
+ name: 'assets-plugin',
288
+ setup(build) {
289
+ // Suporte para imagens (PNG, JPG, JPEG, GIF, SVG, WEBP, etc)
290
+ build.onLoad({ filter: /\.(png|jpe?g|gif|webp|avif|ico|bmp|tiff?)$/i }, async (args) => {
291
+ const fs = require('fs');
292
+ const buffer = await fs.promises.readFile(args.path);
293
+ const base64 = buffer.toString('base64');
294
+ const ext = path.extname(args.path).slice(1).toLowerCase();
295
+ // Mapeamento de extensões para MIME types
296
+ const mimeTypes = {
297
+ 'png': 'image/png',
298
+ 'jpg': 'image/jpeg',
299
+ 'jpeg': 'image/jpeg',
300
+ 'gif': 'image/gif',
301
+ 'webp': 'image/webp',
302
+ 'avif': 'image/avif',
303
+ 'ico': 'image/x-icon',
304
+ 'bmp': 'image/bmp',
305
+ 'tif': 'image/tiff',
306
+ 'tiff': 'image/tiff'
307
+ };
308
+ const mimeType = mimeTypes[ext] || 'application/octet-stream';
309
+ return {
310
+ contents: `export default "data:${mimeType};base64,${base64}";`,
311
+ loader: 'js'
312
+ };
313
+ });
314
+ // Suporte especial para SVG (pode ser usado como string ou data URL)
315
+ build.onLoad({ filter: /\.svg$/i }, async (args) => {
316
+ const fs = require('fs');
317
+ const content = await fs.promises.readFile(args.path, 'utf8');
318
+ const base64 = Buffer.from(content).toString('base64');
319
+ return {
320
+ contents: `
321
+ export default "data:image/svg+xml;base64,${base64}";
322
+ export const svgContent = ${JSON.stringify(content)};
323
+ `,
324
+ loader: 'js'
325
+ };
326
+ });
327
+ // Suporte para arquivos JSON
328
+ build.onLoad({ filter: /\.json$/i }, async (args) => {
329
+ const fs = require('fs');
330
+ const content = await fs.promises.readFile(args.path, 'utf8');
331
+ return {
332
+ contents: `export default ${content};`,
333
+ loader: 'js'
334
+ };
335
+ });
336
+ // Suporte para arquivos de texto (.txt)
337
+ build.onLoad({ filter: /\.txt$/i }, async (args) => {
338
+ const fs = require('fs');
339
+ const content = await fs.promises.readFile(args.path, 'utf8');
340
+ return {
341
+ contents: `export default ${JSON.stringify(content)};`,
342
+ loader: 'js'
343
+ };
344
+ });
345
+ // Suporte para arquivos de fonte (WOFF, WOFF2, TTF, OTF, EOT)
346
+ build.onLoad({ filter: /\.(woff2?|ttf|otf|eot)$/i }, async (args) => {
347
+ const fs = require('fs');
348
+ const buffer = await fs.promises.readFile(args.path);
349
+ const base64 = buffer.toString('base64');
350
+ const ext = path.extname(args.path).slice(1).toLowerCase();
351
+ const mimeTypes = {
352
+ 'woff': 'font/woff',
353
+ 'woff2': 'font/woff2',
354
+ 'ttf': 'font/ttf',
355
+ 'otf': 'font/otf',
356
+ 'eot': 'application/vnd.ms-fontobject'
357
+ };
358
+ const mimeType = mimeTypes[ext] || 'application/octet-stream';
359
+ return {
360
+ contents: `export default "data:${mimeType};base64,${base64}";`,
361
+ loader: 'js'
362
+ };
363
+ });
364
+ // Suporte para arquivos de áudio (MP3, WAV, OGG, etc)
365
+ build.onLoad({ filter: /\.(mp3|wav|ogg|m4a|aac|flac)$/i }, async (args) => {
366
+ const fs = require('fs');
367
+ const buffer = await fs.promises.readFile(args.path);
368
+ const base64 = buffer.toString('base64');
369
+ const ext = path.extname(args.path).slice(1).toLowerCase();
370
+ const mimeTypes = {
371
+ 'mp3': 'audio/mpeg',
372
+ 'wav': 'audio/wav',
373
+ 'ogg': 'audio/ogg',
374
+ 'm4a': 'audio/mp4',
375
+ 'aac': 'audio/aac',
376
+ 'flac': 'audio/flac'
377
+ };
378
+ const mimeType = mimeTypes[ext] || 'audio/mpeg';
379
+ return {
380
+ contents: `export default "data:${mimeType};base64,${base64}";`,
381
+ loader: 'js'
382
+ };
383
+ });
384
+ // Suporte para arquivos de vídeo (MP4, WEBM, OGV)
385
+ build.onLoad({ filter: /\.(mp4|webm|ogv)$/i }, async (args) => {
386
+ const fs = require('fs');
387
+ const buffer = await fs.promises.readFile(args.path);
388
+ const base64 = buffer.toString('base64');
389
+ const ext = path.extname(args.path).slice(1).toLowerCase();
390
+ const mimeTypes = {
391
+ 'mp4': 'video/mp4',
392
+ 'webm': 'video/webm',
393
+ 'ogv': 'video/ogg'
394
+ };
395
+ const mimeType = mimeTypes[ext] || 'video/mp4';
396
+ return {
397
+ contents: `export default "data:${mimeType};base64,${base64}";`,
398
+ loader: 'js'
399
+ };
400
+ });
401
+ }
402
+ };
403
+ /**
404
+ * Builds with code splitting into multiple chunks based on module types.
405
+ * @param {string} entryPoint - The path to the entry file.
406
+ * @param {string} outdir - The directory for output files.
407
+ * @param {boolean} isProduction - Se está em modo produção ou não.
408
+ * @returns {Promise<void>}
409
+ */
410
+ async function buildWithChunks(entryPoint, outdir, isProduction = false) {
411
+ // limpar diretorio, menos a pasta temp
412
+ await cleanDirectoryExcept(outdir, 'temp');
413
+ try {
414
+ await esbuild.build({
415
+ entryPoints: [entryPoint],
416
+ bundle: true,
417
+ minify: isProduction,
418
+ sourcemap: !isProduction,
419
+ platform: 'browser',
420
+ outdir: outdir,
421
+ loader: { '.js': 'js', '.ts': 'tsx' },
422
+ external: nodeBuiltIns,
423
+ plugins: [postcssPlugin, npmDependenciesPlugin, aliasResolvePlugin, reactResolvePlugin, markdownPlugin, assetsPlugin],
424
+ format: 'esm', // ESM suporta melhor o code splitting
425
+ jsx: 'automatic',
426
+ define: {
427
+ 'process.env.NODE_ENV': isProduction ? '"production"' : '"development"'
428
+ },
429
+ conditions: ['development'],
430
+ mainFields: ['browser', 'module', 'main'],
431
+ resolveExtensions: ['.tsx', '.ts', '.js'],
432
+ splitting: true,
433
+ chunkNames: 'chunks/[name]-[hash]',
434
+ // Força o nome do entry para main(.js) ou main-[hash].js em prod
435
+ entryNames: isProduction ? 'main-[hash]' : 'main',
436
+ keepNames: true,
437
+ treeShaking: true,
438
+ });
439
+ }
440
+ catch (error) {
441
+ console.error('An error occurred while building:', error);
442
+ process.exit(1);
443
+ }
444
+ }
445
+ /**
446
+ * Watches with code splitting enabled
447
+ * @param {string} entryPoint - The path to the entry file.
448
+ * @param {string} outdir - The directory for output files.
449
+ * @param {Object} hotReloadManager - Manager de hot reload (opcional).
450
+ * @returns {Promise<void>}
451
+ */
452
+ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
453
+ // limpar diretorio
454
+ await cleanDirectoryExcept(outdir, 'temp');
455
+ try {
456
+ // Plugin para notificar quando o build termina
457
+ const buildCompletePlugin = {
458
+ name: 'build-complete',
459
+ setup(build) {
460
+ let isFirstBuild = true;
461
+ build.onEnd((result) => {
462
+ if (hotReloadManager) {
463
+ if (isFirstBuild) {
464
+ isFirstBuild = false;
465
+ hotReloadManager.onBuildComplete(true);
466
+ }
467
+ else {
468
+ // Notifica o hot reload manager que o build foi concluído
469
+ hotReloadManager.onBuildComplete(result.errors.length === 0);
470
+ }
471
+ }
472
+ });
473
+ }
474
+ };
475
+ const context = await esbuild.context({
476
+ entryPoints: [entryPoint],
477
+ bundle: true,
478
+ minify: false,
479
+ sourcemap: true,
480
+ platform: 'browser',
481
+ outdir: outdir,
482
+ loader: { '.js': 'js', '.ts': 'tsx' },
483
+ external: nodeBuiltIns,
484
+ plugins: [postcssPlugin, npmDependenciesPlugin, aliasResolvePlugin, reactResolvePlugin, hmrPlugin, buildCompletePlugin, markdownPlugin, assetsPlugin],
485
+ format: 'esm',
486
+ jsx: 'automatic',
487
+ define: {
488
+ 'process.env.NODE_ENV': '"development"'
489
+ },
490
+ conditions: ['development'],
491
+ mainFields: ['browser', 'module', 'main'],
492
+ resolveExtensions: ['.tsx', '.ts', '.js'],
493
+ splitting: true,
494
+ chunkNames: 'chunks/[name]-[hash]',
495
+ entryNames: 'main',
496
+ keepNames: true,
497
+ treeShaking: true,
498
+ });
499
+ await context.watch();
500
+ }
501
+ catch (error) {
502
+ console.error(error);
503
+ Console.error('Error starting watch mode with chunks:', error);
504
+ throw error;
505
+ }
506
+ }
507
+ /**
508
+ * Builds a single entry point into a single output file.
509
+ * @param {string} entryPoint - The path to the entry file.
510
+ * @param {string} outfile - The full path to the output file.
511
+ * @param {boolean} isProduction - Se está em modo produção ou não.
512
+ * @returns {Promise<void>}
513
+ */
514
+ async function build(entryPoint, outfile, isProduction = false) {
515
+ // limpar diretorio do outfile
516
+ const outdir = path.dirname(outfile);
517
+ await cleanDirectoryExcept(outdir, 'temp');
518
+ try {
519
+ await esbuild.build({
520
+ entryPoints: [entryPoint],
521
+ bundle: true,
522
+ minify: isProduction,
523
+ sourcemap: !isProduction, // Só gera sourcemap em dev
524
+ platform: 'browser',
525
+ outfile: outfile,
526
+ loader: { '.js': 'js', '.ts': 'tsx' },
527
+ external: nodeBuiltIns,
528
+ plugins: [postcssPlugin, npmDependenciesPlugin, aliasResolvePlugin, reactResolvePlugin, markdownPlugin, assetsPlugin],
529
+ format: 'iife',
530
+ globalName: 'HwebApp',
531
+ jsx: 'automatic',
532
+ define: {
533
+ 'process.env.NODE_ENV': isProduction ? '"production"' : '"development"'
534
+ },
535
+ // Configurações específicas para React 19
536
+ conditions: ['development'],
537
+ mainFields: ['browser', 'module', 'main'],
538
+ resolveExtensions: ['.tsx', '.ts', '.js'],
539
+ // Garante que não há duplicação de dependências
540
+ splitting: false,
541
+ // Preserva nomes de funções e comportamento
542
+ keepNames: true,
543
+ // Remove otimizações que podem causar problemas com hooks
544
+ treeShaking: true,
545
+ drop: [], // Não remove nada automaticamente
546
+ });
547
+ }
548
+ catch (error) {
549
+ console.error('An error occurred during build:', error);
550
+ process.exit(1);
551
+ }
552
+ }
553
+ /**
554
+ * Watches an entry point and its dependencies, rebuilding to a single output file.
555
+ * @param {string} entryPoint - The path to the entry file.
556
+ * @param {string} outfile - The full path to the output file.
557
+ * @param {Object} hotReloadManager - Manager de hot reload (opcional).
558
+ * @returns {Promise<void>}
559
+ */
560
+ async function watch(entryPoint, outfile, hotReloadManager = null) {
561
+ try {
562
+ // Plugin para notificar quando o build termina
563
+ const buildCompletePlugin = {
564
+ name: 'build-complete',
565
+ setup(build) {
566
+ let isFirstBuild = true;
567
+ build.onEnd((result) => {
568
+ if (hotReloadManager) {
569
+ if (isFirstBuild) {
570
+ isFirstBuild = false;
571
+ hotReloadManager.onBuildComplete(true);
572
+ }
573
+ else {
574
+ // Notifica o hot reload manager que o build foi concluído
575
+ hotReloadManager.onBuildComplete(result.errors.length === 0);
576
+ }
577
+ }
578
+ });
579
+ }
580
+ };
581
+ const context = await esbuild.context({
582
+ entryPoints: [entryPoint],
583
+ bundle: true,
584
+ minify: false,
585
+ sourcemap: true,
586
+ platform: 'browser',
587
+ outfile: outfile,
588
+ loader: { '.js': 'js', '.ts': 'tsx' },
589
+ external: nodeBuiltIns,
590
+ plugins: [postcssPlugin, npmDependenciesPlugin, aliasResolvePlugin, reactResolvePlugin, hmrPlugin, buildCompletePlugin, markdownPlugin, assetsPlugin],
591
+ format: 'iife',
592
+ globalName: 'HwebApp',
593
+ jsx: 'automatic',
594
+ define: {
595
+ 'process.env.NODE_ENV': '"development"'
596
+ },
597
+ // Configurações específicas para React 19 (mesmo que no build)
598
+ conditions: ['development'],
599
+ mainFields: ['browser', 'module', 'main'],
600
+ resolveExtensions: ['.tsx', '.ts', '.js'],
601
+ // Garante que não há duplicação de dependências
602
+ splitting: false,
603
+ // Preserva nomes de funções e comportamento
604
+ keepNames: true,
605
+ // Remove otimizações que podem causar problemas com hooks
606
+ treeShaking: true,
607
+ });
608
+ // Configura o watcher do esbuild
609
+ await context.watch();
610
+ }
611
+ catch (error) {
612
+ Console.error('Error starting watch mode:', error);
613
+ throw error;
614
+ }
615
+ }
616
+ /**
617
+ * Remove todo o conteúdo de um diretório,
618
+ * exceto a pasta (ou pastas) especificada(s) em excludeFolder.
619
+ *
620
+ * @param {string} dirPath - Caminho do diretório a limpar
621
+ * @param {string|string[]} excludeFolder - Nome ou nomes das pastas a manter
622
+ */
623
+ async function cleanDirectoryExcept(dirPath, excludeFolder) {
624
+ const excludes = Array.isArray(excludeFolder) ? excludeFolder : [excludeFolder];
625
+ const items = await readdir(dirPath);
626
+ for (const item of items) {
627
+ if (excludes.includes(item))
628
+ continue; // pula as pastas excluídas
629
+ const itemPath = path.join(dirPath, item);
630
+ const info = await stat(itemPath);
631
+ await rm(itemPath, { recursive: info.isDirectory(), force: true });
632
+ }
633
+ }
634
+ module.exports = { build, watch, buildWithChunks, watchWithChunks };
@@ -0,0 +1 @@
1
+ export default function App(): import("react/jsx-runtime").JSX.Element;