create-express-esm 1.2.3 → 1.2.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
@@ -14,8 +14,8 @@ const __dirname = path.dirname(__filename);
14
14
  async function run() {
15
15
  console.clear();
16
16
 
17
- // 1. 시작 인사
18
- p.intro(`${chalk.bgBlue.white(' create-express-esm ')} ${chalk.dim('v1.2.0-beta')}`);
17
+ // 1. 시작 인사 (v1.2.2 버전 반영)
18
+ p.intro(`${chalk.bgBlue.white(' create-express-esm ')} ${chalk.dim('v1.2.2')}`);
19
19
 
20
20
  try {
21
21
  // 2. 사용자 질문 그룹
@@ -45,9 +45,20 @@ async function run() {
45
45
  }),
46
46
  useDb: () =>
47
47
  p.confirm({
48
- message: 'Prisma ORM (PostgreSQL) 및 전역 에러 핸들링을 추가하시겠습니까?',
48
+ message: 'Prisma ORM 및 전역 에러 핸들링을 추가하시겠습니까?',
49
49
  initialValue: false,
50
50
  }),
51
+ // [New] DB 타입 선택 (useDb가 true일 때만 실행)
52
+ dbType: ({ results }) => {
53
+ if (!results.useDb) return;
54
+ return p.select({
55
+ message: '사용할 데이터베이스를 선택하세요:',
56
+ options: [
57
+ { value: 'postgresql', label: 'PostgreSQL' },
58
+ { value: 'mysql', label: 'MySQL' },
59
+ ],
60
+ });
61
+ },
51
62
  },
