frontend-hamroun 1.1.58 → 1.1.59
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/bin/cli.js +109 -74
- package/bin/cli.ts +40 -0
- package/bin/dev-server.ts +34 -0
- package/bin/esbuild.config.ts +39 -0
- package/package.json +4 -2
- package/templates/basic-app/package.json +2 -2
package/bin/cli.js
CHANGED
@@ -1,87 +1,122 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
2
|
|
3
3
|
import { Command } from 'commander';
|
4
|
-
import
|
5
|
-
import
|
4
|
+
import { spawn } from 'child_process';
|
5
|
+
import sirv from 'sirv';
|
6
|
+
import http from 'http';
|
6
7
|
import path from 'path';
|
7
8
|
import { fileURLToPath } from 'url';
|
9
|
+
import fs from 'fs-extra';
|
8
10
|
import chalk from 'chalk';
|
9
|
-
import { createSpinner } from 'nanospinner';
|
10
|
-
|
11
|
-
const __filename = fileURLToPath(import.meta.url);
|
12
|
-
const __dirname = path.dirname(__filename);
|
13
|
-
|
14
|
-
async function init() {
|
15
|
-
const program = new Command();
|
16
11
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
12
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
13
|
+
const program = new Command();
|
14
|
+
|
15
|
+
// Create development server
|
16
|
+
async function createDevServer(root) {
|
17
|
+
const server = http.createServer(sirv(root, {
|
18
|
+
dev: true,
|
19
|
+
single: true
|
20
|
+
}));
|
21
|
+
|
22
|
+
return new Promise((resolve) => {
|
23
|
+
server.listen(3000, () => {
|
24
|
+
console.log(chalk.green('✓'), 'Dev server running at:', chalk.cyan('http://localhost:3000'));
|
25
|
+
resolve(server);
|
24
26
|
});
|
25
|
-
|
26
|
-
program.parse();
|
27
|
-
}
|
28
|
-
|
29
|
-
async function askProjectName() {
|
30
|
-
const { projectName } = await inquirer.prompt([{
|
31
|
-
type: 'input',
|
32
|
-
name: 'projectName',
|
33
|
-
message: 'What is your project named?',
|
34
|
-
default: 'my-frontend-app'
|
35
|
-
}]);
|
36
|
-
return projectName;
|
37
|
-
}
|
38
|
-
|
39
|
-
async function askProjectType() {
|
40
|
-
const { template } = await inquirer.prompt([{
|
41
|
-
type: 'list',
|
42
|
-
name: 'template',
|
43
|
-
message: 'Select project type:',
|
44
|
-
choices: [
|
45
|
-
{ name: 'Client Side App', value: 'basic-app' },
|
46
|
-
{ name: 'Server Side Rendered App', value: 'ssr-template' }
|
47
|
-
]
|
48
|
-
}]);
|
49
|
-
return template;
|
27
|
+
});
|
50
28
|
}
|
51
29
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
console.log(chalk.
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
spinner.error({ text: 'Failed to create project' });
|
82
|
-
console.error(chalk.red(error));
|
83
|
-
process.exit(1);
|
30
|
+
// Build configuration
|
31
|
+
async function buildProject(root, isDev = false) {
|
32
|
+
const esbuild = await import('esbuild');
|
33
|
+
|
34
|
+
const config = {
|
35
|
+
entryPoints: [path.join(root, 'src/main.tsx')],
|
36
|
+
bundle: true,
|
37
|
+
outfile: path.join(root, 'dist/bundle.js'),
|
38
|
+
loader: { '.tsx': 'tsx', '.ts': 'ts' },
|
39
|
+
jsxFactory: '_jsx',
|
40
|
+
jsxFragment: '_Fragment',
|
41
|
+
platform: 'browser',
|
42
|
+
target: 'es2020',
|
43
|
+
minify: !isDev,
|
44
|
+
sourcemap: isDev,
|
45
|
+
define: {
|
46
|
+
'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production')
|
47
|
+
},
|
48
|
+
inject: [path.join(root, 'src/jsx-shim.js')],
|
49
|
+
};
|
50
|
+
|
51
|
+
if (isDev) {
|
52
|
+
const ctx = await esbuild.context(config);
|
53
|
+
await ctx.watch();
|
54
|
+
console.log(chalk.green('✓'), 'Watching for changes...');
|
55
|
+
return ctx;
|
56
|
+
} else {
|
57
|
+
await esbuild.build(config);
|
58
|
+
console.log(chalk.green('✓'), 'Build complete');
|
84
59
|
}
|
85
60
|
}
|
86
61
|
|
87
|
-
|
62
|
+
// Commands
|
63
|
+
program
|
64
|
+
.command('dev')
|
65
|
+
.description('Start development server')
|
66
|
+
.action(async () => {
|
67
|
+
try {
|
68
|
+
const root = process.cwd();
|
69
|
+
const [server, buildCtx] = await Promise.all([
|
70
|
+
createDevServer(root),
|
71
|
+
buildProject(root, true)
|
72
|
+
]);
|
73
|
+
|
74
|
+
process.once('SIGINT', () => {
|
75
|
+
server.close();
|
76
|
+
buildCtx.dispose();
|
77
|
+
process.exit(0);
|
78
|
+
});
|
79
|
+
} catch (error) {
|
80
|
+
console.error(chalk.red('Error:'), error.message);
|
81
|
+
process.exit(1);
|
82
|
+
}
|
83
|
+
});
|
84
|
+
|
85
|
+
program
|
86
|
+
.command('build')
|
87
|
+
.description('Build for production')
|
88
|
+
.action(async () => {
|
89
|
+
try {
|
90
|
+
const root = process.cwd();
|
91
|
+
await buildProject(root, false);
|
92
|
+
} catch (error) {
|
93
|
+
console.error(chalk.red('Error:'), error.message);
|
94
|
+
process.exit(1);
|
95
|
+
}
|
96
|
+
});
|
97
|
+
|
98
|
+
program
|
99
|
+
.command('create <project-name>')
|
100
|
+
.description('Create a new project')
|
101
|
+
.action(async (name) => {
|
102
|
+
const targetDir = path.join(process.cwd(), name);
|
103
|
+
|
104
|
+
try {
|
105
|
+
// Copy template files
|
106
|
+
await fs.copy(
|
107
|
+
path.join(__dirname, '../templates/basic-app'),
|
108
|
+
targetDir
|
109
|
+
);
|
110
|
+
|
111
|
+
console.log(chalk.green('✓'), 'Created project:', chalk.cyan(name));
|
112
|
+
console.log('\nNext steps:');
|
113
|
+
console.log(` cd ${name}`);
|
114
|
+
console.log(' npm install');
|
115
|
+
console.log(' npm run dev');
|
116
|
+
} catch (error) {
|
117
|
+
console.error(chalk.red('Error:'), error.message);
|
118
|
+
process.exit(1);
|
119
|
+
}
|
120
|
+
});
|
121
|
+
|
122
|
+
program.parse(process.argv);
|
package/bin/cli.ts
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
import { Command } from 'commander';
|
2
|
+
import { startDevServer } from './dev-server';
|
3
|
+
import { createBuildConfig } from './esbuild.config';
|
4
|
+
|
5
|
+
const program = new Command();
|
6
|
+
|
7
|
+
program
|
8
|
+
.command('dev')
|
9
|
+
.description('Start development server')
|
10
|
+
.action(async () => {
|
11
|
+
try {
|
12
|
+
const projectRoot = process.cwd();
|
13
|
+
const { esbuild, server } = startDevServer(projectRoot);
|
14
|
+
|
15
|
+
process.on('SIGINT', () => {
|
16
|
+
esbuild.kill();
|
17
|
+
server.close();
|
18
|
+
process.exit(0);
|
19
|
+
});
|
20
|
+
} catch (error) {
|
21
|
+
console.error('Failed to start dev server:', error);
|
22
|
+
process.exit(1);
|
23
|
+
}
|
24
|
+
});
|
25
|
+
|
26
|
+
program
|
27
|
+
.command('build')
|
28
|
+
.description('Build for production')
|
29
|
+
.action(async () => {
|
30
|
+
try {
|
31
|
+
const projectRoot = process.cwd();
|
32
|
+
process.env.NODE_ENV = 'production';
|
33
|
+
await createBuildConfig(projectRoot);
|
34
|
+
} catch (error) {
|
35
|
+
console.error('Build failed:', error);
|
36
|
+
process.exit(1);
|
37
|
+
}
|
38
|
+
});
|
39
|
+
|
40
|
+
program.parse(process.argv);
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import { spawn } from 'child_process';
|
2
|
+
import sirv from 'sirv';
|
3
|
+
import http from 'http';
|
4
|
+
import path from 'path';
|
5
|
+
import { fileURLToPath } from 'url';
|
6
|
+
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
8
|
+
|
9
|
+
export function startDevServer(projectRoot: string) {
|
10
|
+
// Start esbuild in watch mode
|
11
|
+
const esbuild = spawn('node', [path.join(__dirname, 'esbuild.config.js'), '--watch'], {
|
12
|
+
stdio: 'inherit',
|
13
|
+
cwd: projectRoot
|
14
|
+
});
|
15
|
+
|
16
|
+
// Create static server
|
17
|
+
const serve = sirv(projectRoot, {
|
18
|
+
dev: true,
|
19
|
+
single: true
|
20
|
+
});
|
21
|
+
|
22
|
+
const server = http.createServer(serve);
|
23
|
+
server.listen(3000);
|
24
|
+
console.log('✓ Dev server running at http://localhost:3000');
|
25
|
+
|
26
|
+
// Handle cleanup
|
27
|
+
process.on('SIGTERM', () => {
|
28
|
+
esbuild.kill();
|
29
|
+
server.close();
|
30
|
+
process.exit();
|
31
|
+
});
|
32
|
+
|
33
|
+
return { esbuild, server };
|
34
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import * as esbuild from 'esbuild';
|
2
|
+
import path from 'path';
|
3
|
+
|
4
|
+
export async function createBuildConfig(projectRoot: string, options: { watch?: boolean } = {}) {
|
5
|
+
const config: esbuild.BuildOptions = {
|
6
|
+
entryPoints: [path.join(projectRoot, 'src/main.tsx')],
|
7
|
+
bundle: true,
|
8
|
+
outfile: path.join(projectRoot, 'dist/bundle.js'),
|
9
|
+
loader: { '.tsx': 'tsx', '.ts': 'ts' },
|
10
|
+
jsxFactory: 'createElement',
|
11
|
+
jsxFragment: 'Fragment',
|
12
|
+
platform: 'browser',
|
13
|
+
target: 'es2020',
|
14
|
+
minify: process.env.NODE_ENV === 'production',
|
15
|
+
sourcemap: true,
|
16
|
+
define: {
|
17
|
+
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
|
18
|
+
},
|
19
|
+
plugins: [{
|
20
|
+
name: 'frontend-hamroun',
|
21
|
+
setup(build) {
|
22
|
+
// Handle framework imports
|
23
|
+
build.onResolve({ filter: /^frontend-hamroun$/ }, args => ({
|
24
|
+
path: path.resolve(projectRoot, 'node_modules/frontend-hamroun/dist/index.mjs')
|
25
|
+
}));
|
26
|
+
}
|
27
|
+
}]
|
28
|
+
};
|
29
|
+
|
30
|
+
if (options.watch) {
|
31
|
+
const ctx = await esbuild.context(config);
|
32
|
+
await ctx.watch();
|
33
|
+
console.log('✓ Watching for changes...');
|
34
|
+
return ctx;
|
35
|
+
} else {
|
36
|
+
await esbuild.build(config);
|
37
|
+
console.log('✓ Build complete');
|
38
|
+
}
|
39
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "frontend-hamroun",
|
3
|
-
"version": "1.1.
|
3
|
+
"version": "1.1.59",
|
4
4
|
"description": "A lightweight frontend framework with hooks and virtual DOM",
|
5
5
|
"type": "module",
|
6
6
|
"main": "./dist/index.js",
|
@@ -61,8 +61,10 @@
|
|
61
61
|
"dependencies": {
|
62
62
|
"chalk": "^5.3.0",
|
63
63
|
"commander": "^11.0.0",
|
64
|
+
"esbuild": "^0.19.0",
|
64
65
|
"fs-extra": "^11.1.1",
|
65
66
|
"inquirer": "^9.2.10",
|
66
|
-
"nanospinner": "^1.1.0"
|
67
|
+
"nanospinner": "^1.1.0",
|
68
|
+
"sirv": "^2.0.4"
|
67
69
|
}
|
68
70
|
}
|