create-express-esm 1.1.5 → 1.1.8

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,22 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { input, select } from '@inquirer/prompts'; // 현대적인 방식으로 교체
3
+ import { input, select, confirm } from '@inquirer/prompts';
4
4
  import fs from 'fs-extra';
5
5
  import path from 'path';
6
6
  import chalk from 'chalk';
7
7
  import { execSync } from 'child_process';
8
8
  import { fileURLToPath } from 'url';
9
9
 
10
- // ESM에서 __dirname 사용하기 위한 설정
11
10
  const __filename = fileURLToPath(import.meta.url);
12
11
  const __dirname = path.dirname(__filename);
13
12
 
14
- // 1.2.0 버전 정보 및 메인 로직
15
13
  async function run() {
16
14
  console.log(chalk.blue.bold('\n🚀 Create Express ESM 시작!\n'));
17
15
 
18
16
  try {
19
- // 1. 사용자 질문 (비동기 함수 방식으로 변경)
17
+ // 1. 사용자 질문
20
18
  const projectName = await input({
21
19
  message: '생성할 프로젝트 이름을 입력하세요:',
22
20
  default: 'my-app',
@@ -30,6 +28,11 @@ async function run() {
30
28
  ],
31
29
  });
32
30
 
31
+ const useTest = await confirm({
32
+ message: 'Vitest 테스트 환경을 추가하시겠습니까?',
33
+ default: true,
34
+ });
35
+
33
36
  const targetPath = path.join(process.cwd(), projectName);
34
37
  const templatePath = path.join(__dirname, '../template', language);
35
38
 
@@ -39,18 +42,11 @@ async function run() {
39
42
  process.exit(1);
40
43
  }
41
44
 
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
-
45
+ // 3. 기본 템플릿 복사
46
+ console.log(chalk.cyan(`\n📂 [${language.toUpperCase()}] 템플릿 구성을 시작합니다...`));
51
47
  await fs.copy(templatePath, targetPath);
52
48
 
53
- // 4. 도트 파일 변환 환경 설정
49
+ // 4. 도트 파일 변환 (_env -> .env 등)
54
50
  const renameMap = {
55
51
  'gitignore': '.gitignore',
56
52
  '_gitignore': '.gitignore',
@@ -60,46 +56,104 @@ async function run() {
60
56
  for (const [oldName, newName] of Object.entries(renameMap)) {
61
57
  const oldFilePath = path.join(targetPath, oldName);
62
58
  const newFilePath = path.join(targetPath, newName);
63
-
64
59
  if (await fs.pathExists(oldFilePath)) {
65
60
  await fs.move(oldFilePath, newFilePath, { overwrite: true });
66
61
  if (newName === '.env') {
67
- const exampleEnvPath = path.join(targetPath, '.env.example');
68
- await fs.copy(newFilePath, exampleEnvPath);
62
+ await fs.copy(newFilePath, path.join(targetPath, '.env.example'));
69
63
  }
70
64
  }
71
65
  }
72
66
 
73
- // 5. package.json 프로젝트 이름 수정
67
+ // 5. package.json 동적 수정
74
68
  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 });
69
+ const pkg = await fs.readJson(pkgPath);
70
+ pkg.name = projectName;
71
+
72
+ // [추가된 부분] TypeScript 환경에서 ESM 에러를 방지하기 위한 tsx 설정
73
+ if (language === 'ts') {
74
+ console.log(chalk.yellow(`⚙️ TypeScript ESM 실행 환경(tsx)을 최적화하는 중...`));
75
+
76
+ // ts-node 대신 tsx를 사용하여 .js 확장자 임포트 문제 해결
77
+ pkg.scripts.dev = "nodemon --exec tsx src/server.ts";
78
+
79
+ // 의존성 교체
80
+ pkg.devDependencies = {
81
+ ...pkg.devDependencies,
82
+ "tsx": "^4.7.0"
83
+ };
84
+
85
+ // 기존에 ts-node가 있다면 제거 (중복 방지)
86
+ delete pkg.devDependencies['ts-node'];
79
87
  }
80
-
81
- console.log(chalk.green(`✅ 템플릿 구성 완료!`));
88
+
89
+ // Vitest 설정 (이슈 #3 구현 부분)
90
+ if (useTest) {
91
+ console.log(chalk.yellow(`🧪 Vitest 설정 및 샘플 테스트를 생성하는 중...`));
92
+
93
+ pkg.scripts = {
94
+ ...pkg.scripts,
95
+ "test": "vitest",
96
+ "test:ui": "vitest --ui",
97
+ "test:run": "vitest run"
98
+ };
99
+
100
+ const testDeps = {
101
+ "vitest": "^1.0.0",
102
+ "supertest": "^6.3.3"
103
+ };
104
+
105
+ if (language === 'ts') {
106
+ testDeps["@types/supertest"] = "^2.0.12";
107
+ }
108
+
109
+ pkg.devDependencies = {
110
+ ...pkg.devDependencies,
111
+ ...testDeps
112
+ };
113
+
114
+ // Vitest 설정 파일 생성
115
+ const configExt = language === 'ts' ? 'ts' : 'js';
116
+ const configContent = `import { defineConfig } from 'vitest/config';
117
+
118
+ export default defineConfig({
119
+ test: {
120
+ globals: true,
121
+ environment: 'node',
122
+ },
123
+ });`;
124
+ await fs.writeFile(path.join(targetPath, `vitest.config.${configExt}`), configContent);
125
+
126
+ // 샘플 테스트 파일 생성
127
+ const testFileExt = language === 'ts' ? 'ts' : 'js';
128
+ const testContent = `import { describe, it, expect } from 'vitest';
129
+ import request from 'supertest';
130
+ import app from './app.js';
131
+
132
+ describe('API Health Check Test', () => {
133
+ it('GET / 요청이 성공해야 한다', async () => {
134
+ const res = await request(app).get('/');
135
+ expect(res.status).toBe(200);
136
+ expect(res.text).toContain('Server is Running');
137
+ });
138
+ });`;
139
+ await fs.writeFile(path.join(targetPath, `src/app.test.${testFileExt}`), testContent);
140
+ }
141
+
142
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
143
+ console.log(chalk.green(`✅ 모든 구성 완료!`));
82
144
 
83
145
  // 6. 패키지 자동 설치
84
- console.log(chalk.yellow(`\n📦 패키지 자동 설치를 진행합니다... (npm install)`));
85
-
86
- execSync('npm install', {
87
- cwd: targetPath,
88
- stdio: 'inherit'
89
- });
146
+ console.log(chalk.yellow(`\n📦 의존성 패키지를 설치합니다... (npm install)`));
147
+ execSync('npm install', { cwd: targetPath, stdio: 'inherit' });
90
148
 
91
- console.log(chalk.green(`\n✨ 모든 설치가 완료되었습니다!`));
92
- console.log(chalk.white(`\n다음 명령어로 시작하세요:\n`));
149
+ console.log(chalk.green(`\n✨ 프로젝트 생성 성공!`));
150
+ console.log(chalk.white(`\n다음 명령어를 입력해 보세요:\n`));
93
151
  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');
152
+ if (useTest) console.log(chalk.cyan(` npm test`));
153
+ console.log(chalk.cyan(` npm run dev\n`));
100
154
 
101
155
  } catch (error) {
102
- if (error.name === 'ExitPromptError') {
156
+ if (error.name === 'ExitPromptError') { // 오타 수정: ExitPnromptError -> ExitPromptError
103
157
  console.log(chalk.yellow('\n\n👋 설치를 중단했습니다.'));
104
158
  } else {
105
159
  console.error(chalk.red('\n❌ 오류 발생:'), error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-express-esm",
3
- "version": "1.1.5",
3
+ "version": "1.1.8",
4
4
  "description": "A modern CLI tool to bootstrap Express.js applications with ES Modules and Layered Architecture.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -24,6 +24,7 @@
24
24
  "author": "munjuin",
25
25
  "license": "MIT",
26
26
  "dependencies": {
27
+ "@inquirer/prompts": "^8.1.0",
27
28
  "chalk": "^5.6.2",
28
29
  "commander": "^14.0.2",
29
30
  "fs-extra": "^11.3.2",
@@ -36,5 +37,8 @@
36
37
  "bugs": {
37
38
  "url": "https://github.com/munjuin/create-express-esm/issues"
38
39
  },
39
- "homepage": "https://github.com/munjuin/create-express-esm#readme"
40
+ "homepage": "https://github.com/munjuin/create-express-esm#readme",
41
+ "devDependencies": {
42
+ "tsx": "^4.21.0"
43
+ }
40
44
  }
@@ -3,9 +3,9 @@
3
3
  "version": "1.0.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
- "start": "node dist/server.js",
7
- "dev": "nodemon --exec ts-node src/server.ts",
8
- "build": "tsc"
6
+ "dev": "nodemon --exec tsx src/server.ts",
7
+ "build": "tsc",
8
+ "start": "node dist/server.js"
9
9
  },
10
10
  "dependencies": {
11
11
  "express": "^4.18.2",