52
63
  {
53
64
  onCancel: () => {
@@ -57,7 +68,7 @@ async function run() {
57
68
  }
58
69
  );
59
70
 
60
- const { projectName, language, useTest, useDb } = project;
71
+ const { projectName, language, useTest, useDb, dbType } = project;
61
72
  const targetPath = path.join(process.cwd(), projectName);
62
73
  const templatePath = path.join(__dirname, '../template', language);
63
74
  const commonPath = path.join(__dirname, '../template/common');
@@ -88,11 +99,23 @@ async function run() {
88
99
 
89
100
  // 4. DB 및 에러 핸들링 선택 시 추가 파일 복사 및 코드 주입
90
101
  if (useDb) {
91
- // (1) Prisma 설정 및 Docker Compose 복사
92
- await fs.copy(path.join(commonPath, 'prisma'), path.join(targetPath, 'prisma'));
93
- await fs.copy(path.join(commonPath, 'docker-compose.yml'), path.join(targetPath, 'docker-compose.yml'));
102
+ // (1) Prisma 설정 및 Docker Compose 복사 (선택한 DB 타입에 맞춤)
103
+ await fs.ensureDir(path.join(targetPath, 'prisma'));
104
+
105
+ const prismaTemplate = `schema.prisma.${dbType}`;
106
+ const dockerTemplate = `docker-compose.yml.${dbType}`;
94
107
 
95
- // (2) 소스 코드 복사 (lib, services, controllers, routes, utils, middlewares)
108
+ await fs.copy(
109
+ path.join(commonPath, 'prisma', prismaTemplate),
110
+ path.join(targetPath, 'prisma', 'schema.prisma')
111
+ );
112
+
113
+ await fs.copy(
114
+ path.join(commonPath, dockerTemplate),
115
+ path.join(targetPath, 'docker-compose.yml')
116
+ );
117
+
118
+ // (2) 소스 코드 복사 (기존 로직 유지)
96
119
  const sourceFolders = ['lib', 'services', 'controllers', 'routes', 'utils', 'middlewares'];
97
120
  for (const folder of sourceFolders) {
98
121
  const srcFolderPath = path.join(commonPath, 'src', folder);
@@ -102,7 +125,6 @@ async function run() {
102
125
  await fs.ensureDir(destFolderPath);
103
126
  const files = await fs.readdir(srcFolderPath);
104
127
  for (const file of files) {
105
- // 사용자가 선택한 언어(ts/js)와 일치하는 파일만 복사
106
128
  if (file.endsWith(`.${language}`)) {
107
129
  await fs.copy(path.join(srcFolderPath, file), path.join(destFolderPath, file));
108
130
  }
@@ -110,39 +132,33 @@ async function run() {
110
132
  }
111
133
  }
112
134
 
113
- // (3) app.ts / app.js 에 코드 주입 (중요!)
135
+ // (3) app.ts / app.js 에 코드 주입
114
136
  const mainFilePath = path.join(targetPath, `src/app.${language}`);
115
137
  if (await fs.pathExists(mainFilePath)) {
116
138
  let content = await fs.readFile(mainFilePath, 'utf-8');
117
-
118
- // 상단 임포트 주입
119
139
  const imports = [
120
140
  `import userRoutes from './routes/userRoutes.js';`,
121
141
  `import { errorHandler } from './middlewares/errorMiddleware.js';`
122
142
  ].join('\n');
123
143
  content = imports + '\n' + content;
124
-
125
- // 라우터 등록 주입 (express.json() 뒤에)
126
- const routeCode = `\napp.use('/users', userRoutes);`;
127
- content = content.replace('app.use(express.json());', `app.use(express.json());${routeCode}`);
128
-
129
- // 전역 에러 핸들러 주입 (서버 실행 직전에)
130
- const errorMiddlewareCode = `\n// 전역 에러 핸들러 (모든 라우터 다음에 위치해야 함)\napp.use(errorHandler);\n`;
131
- if (content.includes('export default app;')) {
132
- content = content.replace('export default app;', `${errorMiddlewareCode}\nexport default app;`);
133
- } else {
134
- content += `\n${errorMiddlewareCode}`;
135
- }
136
-
144
+ content = content.replace('app.use(express.json());', `app.use(express.json());\napp.use('/users', userRoutes);`);
145
+ const errorMiddlewareCode = `\n// 전역 에러 핸들러\napp.use(errorHandler);\n`;
146
+ content = content.includes('export default app;')
147
+ ? content.replace('export default app;', `${errorMiddlewareCode}\nexport default app;`)
148
+ : content + `\n${errorMiddlewareCode}`;
137
149
  await fs.writeFile(mainFilePath, content);
138
150
  }
139
151
 
140
- // (4) .env 파일에 DATABASE_URL 추가
152
+ // (4) .env 파일에 DB 타입별 DATABASE_URL 추가
141
153
  const envPath = path.join(targetPath, '.env');
142
- const dbUrlContent = `
143
- # PostgreSQL Connection (Docker Compose default)
144
- DATABASE_URL="postgresql://myuser:mypassword@localhost:5432/mydb?schema=public"
145
- `;
154
+ let dbUrlContent = '';
155
+
156
+ if (dbType === 'postgresql') {
157
+ dbUrlContent = `\n# PostgreSQL Connection\nDATABASE_URL="postgresql://myuser:mypassword@localhost:5433/mydb?schema=public"\n`;
158
+ } else if (dbType === 'mysql') {
159
+ dbUrlContent = `\n# MySQL Connection\nDATABASE_URL="mysql://root:mypassword@localhost:3307/mydb"\n`;
160
+ }
161
+
146
162
  await fs.appendFile(envPath, dbUrlContent);
147
163
  }
148
164
 
@@ -156,27 +172,22 @@ DATABASE_URL="postgresql://myuser:mypassword@localhost:5432/mydb?schema=public"
156
172
  pkg.devDependencies["tsx"] = "^4.7.0";
157
173
  }
158
174
 
159
- // 테스트 환경 설정 (비사용 시 관련 파일 및 패키지 제거)
160
175
  if (!useTest) {
161
176
  const configExt = language === 'ts' ? 'ts' : 'js';
162
- const testFileExt = language === 'ts' ? 'ts' : 'js';
163
177
  await fs.remove(path.join(targetPath, `vitest.config.${configExt}`));
164
- await fs.remove(path.join(targetPath, `src/app.test.${testFileExt}`));
178
+ await fs.remove(path.join(targetPath, `src/app.test.${configExt}`));
165
179
  delete pkg.scripts.test;
166
180
  delete pkg.scripts["test:ui"];
167
181
  delete pkg.scripts["test:run"];
168
182
  delete pkg.devDependencies.vitest;
169
183
  delete pkg.devDependencies.supertest;
170
- if (pkg.devDependencies["@types/supertest"]) delete pkg.devDependencies["@types/supertest"];
171
184
  }
172
185
 
173
- // DB 의존성 및 스크립트 추가
174
186
  if (useDb) {
175
187
  pkg.scripts["db:up"] = "docker-compose up -d";
176
188
  pkg.scripts["db:push"] = "prisma db push";
177
189
  pkg.scripts["prisma:generate"] = "prisma generate";
178
190
  pkg.scripts["prisma:studio"] = "prisma studio";
179
-
180
191
  pkg.dependencies["@prisma/client"] = "^5.0.0";
181
192
  pkg.devDependencies["prisma"] = "^5.0.0";
182
193
  }
@@ -187,7 +198,6 @@ DATABASE_URL="postgresql://myuser:mypassword@localhost:5432/mydb?schema=public"
187
198
  // 6. 의존성 설치
188
199
  const installSpinner = p.spinner();
189
200
  installSpinner.start('의존성 패키지를 설치하는 중... (npm install)');
190
-
191
201
  try {
192
202
  execSync('npm install', { cwd: targetPath, stdio: 'ignore' });
193
203
  installSpinner.stop('설치 완료!');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-express-esm",
3
- "version": "1.2.3",
3
+ "version": "1.2.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
6
  "type": "module",
@@ -0,0 +1,14 @@
1
+ services:
2
+ db:
3
+ image: mysql:8.0
4
+ restart: always
5
+ ports:
6
+ - "4306:3306"
7
+ environment:
8
+ MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-mypassword}
9
+ MYSQL_DATABASE: ${DB_NAME:-mydb}
10
+ volumes:
11
+ - mysql_data:/var/lib/mysql
12
+
13
+ volumes:
14
+ mysql_data:
@@ -0,0 +1,14 @@
1
+ datasource db {
2
+ provider = "mysql"
3
+ url = env("DATABASE_URL")
4
+ }
5
+
6
+ generator client {
7
+ provider = "prisma-client-js"
8
+ }
9
+
10
+ model User {
11
+ id Int @id @default(autoincrement())
12
+ email String @unique
13
+ name String?
14
+ }