create-express-esm 1.1.5 → 1.1.9
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/README.md +37 -113
- package/bin/cli.js +93 -39
- package/package.json +6 -2
- package/template/ts/package.json +3 -3
package/README.md
CHANGED
|
@@ -17,10 +17,11 @@
|
|
|
17
17
|
|
|
18
18
|
기존 `express-generator`의 한계를 분석하고 개선하여 개발했습니다.
|
|
19
19
|
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
20
|
+
- **🌐 Multi-Language Support**: JavaScript(ESM)와 **TypeScript** 중 원하는 개발 환경을 선택할 수 있습니다.
|
|
21
|
+
- **🧪 Integrated Testing**: 최신 테스트 프레임워크인 **Vitest**와 API 테스트용 **Supertest** 환경을 자동 설정합니다.
|
|
22
|
+
- **🏗 Layered Architecture**: 실무 표준인 `Controller` - `Service` - `Route` 계층 구조를 제공합니다.
|
|
23
|
+
- **⚡️ Modern TS Execution**: `ts-node`의 ESM 호환성 문제를 해결한 **`tsx`**를 채택하여 쾌적한 개발 환경을 제공합니다.
|
|
24
|
+
- **📦 Smart Auto-Installation**: 프로젝트 생성 즉시 의존성 설치 및 환경 변수(`.env`) 세팅을 완료합니다.
|
|
24
25
|
|
|
25
26
|
## 🚀 Quick Start (사용법)
|
|
26
27
|
|
|
@@ -28,7 +29,8 @@
|
|
|
28
29
|
|
|
29
30
|
```bash
|
|
30
31
|
npx create-express-esm
|
|
31
|
-
npm create
|
|
32
|
+
npm install -g create-express-esm
|
|
33
|
+
npm install create-express-esm
|
|
32
34
|
```
|
|
33
35
|
|
|
34
36
|
또는 전역으로 설치하여 사용할 수도 있습니다
|
|
@@ -46,125 +48,47 @@ create-express-esm
|
|
|
46
48
|
```text
|
|
47
49
|
my-app/
|
|
48
50
|
├── src/
|
|
49
|
-
│
|
|
50
|
-
│
|
|
51
|
-
│
|
|
52
|
-
│
|
|
53
|
-
│
|
|
54
|
-
│
|
|
55
|
-
|
|
56
|
-
├── .
|
|
57
|
-
├── .
|
|
58
|
-
└── package.json
|
|
51
|
+
│ ├── controllers/ # 🕹️ 요청 처리 및 응답 반환 (Controller Layer)
|
|
52
|
+
│ ├── services/ # 🧠 비즈니스 로직 처리 (Service Layer)
|
|
53
|
+
│ ├── routes/ # 🚦 API 엔드포인트 정의 (Route Layer)
|
|
54
|
+
│ ├── app.ts (or .js) # 🏗️ Express 앱 설정 및 미들웨어
|
|
55
|
+
│ ├── server.ts (.js) # 🚀 서버 진입점 (Entry Point)
|
|
56
|
+
│ └── app.test.ts # 🧪 Vitest 샘플 테스트 코드
|
|
57
|
+
├── .env # 🔐 환경 변수 (자동 생성)
|
|
58
|
+
├── vitest.config.ts # 🧪 Vitest 설정 파일
|
|
59
|
+
├── tsconfig.json # ⚙️ TS 컴파일러 설정 (TS 선택 시)
|
|
60
|
+
└── package.json # 📦 의존성 및 스크립트
|
|
59
61
|
```
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
- **Runtime**: Node.js
|
|
64
|
-
- **Framework**: Express.js
|
|
65
|
-
- **Architecture**: Layered Pattern (Controller-Service-Model)
|
|
66
|
-
- **Language**: JavaScript (ES6+ Modules)
|
|
67
|
-
- **Tools**:
|
|
68
|
-
- `dotenv` (환경변수 관리)
|
|
69
|
-
- `cors` (Cross-Origin 리소스 공유 설정)
|
|
70
|
-
- `morgan` (HTTP 요청 로그 기록)
|
|
71
|
-
- `nodemon` (개발 생산성 향상/자동 재시작)
|
|
72
|
-
|
|
73
|
-
## 🛠️ Engineering Deep Dive
|
|
74
|
-
|
|
75
|
-
단순한 도구 개발을 넘어, Node.js의 런타임 환경과 모듈 시스템의 차이를 깊이 있게 이해하기 위해 진행한 프로젝트입니다.
|
|
76
|
-
|
|
77
|
-
### - Project Motivation (Why)
|
|
78
|
-
|
|
79
|
-
대부분의 Express 예제나 스캐폴딩 도구들이 여전히 CommonJS(require) 방식을 사용하고 있습니다. 하지만 최신 Node.js 생태계는 ES Modules(import)로 전환되고 있습니다.
|
|
80
|
-
**"최신 문법을 지원하는 환경을 매번 수동으로 설정하는 비효율을 해결하자"**는 목표로 시작했으며, 프레임워크 없이 순수 Node.js의 `fs`, `path` 모듈을 다루며 CLI 도구의 동작 원리를 체득하고자 했습니다.
|
|
81
|
-
|
|
82
|
-
### - Architecture
|
|
83
|
-
|
|
84
|
-
1. **비동기 파일 시스템 제어**: 대량의 템플릿 파일을 생성할 때 I/O 블로킹을 막기 위해 `fs.promises`와 `async/await`를 사용하여 안정적인 파일 쓰기 작업을 구현했습니다.
|
|
85
|
-
2. **동적 템플릿 생성**: 사용자가 입력한 프로젝트 이름을 `package.json` 등에 동적으로 주입하여, 생성 즉시 실행 가능한 상태를 보장합니다.
|
|
63
|
+
주인님, 요청하신 대로 🛠 Tech Stack (기술 스택) 섹션부터 마지막까지의 내용을 마크다운 코드로 정리해 드립니다. 이 부분은 주인님이 이번에 해결하신 기술적 도전 과제들이 고스란히 담겨 있어 포트폴리오로서의 가치가 매우 높습니다.
|
|
86
64
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
개발 과정에서 마주친 기술적 난관과 해결 과정입니다.
|
|
90
|
-
|
|
91
|
-
### 1. ESM 환경에서의 경로 시스템 구축 (Transition to ESM)
|
|
92
|
-
|
|
93
|
-
> **🔴 Problem:** `ReferenceError: __dirname is not defined`
|
|
94
|
-
|
|
95
|
-
프로젝트를 `type: "module"`(ESM)로 설정한 후, 템플릿 폴더 경로를 참조하기 위해 관습적으로 `__dirname`을 사용했으나 에러가 발생하며 앱이 종료되었습니다.
|
|
96
|
-
|
|
97
|
-
**🔍 Root Cause & Solution**
|
|
98
|
-
|
|
99
|
-
Node.js의 CommonJS 환경에서는 `__dirname`이 기본적으로 주입되지만, ESM 표준 스펙에는 이 변수가 존재하지 않습니다. 이를 해결하기 위해 `url`과 `path` 모듈을 조합하여 Polyfill(직접 구현) 했습니다.
|
|
100
|
-
|
|
101
|
-
```javascript
|
|
102
|
-
import path from "path";
|
|
103
|
-
import { fileURLToPath } from "url";
|
|
104
|
-
|
|
105
|
-
// 1. 현재 파일의 URL(file://...)을 시스템 경로로 변환
|
|
106
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
107
|
-
|
|
108
|
-
// 2. 파일 경로에서 디렉토리 경로만 추출하여 __dirname 구현
|
|
109
|
-
const __dirname = path.dirname(__filename);
|
|
110
|
-
```
|
|
65
|
+
Markdown
|
|
111
66
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
> **🔴 Problem:** `ENOENT: no such file or directory`
|
|
115
|
-
|
|
116
|
-
로컬 테스트(`node bin/cli.js`) 시에는 정상 작동했으나, `npm link` 후 다른 경로(바탕화면 등)에서 실행했을 때 템플릿 폴더를 찾지 못하는 문제가 발생했습니다.
|
|
117
|
-
|
|
118
|
-
**🔍 Root Cause**
|
|
119
|
-
|
|
120
|
-
CLI 도구 개발 시 **'코드의 위치(Source)'**와 **'명령어 실행 위치(Target)'**가 다를 수 있음을 간과했습니다. 템플릿을 찾을 때 `process.cwd()`(사용자 위치)를 기준으로 탐색했기 때문에 발생한 문제였습니다.
|
|
121
|
-
|
|
122
|
-
**✅ Solution**
|
|
123
|
-
|
|
124
|
-
리소스의 성격에 따라 기준 경로를 명확히 분리하여 해결했습니다.
|
|
125
|
-
|
|
126
|
-
- **Source (Template)**: 코드가 설치된 곳에 항상 함께 존재하므로 `__dirname` 기준.
|
|
127
|
-
- **Target (Project)**: 사용자가 명령어를 실행한 위치에 생성되어야 하므로 `process.cwd()` 기준.
|
|
128
|
-
|
|
129
|
-
```javascript
|
|
130
|
-
// [Source] 템플릿 경로: 내 코드가 설치된 곳 기준
|
|
131
|
-
const templateDir = path.join(__dirname, "../template");
|
|
132
|
-
|
|
133
|
-
// [Target] 생성 경로: 사용자가 명령어를 실행한 곳 기준
|
|
134
|
-
const targetDir = path.join(process.cwd(), projectName);
|
|
135
|
-
|
|
136
|
-
// Copy: Source -> Target
|
|
137
|
-
await copyDir(templateDir, targetDir);
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### 3. 배포 파이프라인 최적화 (Appropriate Technology)
|
|
141
|
-
|
|
142
|
-
> **🔴 Problem**
|
|
143
|
-
|
|
144
|
-
잦은 업데이트 과정에서 `버전 수정` -> `태그 생성` -> `깃 푸시` -> `npm 배포`라는 4단계 프로세스를 수동으로 반복하다 보니, 순서를 누락하거나 버전을 잘못 기입하는 휴먼 에러가 발생했습니다.
|
|
145
|
-
|
|
146
|
-
**🔍 Approach & Solution**
|
|
147
|
-
|
|
148
|
-
GitHub Actions와 같은 CI/CD 도구 도입을 고려했으나, 1인 개발 프로젝트 규모에 비해 설정 비용이 크고 오버엔지니어링이라는 판단이 들었습니다. 대신 Node.js의 내장 기능인 **NPM Scripts**를 활용하는 것이 가장 효율적인 **'적정 기술(Appropriate Technology)'**이라 판단했습니다.
|
|
67
|
+
## 🛠 Tech Stack (기술 스택)
|
|
149
68
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
69
|
+
- **Runtime**: Node.js (v20+)
|
|
70
|
+
- **Framework**: Express.js
|
|
71
|
+
- **Language**: JavaScript (ESM) / TypeScript 5.x
|
|
72
|
+
- **Testing**: Vitest, Supertest
|
|
73
|
+
- **Dev Tools**:
|
|
74
|
+
- `tsx` (TypeScript Execution Engine)
|
|
75
|
+
- `nodemon` (Hot Reload)
|
|
76
|
+
- `dotenv` (Environment Variables)
|
|
77
|
+
- `cors` (Cross-Origin Resource Sharing)
|
|
78
|
+
- `chalk` (CLI Styling)
|
|
157
79
|
|
|
158
80
|
## 📝 Retrospective
|
|
159
81
|
|
|
160
|
-
-
|
|
161
|
-
- **
|
|
162
|
-
-
|
|
82
|
+
- **표준화된 환경의 중요성**: CJS에서 ESM으로 넘어가는 과도기적 문제를 해결하며 모던 자바스크립트 모듈 시스템에 대한 깊은 이해를 얻었습니다.
|
|
83
|
+
- **UX 기반 설계**: 사용자가 프로젝트를 생성하자마자 `npm run dev`와 `npm test`를 즉시 실행할 수 있는 "Zero-Config" 환경을 제공하는 데 집중했습니다.
|
|
84
|
+
- **배포 프로세스의 성숙**: 수동 배포의 위험성을 CI/CD와 OIDC 도입을 통해 자동화하며 소프트웨어 릴리스 과정의 안정성을 확보했습니다.
|
|
163
85
|
|
|
164
86
|
## 🗺️ Roadmap (Future Plans)
|
|
165
87
|
|
|
166
|
-
- [
|
|
167
|
-
- [
|
|
88
|
+
- [x] **TypeScript Support**: `.ts` 템플릿 및 `tsx` 환경 최적화
|
|
89
|
+
- [x] **Test Environment**: Vitest 및 Supertest 설정 자동화
|
|
90
|
+
- [ ] **Interactive UI Upgrade**: `Clack` 라이브러리를 통한 시각적 CLI UI 개선
|
|
91
|
+
- [ ] **Database Integration**: Prisma/Sequelize 등 ORM 선택 옵션 추가
|
|
168
92
|
|
|
169
93
|
## 📝 License
|
|
170
94
|
|
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
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
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📦
|
|
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다음
|
|
149
|
+
console.log(chalk.green(`\n✨ 프로젝트 생성 성공!`));
|
|
150
|
+
console.log(chalk.white(`\n다음 명령어를 입력해 보세요:\n`));
|
|
93
151
|
console.log(chalk.cyan(` cd ${projectName}`));
|
|
94
|
-
if (
|
|
95
|
-
|
|
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.
|
|
3
|
+
"version": "1.1.9",
|
|
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
|
}
|
package/template/ts/package.json
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
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",
|