kontyra-cli 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/index.js +72 -0
- package/package.json +24 -0
- package/template/build.js +103 -0
- package/template/public/dist/bundle.js +23630 -0
- package/template/public/dist/client.js +25648 -0
- package/template/public/index.html +12 -0
- package/template/server.js +48 -0
- package/template/src/components/Layout.kon +24 -0
- package/template/src/index.kon +35 -0
- package/template/src/index.kontyra +35 -0
- package/template/src/pages/about.kon +16 -0
- package/template/src/pages/index.kon +23 -0
package/index.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const cyan = (text) => `\x1b[36m${text}\x1b[0m`;
|
|
8
|
+
const green = (text) => `\x1b[32m${text}\x1b[0m`;
|
|
9
|
+
const red = (text) => `\x1b[31m${text}\x1b[0m`;
|
|
10
|
+
|
|
11
|
+
const projectName = process.argv[2];
|
|
12
|
+
|
|
13
|
+
if (!projectName) {
|
|
14
|
+
console.log(red('Please specify the project directory:'));
|
|
15
|
+
console.log(` npx create-kontyra-app ${cyan('<project-directory>')}`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const targetPath = path.resolve(process.cwd(), projectName);
|
|
20
|
+
|
|
21
|
+
if (fs.existsSync(targetPath)) {
|
|
22
|
+
console.log(red(`Directory ${projectName} already exists. Please choose a different name.`));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.log(`Creating a new Kontyra app in ${green(targetPath)}.\n`);
|
|
27
|
+
|
|
28
|
+
fs.mkdirSync(targetPath, { recursive: true });
|
|
29
|
+
|
|
30
|
+
// Copy the template directory
|
|
31
|
+
const templatePath = path.join(__dirname, 'template');
|
|
32
|
+
if (fs.existsSync(templatePath)) {
|
|
33
|
+
fs.cpSync(templatePath, targetPath, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Generate package.json
|
|
37
|
+
const packageJson = {
|
|
38
|
+
name: projectName,
|
|
39
|
+
version: "0.1.0",
|
|
40
|
+
private: true,
|
|
41
|
+
scripts: {
|
|
42
|
+
"dev": "node build.js && node server.js",
|
|
43
|
+
"build": "node build.js",
|
|
44
|
+
"start": "node server.js"
|
|
45
|
+
},
|
|
46
|
+
dependencies: {
|
|
47
|
+
"express": "^4.19.0",
|
|
48
|
+
"react": "^18.3.0",
|
|
49
|
+
"react-dom": "^18.3.0",
|
|
50
|
+
"react-router-dom": "^6.22.3"
|
|
51
|
+
},
|
|
52
|
+
devDependencies: {
|
|
53
|
+
"esbuild": "^0.20.0"
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
fs.writeFileSync(
|
|
58
|
+
path.join(targetPath, 'package.json'),
|
|
59
|
+
JSON.stringify(packageJson, null, 2)
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
console.log(green('Project created successfully!\n'));
|
|
63
|
+
console.log('Inside that directory, you can run several commands:');
|
|
64
|
+
console.log(cyan(' npm install'));
|
|
65
|
+
console.log(' Installs the dependencies.\n');
|
|
66
|
+
console.log(cyan(' npm run dev'));
|
|
67
|
+
console.log(' Starts the development server with SSR.\n');
|
|
68
|
+
console.log('We suggest that you begin by typing:');
|
|
69
|
+
console.log(cyan(` cd ${projectName}`));
|
|
70
|
+
console.log(cyan(' npm install'));
|
|
71
|
+
console.log(cyan(' npm run dev\n'));
|
|
72
|
+
console.log('Happy coding with Kontyra!');
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kontyra-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI tool to scaffold a new Kontyra Framework application.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"kontyra-cli": "index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"kontyra",
|
|
14
|
+
"framework",
|
|
15
|
+
"react",
|
|
16
|
+
"ssr",
|
|
17
|
+
"scaffold"
|
|
18
|
+
],
|
|
19
|
+
"author": "Kontyra",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"chalk": "^4.1.2"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
const esbuild = require('esbuild');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const PAGES_DIR = path.join(__dirname, 'src', 'pages');
|
|
6
|
+
|
|
7
|
+
// 1. Scan pages directory
|
|
8
|
+
const files = fs.readdirSync(PAGES_DIR).filter(f => f.endsWith('.kon'));
|
|
9
|
+
|
|
10
|
+
// 2. Generate the React Router setup dynamically
|
|
11
|
+
let imports = `import React from 'react';\n`;
|
|
12
|
+
imports += `import Layout from './src/components/Layout.kon';\n`;
|
|
13
|
+
let routes = '';
|
|
14
|
+
|
|
15
|
+
files.forEach(file => {
|
|
16
|
+
const componentName = file.replace('.kon', '');
|
|
17
|
+
// index.kon maps to '/', about.kon maps to '/about'
|
|
18
|
+
const routePath = componentName === 'index' ? '/' : `/${componentName}`;
|
|
19
|
+
|
|
20
|
+
imports += `import ${componentName}Page from './src/pages/${file}';\n`;
|
|
21
|
+
routes += ` <Route path="${routePath}" element={<${componentName}Page />} />\n`;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const clientEntryCode = `
|
|
25
|
+
${imports}
|
|
26
|
+
import { hydrateRoot } from 'react-dom/client';
|
|
27
|
+
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
28
|
+
|
|
29
|
+
function App() {
|
|
30
|
+
return (
|
|
31
|
+
<BrowserRouter>
|
|
32
|
+
<Layout>
|
|
33
|
+
<Routes>
|
|
34
|
+
${routes}
|
|
35
|
+
</Routes>
|
|
36
|
+
</Layout>
|
|
37
|
+
</BrowserRouter>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
hydrateRoot(document.getElementById('root'), <App />);
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const serverEntryCode = `
|
|
45
|
+
${imports}
|
|
46
|
+
import { StaticRouter } from 'react-router-dom/server';
|
|
47
|
+
import { Routes, Route } from 'react-router-dom';
|
|
48
|
+
|
|
49
|
+
export function AppServer({ location }) {
|
|
50
|
+
return (
|
|
51
|
+
<StaticRouter location={location}>
|
|
52
|
+
<Layout>
|
|
53
|
+
<Routes>
|
|
54
|
+
${routes}
|
|
55
|
+
</Routes>
|
|
56
|
+
</Layout>
|
|
57
|
+
</StaticRouter>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
// Write the dynamic entry files
|
|
63
|
+
fs.writeFileSync(path.join(__dirname, '.client-entry.jsx'), clientEntryCode);
|
|
64
|
+
fs.writeFileSync(path.join(__dirname, '.server-entry.jsx'), serverEntryCode);
|
|
65
|
+
|
|
66
|
+
// Custom plugin to handle .kon files as JSX
|
|
67
|
+
const kontyraPlugin = {
|
|
68
|
+
name: 'kontyra-plugin',
|
|
69
|
+
setup(build) {
|
|
70
|
+
build.onLoad({ filter: /\.kon$/ }, async (args) => {
|
|
71
|
+
const contents = await fs.promises.readFile(args.path, 'utf8');
|
|
72
|
+
return { contents, loader: 'jsx' };
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const commonConfig = {
|
|
78
|
+
bundle: true,
|
|
79
|
+
plugins: [kontyraPlugin],
|
|
80
|
+
loader: { '.js': 'jsx', '.jsx': 'jsx' },
|
|
81
|
+
define: { 'process.env.NODE_ENV': '"development"' },
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Build Client
|
|
85
|
+
esbuild.build({
|
|
86
|
+
...commonConfig,
|
|
87
|
+
entryPoints: ['.client-entry.jsx'],
|
|
88
|
+
outfile: 'public/dist/client.js',
|
|
89
|
+
}).then(() => {
|
|
90
|
+
console.log('Client build successful!');
|
|
91
|
+
}).catch(() => process.exit(1));
|
|
92
|
+
|
|
93
|
+
// Build Server
|
|
94
|
+
esbuild.build({
|
|
95
|
+
...commonConfig,
|
|
96
|
+
entryPoints: ['.server-entry.jsx'],
|
|
97
|
+
outfile: 'dist/server-app.js',
|
|
98
|
+
platform: 'node',
|
|
99
|
+
format: 'cjs',
|
|
100
|
+
external: ['react', 'react-dom', 'react-router-dom', 'react-router'],
|
|
101
|
+
}).then(() => {
|
|
102
|
+
console.log('Server build successful!');
|
|
103
|
+
}).catch(() => process.exit(1));
|