kontyra-cli 1.0.2 → 1.0.3
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/package.json +1 -1
- package/template/build.js +115 -51
- package/template/package.json +24 -0
package/package.json
CHANGED
package/template/build.js
CHANGED
|
@@ -2,26 +2,45 @@ const esbuild = require('esbuild');
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
|
|
5
|
+
const WATCH_MODE = process.argv.includes('--watch');
|
|
5
6
|
const PAGES_DIR = path.join(__dirname, 'src', 'pages');
|
|
6
7
|
|
|
7
|
-
//
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
8
|
+
// ─── Route Scanner ───────────────────────────────────────────────────────────
|
|
9
|
+
const walkSync = (dir, filelist = []) => {
|
|
10
|
+
if (!fs.existsSync(dir)) return filelist;
|
|
11
|
+
fs.readdirSync(dir).forEach(file => {
|
|
12
|
+
const dirFile = path.join(dir, file);
|
|
13
|
+
if (fs.statSync(dirFile).isDirectory()) {
|
|
14
|
+
filelist = walkSync(dirFile, filelist);
|
|
15
|
+
} else if (file.endsWith('.kon')) {
|
|
16
|
+
filelist.push(dirFile);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return filelist;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// ─── Entry Code Generator ────────────────────────────────────────────────────
|
|
23
|
+
function generateEntries() {
|
|
24
|
+
const allFiles = walkSync(PAGES_DIR);
|
|
25
|
+
|
|
26
|
+
let imports = `import React from 'react';\n`;
|
|
27
|
+
imports += `import Layout from './src/components/Layout.kon';\n`;
|
|
28
|
+
let routes = '';
|
|
29
|
+
|
|
30
|
+
allFiles.forEach(absolutePath => {
|
|
31
|
+
const relativePath = path.relative(PAGES_DIR, absolutePath).replace(/\\/g, '/');
|
|
32
|
+
let routePath = relativePath.replace('.kon', '');
|
|
33
|
+
routePath = routePath.replace(/\[([^\]]+)\]/g, ':$1');
|
|
34
|
+
if (routePath.endsWith('index')) routePath = routePath.replace(/index$/, '');
|
|
35
|
+
routePath = '/' + routePath;
|
|
36
|
+
if (routePath.length > 1 && routePath.endsWith('/')) routePath = routePath.slice(0, -1);
|
|
23
37
|
|
|
24
|
-
const
|
|
38
|
+
const componentName = 'Page_' + relativePath.replace(/[^a-zA-Z0-9]/g, '_');
|
|
39
|
+
imports += `import ${componentName} from './src/pages/${relativePath}';\n`;
|
|
40
|
+
routes += ` <Route path="${routePath}" element={<${componentName} />} />\n`;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const clientEntryCode = `
|
|
25
44
|
${imports}
|
|
26
45
|
import { hydrateRoot } from 'react-dom/client';
|
|
27
46
|
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
@@ -29,11 +48,11 @@ import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
|
29
48
|
function App() {
|
|
30
49
|
return (
|
|
31
50
|
<BrowserRouter>
|
|
32
|
-
<
|
|
33
|
-
<
|
|
51
|
+
<Routes>
|
|
52
|
+
<Route path="/" element={<Layout />}>
|
|
34
53
|
${routes}
|
|
35
|
-
</
|
|
36
|
-
</
|
|
54
|
+
</Route>
|
|
55
|
+
</Routes>
|
|
37
56
|
</BrowserRouter>
|
|
38
57
|
);
|
|
39
58
|
}
|
|
@@ -41,7 +60,7 @@ ${routes}
|
|
|
41
60
|
hydrateRoot(document.getElementById('root'), <App />);
|
|
42
61
|
`;
|
|
43
62
|
|
|
44
|
-
const serverEntryCode = `
|
|
63
|
+
const serverEntryCode = `
|
|
45
64
|
${imports}
|
|
46
65
|
import { StaticRouter } from 'react-router-dom/server';
|
|
47
66
|
import { Routes, Route } from 'react-router-dom';
|
|
@@ -49,21 +68,21 @@ import { Routes, Route } from 'react-router-dom';
|
|
|
49
68
|
export function AppServer({ location }) {
|
|
50
69
|
return (
|
|
51
70
|
<StaticRouter location={location}>
|
|
52
|
-
<
|
|
53
|
-
<
|
|
71
|
+
<Routes>
|
|
72
|
+
<Route path="/" element={<Layout />}>
|
|
54
73
|
${routes}
|
|
55
|
-
</
|
|
56
|
-
</
|
|
74
|
+
</Route>
|
|
75
|
+
</Routes>
|
|
57
76
|
</StaticRouter>
|
|
58
77
|
);
|
|
59
78
|
}
|
|
60
79
|
`;
|
|
61
80
|
|
|
62
|
-
|
|
63
|
-
fs.writeFileSync(path.join(__dirname, '.
|
|
64
|
-
|
|
81
|
+
fs.writeFileSync(path.join(__dirname, '.client-entry.jsx'), clientEntryCode);
|
|
82
|
+
fs.writeFileSync(path.join(__dirname, '.server-entry.jsx'), serverEntryCode);
|
|
83
|
+
}
|
|
65
84
|
|
|
66
|
-
//
|
|
85
|
+
// ─── esbuild Plugin ──────────────────────────────────────────────────────────
|
|
67
86
|
const kontyraPlugin = {
|
|
68
87
|
name: 'kontyra-plugin',
|
|
69
88
|
setup(build) {
|
|
@@ -77,27 +96,72 @@ const kontyraPlugin = {
|
|
|
77
96
|
const commonConfig = {
|
|
78
97
|
bundle: true,
|
|
79
98
|
plugins: [kontyraPlugin],
|
|
80
|
-
loader: { '.js': 'jsx', '.jsx': 'jsx' },
|
|
99
|
+
loader: { '.js': 'jsx', '.jsx': 'jsx', '.css': 'css' },
|
|
81
100
|
define: { 'process.env.NODE_ENV': '"development"' },
|
|
82
101
|
};
|
|
83
102
|
|
|
84
|
-
// Build
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
})
|
|
103
|
+
// ─── Build Once or Watch ─────────────────────────────────────────────────────
|
|
104
|
+
async function build() {
|
|
105
|
+
generateEntries();
|
|
106
|
+
|
|
107
|
+
if (!WATCH_MODE) {
|
|
108
|
+
await esbuild.build({
|
|
109
|
+
...commonConfig,
|
|
110
|
+
entryPoints: ['.client-entry.jsx'],
|
|
111
|
+
outfile: 'public/dist/client.js',
|
|
112
|
+
});
|
|
113
|
+
console.log('[kontyra] \u2713 Client build successful!');
|
|
114
|
+
|
|
115
|
+
await esbuild.build({
|
|
116
|
+
...commonConfig,
|
|
117
|
+
entryPoints: ['.server-entry.jsx'],
|
|
118
|
+
outfile: 'dist/server-app.js',
|
|
119
|
+
platform: 'node',
|
|
120
|
+
format: 'cjs',
|
|
121
|
+
external: ['react', 'react-dom', 'react-router-dom', 'react-router'],
|
|
122
|
+
});
|
|
123
|
+
console.log('[kontyra] \u2713 Server build successful!');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── Watch mode ──────────────────────────────────────────────────────────────
|
|
128
|
+
console.log('[kontyra] \uD83D\uDC40 Watch mode active. Waiting for file changes...\n');
|
|
129
|
+
|
|
130
|
+
const clientCtx = await esbuild.context({
|
|
131
|
+
...commonConfig,
|
|
132
|
+
entryPoints: ['.client-entry.jsx'],
|
|
133
|
+
outfile: 'public/dist/client.js',
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const serverCtx = await esbuild.context({
|
|
137
|
+
...commonConfig,
|
|
138
|
+
entryPoints: ['.server-entry.jsx'],
|
|
139
|
+
outfile: 'dist/server-app.js',
|
|
140
|
+
platform: 'node',
|
|
141
|
+
format: 'cjs',
|
|
142
|
+
external: ['react', 'react-dom', 'react-router-dom', 'react-router'],
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
async function rebuild(reason) {
|
|
146
|
+
console.log(`[kontyra] \uD83D\uDD04 Change detected: ${reason}`);
|
|
147
|
+
generateEntries();
|
|
148
|
+
try {
|
|
149
|
+
await Promise.all([clientCtx.rebuild(), serverCtx.rebuild()]);
|
|
150
|
+
console.log(`[kontyra] \u2713 Rebuilt at ${new Date().toLocaleTimeString()}`);
|
|
151
|
+
} catch (e) {
|
|
152
|
+
console.error('[kontyra] \u2717 Build error:', e.message);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
await rebuild('initial build');
|
|
157
|
+
|
|
158
|
+
fs.watch(path.join(__dirname, 'src'), { recursive: true }, (eventType, filename) => {
|
|
159
|
+
if (!filename) return;
|
|
160
|
+
rebuild(filename);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
build().catch(e => {
|
|
165
|
+
console.error('[kontyra] Fatal build error:', e);
|
|
166
|
+
process.exit(1);
|
|
167
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "my-kontyra-app",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A Kontyra Framework application",
|
|
5
|
+
"author": "Kontyra",
|
|
6
|
+
"private": true,
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "node build.js",
|
|
9
|
+
"start": "node server.js",
|
|
10
|
+
"dev": "node build.js && node server.js",
|
|
11
|
+
"dev:build": "node build.js --watch",
|
|
12
|
+
"dev:serve": "node server.js",
|
|
13
|
+
"export": "node export.js"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"express": "^4.19.0",
|
|
17
|
+
"react": "^18.3.0",
|
|
18
|
+
"react-dom": "^18.3.0",
|
|
19
|
+
"react-router-dom": "^6.30.4"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"esbuild": "^0.20.0"
|
|
23
|
+
}
|
|
24
|
+
}
|