create-nextify 0.1.11 → 0.1.14
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/dist/devServer.js +156 -0
- package/dist/index.js +12 -22
- package/package.json +11 -5
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { createServer as createHttpServer } from 'node:http';
|
|
4
|
+
const PORT = Number(process.env.PORT ?? 3000);
|
|
5
|
+
const PROJECT_ROOT = process.env.NEXTIFY_ROOT ?? process.cwd();
|
|
6
|
+
const PAGES_DIR = path.join(PROJECT_ROOT, 'pages');
|
|
7
|
+
function toRoutePath(filePath) {
|
|
8
|
+
const clean = filePath
|
|
9
|
+
.replace(/\\/g, '/')
|
|
10
|
+
.replace(/^pages\//, '')
|
|
11
|
+
.replace(/\.(t|j)sx?$/, '')
|
|
12
|
+
.replace(/index$/, '');
|
|
13
|
+
if (!clean)
|
|
14
|
+
return '/';
|
|
15
|
+
return '/' + clean.split('/').filter(Boolean)
|
|
16
|
+
.map((seg) => seg.replace(/^\[(.+)\]$/, ':$1')).join('/');
|
|
17
|
+
}
|
|
18
|
+
function buildRouteManifest(files) {
|
|
19
|
+
return files.map((file) => {
|
|
20
|
+
const normalized = file.replace(/\\/g, '/');
|
|
21
|
+
const routePath = toRoutePath(normalized);
|
|
22
|
+
const base = path.basename(normalized);
|
|
23
|
+
const kind = normalized.includes('/api/') ? 'api'
|
|
24
|
+
: base.startsWith('middleware') ? 'middleware' : 'page';
|
|
25
|
+
return { file: normalized, routePath, kind };
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function getPageFiles() {
|
|
29
|
+
if (!fs.existsSync(PAGES_DIR))
|
|
30
|
+
return [];
|
|
31
|
+
const files = [];
|
|
32
|
+
function walk(dir, base = '') {
|
|
33
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
34
|
+
const rel = base ? `${base}/${entry.name}` : entry.name;
|
|
35
|
+
if (entry.isDirectory())
|
|
36
|
+
walk(path.join(dir, entry.name), rel);
|
|
37
|
+
else if (/\.(tsx|ts|jsx|js)$/.test(entry.name))
|
|
38
|
+
files.push(`pages/${rel}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
walk(PAGES_DIR);
|
|
42
|
+
return files;
|
|
43
|
+
}
|
|
44
|
+
function buildHtmlShell(routePath) {
|
|
45
|
+
const fileHint = routePath === '/' ? '/pages/index' : `/pages${routePath}`;
|
|
46
|
+
const candidates = JSON.stringify([
|
|
47
|
+
`${fileHint}.tsx`, `${fileHint}.jsx`, `${fileHint}.ts`, `${fileHint}.js`,
|
|
48
|
+
]);
|
|
49
|
+
return `<!DOCTYPE html>
|
|
50
|
+
<html lang="pt-BR">
|
|
51
|
+
<head>
|
|
52
|
+
<meta charset="UTF-8" />
|
|
53
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
54
|
+
<title>Nextify.js</title>
|
|
55
|
+
</head>
|
|
56
|
+
<body>
|
|
57
|
+
<div id="root"></div>
|
|
58
|
+
<script type="module">
|
|
59
|
+
import { createElement } from 'react';
|
|
60
|
+
import { createRoot } from 'react-dom/client';
|
|
61
|
+
const candidates = ${candidates};
|
|
62
|
+
async function loadPage() {
|
|
63
|
+
let mod;
|
|
64
|
+
for (const c of candidates) { try { mod = await import(c); break; } catch {} }
|
|
65
|
+
const root = document.getElementById('root');
|
|
66
|
+
if (!mod?.default) {
|
|
67
|
+
root.innerHTML = '<div style="font-family:monospace;padding:2rem;color:#e53e3e"><h2>404 — Página não encontrada</h2></div>';
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
createRoot(root).render(createElement(mod.default));
|
|
71
|
+
}
|
|
72
|
+
loadPage().catch((err) => {
|
|
73
|
+
document.getElementById('root').innerHTML = '<pre style="color:red;padding:2rem">' + err.stack + '</pre>';
|
|
74
|
+
});
|
|
75
|
+
</script>
|
|
76
|
+
</body>
|
|
77
|
+
</html>`;
|
|
78
|
+
}
|
|
79
|
+
export async function startDevServer(options = {}) {
|
|
80
|
+
const root = options.root ?? PROJECT_ROOT;
|
|
81
|
+
const port = options.port ?? PORT;
|
|
82
|
+
// Resolve vite e plugin-react a partir do projeto do usuário (node_modules local)
|
|
83
|
+
const vitePath = path.join(root, 'node_modules', 'vite', 'dist', 'node', 'index.js');
|
|
84
|
+
const reactPluginPath = path.join(root, 'node_modules', '@vitejs', 'plugin-react', 'dist', 'index.mjs');
|
|
85
|
+
let createViteServer, react;
|
|
86
|
+
try {
|
|
87
|
+
({ createServer: createViteServer } = await import(vitePath));
|
|
88
|
+
({ default: react } = await import(reactPluginPath));
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
console.error('[nextify] Vite não encontrado. Rode: npm install vite @vitejs/plugin-react');
|
|
92
|
+
console.error(err.message);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
const vite = await createViteServer({
|
|
96
|
+
root,
|
|
97
|
+
server: { middlewareMode: true },
|
|
98
|
+
appType: 'custom',
|
|
99
|
+
plugins: [react()],
|
|
100
|
+
resolve: { alias: { '@': path.join(root, 'src') } },
|
|
101
|
+
});
|
|
102
|
+
const manifest = buildRouteManifest(getPageFiles());
|
|
103
|
+
console.log('\n nextify dev\n');
|
|
104
|
+
for (const r of manifest)
|
|
105
|
+
console.log(` ${r.kind === 'api' ? '⚡' : '○'} ${r.routePath}`);
|
|
106
|
+
console.log('');
|
|
107
|
+
const server = createHttpServer(async (req, res) => {
|
|
108
|
+
const host = req.headers.host ?? `localhost:${port}`;
|
|
109
|
+
const pathname = new URL(`http://${host}${req.url}`).pathname;
|
|
110
|
+
if (pathname.startsWith('/@') || pathname.startsWith('/node_modules') ||
|
|
111
|
+
/\.(js|ts|tsx|jsx|css|svg|png|ico|woff2?|map)$/.test(pathname)) {
|
|
112
|
+
vite.middlewares(req, res, () => { res.statusCode = 404; res.end(); });
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const apiRoute = manifest.find((r) => r.kind === 'api' && r.routePath === pathname);
|
|
116
|
+
if (apiRoute) {
|
|
117
|
+
try {
|
|
118
|
+
const mod = await vite.ssrLoadModule(path.join(root, apiRoute.file));
|
|
119
|
+
if (typeof mod.default !== 'function')
|
|
120
|
+
throw new Error('API route sem default export');
|
|
121
|
+
const webReq = new globalThis.Request(`http://${host}${req.url}`, { method: req.method ?? 'GET' });
|
|
122
|
+
const webRes = await mod.default(webReq);
|
|
123
|
+
res.statusCode = webRes.status;
|
|
124
|
+
for (const [k, v] of webRes.headers.entries())
|
|
125
|
+
res.setHeader(k, v);
|
|
126
|
+
res.end(Buffer.from(await webRes.arrayBuffer()));
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
vite.ssrFixStacktrace(err);
|
|
130
|
+
res.statusCode = 500;
|
|
131
|
+
res.setHeader('content-type', 'application/json');
|
|
132
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
133
|
+
}
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
const html = await vite.transformIndexHtml(req.url ?? '/', buildHtmlShell(pathname));
|
|
138
|
+
const found = manifest.some((r) => r.kind === 'page' && r.routePath === pathname);
|
|
139
|
+
res.statusCode = found ? 200 : 404;
|
|
140
|
+
res.setHeader('content-type', 'text/html; charset=utf-8');
|
|
141
|
+
res.end(html);
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
vite.ssrFixStacktrace(err);
|
|
145
|
+
res.statusCode = 500;
|
|
146
|
+
res.setHeader('content-type', 'text/html; charset=utf-8');
|
|
147
|
+
res.end(`<pre style="color:red;padding:2rem">${err.stack}</pre>`);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
server.listen(port, () => {
|
|
151
|
+
console.log(` ➜ Local: \x1b[36mhttp://localhost:${port}\x1b[0m`);
|
|
152
|
+
console.log(` ➜ HMR: ativo\n`);
|
|
153
|
+
});
|
|
154
|
+
return { server, vite };
|
|
155
|
+
}
|
|
156
|
+
startDevServer();
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,8 @@ function createProject(target = 'nextify-app') {
|
|
|
24
24
|
},
|
|
25
25
|
devDependencies: {
|
|
26
26
|
'create-nextify': 'latest',
|
|
27
|
+
vite: '^5.4.19',
|
|
28
|
+
'@vitejs/plugin-react': '^4.3.4',
|
|
27
29
|
'@types/react': '^18.3.1',
|
|
28
30
|
'@types/react-dom': '^18.3.1',
|
|
29
31
|
typescript: '^5.0.0',
|
|
@@ -63,22 +65,15 @@ function createProject(target = 'nextify-app') {
|
|
|
63
65
|
console.log(' npm run dev\n');
|
|
64
66
|
}
|
|
65
67
|
async function runDevServer(port) {
|
|
66
|
-
// Tenta usar o @nextify/dev-server real (com Vite)
|
|
67
68
|
try {
|
|
68
|
-
|
|
69
|
+
// devServer.js está embutido no próprio pacote create-nextify (dist/devServer.js)
|
|
70
|
+
const devServerUrl = new URL('./devServer.js', import.meta.url).href;
|
|
71
|
+
const { startDevServer } = await import(devServerUrl);
|
|
69
72
|
await startDevServer({ root: process.cwd(), port });
|
|
70
73
|
}
|
|
71
|
-
catch {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
' Instale as dependências do projeto com: npm install\n');
|
|
75
|
-
const server = http.createServer((_req, res) => {
|
|
76
|
-
res.setHeader('content-type', 'text/plain; charset=utf-8');
|
|
77
|
-
res.end('Nextify dev server ativo (modo básico)');
|
|
78
|
-
});
|
|
79
|
-
server.listen(port, () => {
|
|
80
|
-
console.log(` ➜ Local: http://localhost:${port}`);
|
|
81
|
-
});
|
|
74
|
+
catch (err) {
|
|
75
|
+
console.error('[nextify] Erro ao iniciar dev server:', err.message);
|
|
76
|
+
process.exit(1);
|
|
82
77
|
}
|
|
83
78
|
}
|
|
84
79
|
function runProdServer(port) {
|
|
@@ -87,16 +82,13 @@ function runProdServer(port) {
|
|
|
87
82
|
res.end('Nextify production server ativo 🚀');
|
|
88
83
|
});
|
|
89
84
|
server.listen(port, () => {
|
|
90
|
-
console.log(`Nextify start
|
|
85
|
+
console.log(`Nextify start em http://localhost:${port}`);
|
|
91
86
|
});
|
|
92
87
|
}
|
|
93
88
|
function runBuild() {
|
|
94
89
|
mkdirSync(join(process.cwd(), 'dist'), { recursive: true });
|
|
95
|
-
writeFileSync(join(process.cwd(), 'dist', 'route-manifest.json'), JSON.stringify({
|
|
96
|
-
|
|
97
|
-
note: 'Manifesto de rotas gerado pelo CLI do Nextify.',
|
|
98
|
-
}, null, 2));
|
|
99
|
-
console.log('✔ Build do Nextify concluído. Artefatos em dist/');
|
|
90
|
+
writeFileSync(join(process.cwd(), 'dist', 'route-manifest.json'), JSON.stringify({ generatedAt: new Date().toISOString() }, null, 2));
|
|
91
|
+
console.log('✔ Build concluído. Artefatos em dist/');
|
|
100
92
|
}
|
|
101
93
|
function showHelp() {
|
|
102
94
|
console.log(`
|
|
@@ -133,7 +125,5 @@ switch (command) {
|
|
|
133
125
|
case 'start':
|
|
134
126
|
runProdServer(port);
|
|
135
127
|
break;
|
|
136
|
-
default:
|
|
137
|
-
// suporta: npx create-nextify minha-app
|
|
138
|
-
createProject(command);
|
|
128
|
+
default: createProject(command);
|
|
139
129
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-nextify",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "CLI para criar aplicações Nextify.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -11,17 +11,23 @@
|
|
|
11
11
|
"dist"
|
|
12
12
|
],
|
|
13
13
|
"scripts": {
|
|
14
|
-
"build": "
|
|
15
|
-
"typecheck": "
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"typecheck": "tsc --noEmit",
|
|
16
16
|
"test": "vitest run --config ./vitest.config.ts",
|
|
17
|
-
"lint": "
|
|
17
|
+
"lint": "echo 'sem lint configurado neste pacote'"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"vite": "^5.4.19",
|
|
21
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
22
|
+
"react": "^18.3.1",
|
|
23
|
+
"react-dom": "^18.3.1"
|
|
18
24
|
},
|
|
19
25
|
"keywords": [
|
|
20
26
|
"nextify",
|
|
21
27
|
"framework",
|
|
22
28
|
"cli"
|
|
23
29
|
],
|
|
24
|
-
"author": "
|
|
30
|
+
"author": "",
|
|
25
31
|
"license": "MIT",
|
|
26
32
|
"devDependencies": {
|
|
27
33
|
"typescript": "^5.9.3"
|