create-express-esm 1.1.2 → 1.1.4

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 CHANGED
@@ -1,7 +1,6 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
- import { program } from 'commander';
4
- import inquirer from 'inquirer';
3
+ import { input, select } from '@inquirer/prompts'; // 현대적인 방식으로 교체
5
4
  import fs from 'fs-extra';
6
5
  import path from 'path';
7
6
  import chalk from 'chalk';
@@ -12,89 +11,100 @@ import { fileURLToPath } from 'url';
12
11
  const __filename = fileURLToPath(import.meta.url);
13
12
  const __dirname = path.dirname(__filename);
14
13
 
15
- program
16
- .version('1.1.0') // 이슈 해결을 반영하여 버전 상향
17
- .description('Layered Architecture 기반의 Modern Express 프로젝트 생성기');
18
-
19
- program
20
- .action(async () => {
21
- console.log(chalk.blue.bold('\n🚀 Create Express ESM 시작!\n'));
22
-
23
- // 1. 사용자 질문
24
- const answers = await inquirer.prompt([
25
- {
26
- type: 'input',
27
- name: 'projectName',
28
- message: '생성할 프로젝트 이름을 입력하세요:',
29
- default: 'my-app',
30
- }
31
- ]);
14
+ // 1.2.0 버전 정보 및 메인 로직
15
+ async function run() {
16
+ console.log(chalk.blue.bold('\n🚀 Create Express ESM 시작!\n'));
17
+
18
+ try {
19
+ // 1. 사용자 질문 (비동기 함수 방식으로 변경)
20
+ const projectName = await input({
21
+ message: '생성할 프로젝트 이름을 입력하세요:',
22
+ default: 'my-app',
23
+ });
24
+
25
+ const language = await select({
26
+ message: '사용할 언어를 선택하세요:',
27
+ choices: [
28
+ { name: 'JavaScript (ESM)', value: 'js' },
29
+ { name: 'TypeScript', value: 'ts' },
30
+ ],
31
+ });
32
32
 
33
- const { projectName } = answers;
34
33
  const targetPath = path.join(process.cwd(), projectName);
35
- const templatePath = path.join(__dirname, '../template');
34
+ const templatePath = path.join(__dirname, '../template', language);
36
35
 
37
- // 2. 템플릿 복사 환경 설정
38
- try {
39
- if (fs.existsSync(targetPath)) {
40
- console.error(chalk.red(`❌ 오류: '${projectName}' 폴더가 이미 존재합니다.`));
41
- process.exit(1);
42
- }
43
-
44
- console.log(chalk.cyan(`\n📂 템플릿을 복사하는 중...`));
45
- await fs.copy(templatePath, targetPath);
46
-
47
- /**
48
- * [이슈 #1 해결] 도트 파일(Dotfiles) 이름 변경 로직
49
- * NPM 배포 시 무시되는 .gitignore와 .env를 처리합니다.
50
- */
51
- const renameMap = {
52
- 'gitignore': '.gitignore', // 기존 사용 방식 대응
53
- '_gitignore': '.gitignore', // 신규 권장 방식 대응
54
- '_env': '.env' // .env 대응
55
- };
56
-
57
- for (const [oldName, newName] of Object.entries(renameMap)) {
58
- const oldFilePath = path.join(targetPath, oldName);
59
- const newFilePath = path.join(targetPath, newName);
60
-
61
- if (await fs.pathExists(oldFilePath)) {
62
- await fs.move(oldFilePath, newFilePath, { overwrite: true });
63
-
64
- // .env가 생성될 때 .env.example도 함께 생성 (DX 개선)
65
- if (newName === '.env') {
66
- const exampleEnvPath = path.join(targetPath, '.env.example');
67
- await fs.copy(newFilePath, exampleEnvPath);
68
- }
36
+ // 2. 폴더 존재 여부 확인
37
+ if (fs.existsSync(targetPath)) {
38
+ console.error(chalk.red(`\n❌ 오류: '${projectName}' 폴더가 이미 존재합니다.`));
39
+ process.exit(1);
40
+ }
41
+
42
+ // 3. 템플릿 복사
43
+ console.log(chalk.cyan(`\n📂 [${language.toUpperCase()}] 템플릿을 복사하는 중...`));
44
+
45
+ if (!fs.existsSync(templatePath)) {
46
+ console.error(chalk.red(`\n❌ 오류: ${language} 템플릿 폴더를 찾을 수 없습니다.`));
47
+ console.log(chalk.gray(`경로 확인: ${templatePath}`));
48
+ process.exit(1);
49
+ }
50
+
51
+ await fs.copy(templatePath, targetPath);
52
+
53
+ // 4. 도트 파일 변환 및 환경 설정
54
+ const renameMap = {
55
+ 'gitignore': '.gitignore',
56
+ '_gitignore': '.gitignore',
57
+ '_env': '.env'
58
+ };
59
+
60
+ for (const [oldName, newName] of Object.entries(renameMap)) {
61
+ const oldFilePath = path.join(targetPath, oldName);
62
+ const newFilePath = path.join(targetPath, newName);
63
+
64
+ if (await fs.pathExists(oldFilePath)) {
65
+ await fs.move(oldFilePath, newFilePath, { overwrite: true });
66
+ if (newName === '.env') {
67
+ const exampleEnvPath = path.join(targetPath, '.env.example');
68
+ await fs.copy(newFilePath, exampleEnvPath);
69
69
  }
70
70
  }
71
-
72
- // 3. package.json 프로젝트 이름 수정
73
- const pkgPath = path.join(targetPath, 'package.json');
74
- if (await fs.pathExists(pkgPath)) {
75
- const pkg = await fs.readJson(pkgPath);
76
- pkg.name = projectName;
77
- await fs.writeJson(pkgPath, pkg, { spaces: 2 });
78
- }
79
-
80
- console.log(chalk.green(`✅ 템플릿 구성 및 환경 설정 완료!`));
81
-
82
- // 4. 패키지 자동 설치
83
- console.log(chalk.yellow(`\n📦 패키지 자동 설치를 진행합니다... (npm install)`));
84
-
85
- execSync('npm install', {
86
- cwd: targetPath,
87
- stdio: 'inherit'
88
- });
89
-
90
- console.log(chalk.green(`\n✨ 모든 설치가 완료되었습니다!`));
91
- console.log(chalk.white(`\n다음 명령어로 시작하세요:\n`));
92
- console.log(chalk.cyan(` cd ${projectName}`));
93
- console.log(chalk.cyan(` npm run dev\n`));
94
-
95
- } catch (error) {
96
- console.error(chalk.red('\n❌ 프로젝트 생성 중 오류 발생:'), error);
97
71
  }
98
- });
72
+
73
+ // 5. package.json 프로젝트 이름 수정
74
+ const pkgPath = path.join(targetPath, 'package.json');
75
+ if (await fs.pathExists(pkgPath)) {
76
+ const pkg = await fs.readJson(pkgPath);
77
+ pkg.name = projectName;
78
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
79
+ }
80
+
81
+ console.log(chalk.green(`✅ 템플릿 구성 완료!`));
82
+
83
+ // 6. 패키지 자동 설치
84
+ console.log(chalk.yellow(`\n📦 패키지 자동 설치를 진행합니다... (npm install)`));
85
+
86
+ execSync('npm install', {
87
+ cwd: targetPath,
88
+ stdio: 'inherit'
89
+ });
90
+
91
+ console.log(chalk.green(`\n✨ 모든 설치가 완료되었습니다!`));
92
+ console.log(chalk.white(`\n다음 명령어로 시작하세요:\n`));
93
+ console.log(chalk.cyan(` cd ${projectName}`));
94
+ if (language === 'ts') {
95
+ console.log(chalk.cyan(` npm run dev (또는 npm run build)`));
96
+ } else {
97
+ console.log(chalk.cyan(` npm run dev`));
98
+ }
99
+ console.log('\n');
100
+
101
+ } catch (error) {
102
+ if (error.name === 'ExitPromptError') {
103
+ console.log(chalk.yellow('\n\n👋 설치를 중단했습니다.'));
104
+ } else {
105
+ console.error(chalk.red('\n❌ 오류 발생:'), error);
106
+ }
107
+ }
108
+ }
99
109
 
100
- program.parse(process.argv);
110
+ run();
package/package.json CHANGED
@@ -1,19 +1,28 @@
1
1
  {
2
2
  "name": "create-express-esm",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "A modern CLI tool to bootstrap Express.js applications with ES Modules and Layered Architecture.",
5
5
  "main": "index.js",
6
+ "type": "module",
6
7
  "bin": {
7
- "create-express-esm": "./bin/cli.js"
8
+ "create-express-esm": "bin/cli.js"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/munjuin/create-express-esm.git"
8
13
  },
9
14
  "scripts": {
10
15
  "test": "echo \"Error: no test specified\" && exit 1",
11
16
  "deploy": "npm version patch && git push origin main --tags && npm publish"
12
17
  },
13
- "keywords": [],
14
- "author": "",
15
- "license": "ISC",
16
- "type": "module",
18
+ "keywords": [
19
+ "express",
20
+ "esm",
21
+ "cli",
22
+ "boilerplate"
23
+ ],
24
+ "author": "munjuin",
25
+ "license": "MIT",
17
26
  "dependencies": {
18
27
  "chalk": "^5.6.2",
19
28
  "commander": "^14.0.2",
@@ -23,5 +32,9 @@
23
32
  "files": [
24
33
  "bin",
25
34
  "template"
26
- ]
35
+ ],
36
+ "bugs": {
37
+ "url": "https://github.com/munjuin/create-express-esm/issues"
38
+ },
39
+ "homepage": "https://github.com/munjuin/create-express-esm#readme"
27
40
  }
@@ -0,0 +1,2 @@
1
+ PORT=8080PORT=3000
2
+ NODE_ENV=development
@@ -0,0 +1,18 @@
1
+ # Dependency directories
2
+ node_modules/
3
+
4
+ # Build output
5
+ dist/
6
+
7
+ # Environment variables
8
+ .env
9
+ .env.example
10
+
11
+ # Debug logs
12
+ npm-debug.log*
13
+ yarn-debug.log*
14
+ yarn-error.log*
15
+
16
+ # OS files
17
+ .DS_Store
18
+ Thumbs.db
File without changes
File without changes
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "temp-name",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "start": "node dist/server.js",
7
+ "dev": "nodemon --exec ts-node src/server.ts",
8
+ "build": "tsc"
9
+ },
10
+ "dependencies": {
11
+ "express": "^4.18.2",
12
+ "dotenv": "^16.3.1",
13
+ "cors": "^2.8.5"
14
+ },
15
+ "devDependencies": {
16
+ "typescript": "^5.0.0",
17
+ "@types/express": "^4.17.17",
18
+ "@types/node": "^20.0.0",
19
+ "@types/cors": "^2.8.13",
20
+ "ts-node": "^10.9.1",
21
+ "nodemon": "^3.0.1"
22
+ }
23
+ }
@@ -0,0 +1,20 @@
1
+ import express, { Application, Request, Response } from 'express';
2
+ import cors from 'cors';
3
+ import userRoutes from './routes/userRoutes.js';
4
+
5
+ const app: Application = express();
6
+
7
+ // Middleware
8
+ app.use(cors());
9
+ app.use(express.json());
10
+ app.use(express.urlencoded({ extended: true }));
11
+
12
+ // Routes
13
+ app.use('/api/users', userRoutes);
14
+
15
+ // Health Check
16
+ app.get('/', (req: Request, res: Response) => {
17
+ res.send('Create Express ESM (TypeScript) Server is Running!');
18
+ });
19
+
20
+ export default app;
@@ -0,0 +1,17 @@
1
+ import { Request, Response } from 'express';
2
+ import * as userService from '../services/userService.js';
3
+
4
+ export const getUsers = async (req: Request, res: Response): Promise<void> => {
5
+ try {
6
+ const users = await userService.fetchAllUsers();
7
+ res.status(200).json({
8
+ success: true,
9
+ data: users,
10
+ });
11
+ } catch (error) {
12
+ res.status(500).json({
13
+ success: false,
14
+ message: 'Internal Server Error',
15
+ });
16
+ }
17
+ };
@@ -0,0 +1,8 @@
1
+ import { Router } from 'express';
2
+ import * as userController from '../controllers/userController.js';
3
+
4
+ const router = Router();
5
+
6
+ router.get('/', userController.getUsers);
7
+
8
+ export default router;
@@ -0,0 +1,8 @@
1
+ import 'dotenv/config';
2
+ import app from './app.js';
3
+
4
+ const PORT = process.env.PORT || 3000;
5
+
6
+ app.listen(PORT, () => {
7
+ console.log(`🚀 Server is running on http://localhost:${PORT}`);
8
+ });
@@ -0,0 +1,14 @@
1
+ // 유저 데이터 타입 정의
2
+ interface User {
3
+ id: number;
4
+ name: string;
5
+ email: string;
6
+ }
7
+
8
+ export const fetchAllUsers = async (): Promise<User[]> => {
9
+ // 실제 DB 연동 대신 샘플 데이터를 반환합니다.
10
+ return [
11
+ { id: 1, name: 'Owner', email: 'owner@example.com' },
12
+ { id: 2, name: 'Gemini', email: 'gemini@ai.com' },
13
+ ];
14
+ };
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true
12
+ },
13
+ "include": ["src/**/*"],
14
+ "exclude": ["node_modules"]
15
+ }
package/template/_env DELETED
@@ -1 +0,0 @@
1
- PORT=8080
@@ -1,4 +0,0 @@
1
- node_modules/
2
- .env
3
- .DS_Store
4
- template/node_modules/
File without changes
File without changes
File without changes
File without changes
File without changes