개발을 하다 보면 npm install 명령어를 자주 사용하게 됩니다. 그런데 때로는 --save-dev라는 옵션이 붙어있고, 때로는 그냥 패키지 이름만 적혀있죠. 이 차이가 무엇인지, 언제 어떤 옵션을 써야 하는지 헷갈리는 분들이 많이 있습니다. 회사에서도 그냥 사용하시는 분들도 보이고. 오늘은 이 모든 것을 쉽게 풀어서 설명해드리겠습니다.
npm install의 기본 동작
먼저 npm install이 무엇을 하는지 간단히 알아보겠습니다. npm은 Node Package Manager의 줄임말로, 라이브러리들을 관리해주는 도구입니다.
npm install lodash
이렇게 명령어를 실행하면 두 가지 일이 일어납니다:
- node_modules 폴더에 lodash 라이브러리가 다운로드됩니다
- package.json 파일의 dependencies 섹션에 lodash가 추가됩니다
package.json의 두 가지 의존성
package.json 파일을 열어보면 다음과 같은 구조를 볼 수 있습니다:
{
"name": "my-project",
"version": "1.0.0",
"dependencies": {
"lodash": "^4.17.21",
"express": "^4.18.0"
},
"devDependencies": {
"cross-env": "^7.0.3",
"nodemon": "^2.0.20"
}
}
dependencies는 실제 프로덕션(운영 환경)에서 필요한 라이브러리들이고, devDependencies는 개발할 때만 필요한 라이브러리들입니다.
쉬운 비유로 이해하기
카페를 운영한다고 생각해보세요:
- dependencies: 커피 원두, 우유, 시럽 등 → 고객에게 커피를 제공하기 위해 꼭 필요한 재료들
- devDependencies: 청소도구, 직원 교육 자료, 계산기 등 → 카페 운영을 위해 필요하지만 고객이 직접 보지 않는 것들
웹 개발로 돌아와서:
- dependencies: 사용자가 웹사이트를 이용할 때 실제로 동작하는 코드들 (React, Express, Lodash 등)
- devDependencies: 개발자가 개발할 때만 사용하는 도구들 (테스트 도구, 빌드 도구, 린터 등)
주요 npm install 옵션들
1. 기본 설치 (dependencies에 추가)
npm install express
# 또는
npm install express --save
언제 사용? 실제 애플리케이션이 동작하기 위해 필요한 라이브러리를 설치할 때
예시:
- React, Vue, Angular 같은 프레임워크
- Express, Koa 같은 서버 프레임워크
- Lodash, Moment 같은 유틸리티 라이브러리
2. 개발 의존성 설치 (devDependencies에 추가)
npm install cross-env --save-dev
# 또는 줄여서
npm install cross-env -D
언제 사용? 개발하거나 빌드할 때만 필요한 도구들을 설치할 때
예시:
- cross-env: 환경변수 설정 도구
- nodemon: 개발 서버 자동 재시작 도구
- webpack, parcel: 번들링 도구
- jest, mocha: 테스트 프레임워크
- eslint, prettier: 코드 품질 도구
3. 전역 설치
npm install -g create-react-app
언제 사용? 특정 프로젝트가 아닌 컴퓨터 전체에서 사용할 도구를 설치할 때
예시:
- create-react-app: React 프로젝트 생성 도구
- nodemon: 개발 서버 도구
- http-server: 간단한 정적 파일 서버
4. 정확한 버전 설치
npm install lodash --save-exact
package.json에 ^4.17.21 대신 정확히 4.17.21로 저장됩니다.
5. 설치하지 않고 package.json만 업데이트
npm install lodash --no-save
라이브러리는 다운로드하지만 package.json에는 추가하지 않습니다.
6. 선택적 의존성
npm install sharp --save-optional
설치에 실패해도 전체 설치 과정을 중단시키지 않는 패키지입니다.
실전 예시로 이해하기
Node.js 백엔드 API 서버를 만든다고 가정해보겠습니다:
# 1. 서버 운영에 필요한 라이브러리들 설치 (실제 서비스에서 동작)
npm install express mongoose cors helmet
npm install jsonwebtoken bcryptjs dotenv
# 2. 개발 도구들 설치 (개발할 때만 필요)
npm install --save-dev nodemon cross-env
npm install --save-dev jest supertest
npm install --save-dev eslint prettier
npm install --save-dev @types/node typescript ts-node
# 3. 전역 도구 설치 (여러 프로젝트에서 사용)
npm install -g pm2 nodemon
결과적으로 package.json은 다음과 같아집니다:
{
"dependencies": {
"express": "^4.18.2",
"mongoose": "^6.8.0",
"cors": "^2.8.5",
"helmet": "^6.0.1",
"jsonwebtoken": "^9.0.0",
"bcryptjs": "^2.4.3",
"dotenv": "^16.0.3"
},
"devDependencies": {
"nodemon": "^2.0.20",
"cross-env": "^7.0.3",
"jest": "^29.3.1",
"supertest": "^6.3.3",
"eslint": "^8.30.0",
"prettier": "^2.8.1",
"@types/node": "^18.11.18",
"typescript": "^4.9.4",
"ts-node": "^10.9.1"
}
}
왜 이런 구분이 중요할까?
1. 배포 시간 단축
실제 서비스를 배포할 때는 다음 명령어를 사용합니다:
npm install --production
# 또는
npm ci --production
이렇게 하면 dependencies에 있는 패키지들만 설치되어 배포가 훨씬 빨라집니다.
2. 용량 절약
개발 도구들은 보통 크기가 큽니다. 서비스 배포 시 이런 도구들을 제외하면 상당한 용량을 절약할 수 있습니다.
3. 보안
프로덕션 환경에서는 개발 도구가 필요 없으므로, 불필요한 패키지로 인한 보안 위험을 줄일 수 있습니다.
자주 하는 실수들
실수 1: 서버 운영에 필요한 패키지를 devDependencies에 설치
# 잘못된 예시
npm install express --save-dev
npm install mongoose --save-dev
# 올바른 예시
npm install express mongoose
Express와 MongoDB는 서버가 실제로 동작하기 위해 꼭 필요하므로 dependencies에 들어가야 합니다.
실수 2: 개발 도구를 dependencies에 설치
# 잘못된 예시
npm install nodemon jest
# 올바른 예시
npm install nodemon jest --save-dev
Nodemon과 Jest는 개발/테스트할 때만 필요하므로 devDependencies에 들어가야 합니다.
팀 협업 시 주의사항
팀원들과 같은 환경을 맞추려면 다음을 권장합니다:
# package-lock.json도 함께 커밋
npm ci # npm install 대신 사용 (더 안정적)
npm ci는 package-lock.json을 기반으로 정확히 같은 버전을 설치해줍니다.
마무리
npm install 옵션들을 정리하면:
- 기본 설치: 실제 서비스에 필요한 라이브러리
- --save-dev (-D): 개발할 때만 필요한 도구들
- -g: 컴퓨터 전체에서 사용할 도구들
이제 cross-env같은 개발 도구는 --save-dev로, React같은 라이브러리는 기본 설치로 하시면 됩니다. 이렇게 구분해서 설치하면 프로젝트 관리가 훨씬 체계적이고 효율적이 됩니다.
혹시 "이 패키지는 어디에 설치해야 할까?" 하고 고민된다면, "실제 사용자가 웹사이트를 이용할 때 이 코드가 실행될까?"를 생각해보세요. 답이 "예"라면 dependencies에, "아니오"라면 devDependencies에 설치하시면 됩니다!
참고 자료
'개발 > JavaScript' 카테고리의 다른 글
| [JavaScript] await? return await? return? (0) | 2023.03.25 |
|---|---|
| [TypeScript] 타입 공간과 값 공간의 심벌 구분하기! (0) | 2023.02.26 |
| [JavaScript] 옵셔널 체이닝(Optional chaining) 사용법과 주의할점 (0) | 2023.02.13 |
| [JavaScript] call by value, call by reference, call by sharing (0) | 2023.02.07 |
| [JavaScript] 인자 개수가 자유로운 함수 선언(arguments) (0) | 2023.02.05 |
댓글