개발을 위해 npm install xxx
로 설치하는 모듈이 많아지면서 자주 사용하는 나의 코드들도 같은 방법으로 제공하고 싶었죠.
하지만 ‘코드 복붙’이 더 쉬우니 차일피일 미루던 일을 최근 기회가 생겨 시작했습니다.
동시에 NPM 배포에 필요한 과정을 정리했습니다.
모듈은 Node.js
require()
함수에 의해 로드할 수 있는node_modules
디렉터리의 파일 또는 디렉터리입니다.
모듈은package.json
파일을 가질 필요가 없기 때문에 모든 모듈이 패키지는 아닙니다.package.json
파일을 가진 모듈들만 패키지입니다.
다음과 같은 패키지 구조를 추천합니다.
dist/
는 배포용 디렉터리입니다. Webpack이나 Parcel, Gulp 같은 번들러로 배포용 파일을 생성할 수 있습니다.examples/
는 제공할 예제 디렉터리입니다. 예제 파일과 함께 Demo 페이지를 제공한다면 더욱 좋습니다.lib/
에는 패키지 제작을 위한 원본 파일이 포함되어 있습니다.my_npm_module/
├── dist/
├── examples/
├── lib/
├── .gitignore
├── .npmignore
├── LICENSE
└── package.json
다음 예시와 같이 AMD
, UMD
, CommonJS
, ES Module
등의 제공할 패키지 형식을 지정합니다.
dist/
├── my_module.js (UMD)
├── my_module.min.js (UMD, compressed)
├── my_module.common.js (CommonJS, default)
└── my_module.esm.js (ES Module)
패키지 형식에 대한 자세한 내용은 자바스크립트 모듈, 모듈 포맷, 모듈 로더와 모듈 번들러에 대한 10분 입문서을 참고하세요.
패키지 번들러로 Webpack을 사용한다면 output.libraryTarget을, Parcel을 사용한다면 모듈을 UMD 로 출력을 참고하세요.
이해를 돕기 위해 일부 예제에서 axios/package.json을 참고했습니다.
URL이나 Command Line의 일부로 사용될 소문자로 표기된 214자 이내의 패키지(모듈) 이름으로, 간결하고 직관적인 이름으로 설정하되 다른 모듈과 중복되지 않도록 고유한 이름을 설정합니다.
SemVer(The semantic versioner for npm)로 분석 가능한 형태의 버전을 지정합니다.
{
"version": "0.19.0-beta.1"
}
프로젝트(패키지)의 설명을 지정합니다.
(npm search 사용 시 도움이 됩니다.)
{
"description": "Promise based HTTP client for the browser and node.js"
}
프로젝트(패키지)의 키워드를 배열로 지정합니다.
(npm search 사용 시 도움이 됩니다.)
{
"keywords": [
"xhr",
"http",
"ajax",
"promise",
"node"
]
}
다음과 같이 프로젝트 홈페이지로 연결되는 URL을 지정합니다.
{
"homepage": "https://github.com/axios/axios"
}
패키지에 문제가 있을 때 보고될 이슈 트래커(추적시스템) 및 이메일 주소 등에 대한 URL을 지정합니다.
{
"bugs": {
"url": "https://github.com/axios/axios/issues",
"email": "issues@axios.com"
}
}
패키지 사용을 허용하는 방법과 제한 사항을 알 수 있도록 라이센스를 지정합니다.
Open Source Licenses
{
"license": "MIT"
}
패키지가 여러 공용 라이센스일 경우 SPDX 라이센스 표현식을 사용하세요.
{
"license": "(MIT OR Apache-2.0)"
}
더 이상 다음과 같이 사용하지 않습니다.
// Not valid metadata
{
"licenses" : [
{
"type": "MIT",
"url": "https://www.opensource.org/licenses/mit-license.php"
},
{
"type": "Apache-2.0",
"url": "https://opensource.org/licenses/apache2.0.php"
}
]
}
제작자의 이름을 지정합니다.
{
"author": {
"name": "Steven Wanderski",
"email": "steven@bxcreative.com",
"url": "http://stevenwanderski.com"
}
}
하나의 문자열로 줄일 수 있습니다.
NPM이 자동으로 파싱합니다.
{
"author": "Steven Wanderski <steven@bxcreative.com> (http://stevenwanderski.com)"
}
제작자가 여러 명일 경우 author
옵션(field) 대신에 사용할 수 있습니다.
{
"contributors": [
"Evan <evan@zillinks.com> (https://zillinks.com)",
"Lewis <lewis@zillinks.com> (https://zillinks.com)",
"Neo <neo@zillinks.com> (https://zillinks.com)"
]
}
프로그램의 기본 진입 점(entry point)를 지정합니다.
패키지의 이름이 axios
이고, 사용자가 require('axios')
or import 'axios'
를 사용하면 진입 점의 메인 모듈에서 exports object가 반환(return)됩니다.
{
"main": "dist/my_module.min.js"
}
코드가 존재하는 장소(주소)를 지정합니다.npm docs
명령을 사용하여 패키지 저장소를 쉽게 찾을 수 있습니다.
$ npm docs axios
{
"repository": {
"type": "git",
"url": "https://github.com/axios/axios.git"
}
}
패키지가 의존성으로 설치될 때 같이 포함될 파일(디렉터리)들의 배열입니다.
생략하면 자동 제외로 설정된 파일을 제외한 모든 파일이 포함됩니다
{
"files": [
"dist",
"lib",
"!dist/test"
]
}
클라이언트(client-side) 사용을 위하는 경우 자바스크립트 번들러 또는 구성 요소 도구에 대한 힌트로 제공하기 위해 main
옵션(field) 대신에 사용해야 합니다.
더 자세한 내용은 Package browser field spec을 참고하세요.
{
"browser": "./browser/specific/main.js"
}
패키지의 배포 시 포함될 의존성 모듈을 지정합니다.
{
"dependencies": {
"follow-redirects": "^1.4.1",
"is-buffer": "^2.0.2"
}
}
패키지의 호환성 모듈을 지정합니다.
(npm@3 이후로 배포 시 포함되지 않습니다, 대신 호환성 모듈이 없으면 경고 메시지가 표시됩니다)
{
"name": "bootstrap",
"peerDependencies": {
"jquery": "1.9.1 - 3",
"popper.js": "^1.12.9"
}
}
패키지가 작동하는 Node 버전을 지정합니다.
{
"engines": {
"node": ">=0.10.3 <0.12",
"npm" : "~1.0.20"
}
}
패키지에서 제공할 문서를 작성합니다.
패키지에 대한 정의, 사용법, 예제 등을 자세하게 정리할 수 있습니다.
NPM과 대부분의 저장소는 마크다운 문법을 지원합니다.
다음은 axios/README.md 일부입니다.
## Browser Support
![Chrome](https://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/src/safari/safari_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/src/opera/opera_48x48.png) | ![Edge](https://raw.github.com/alrra/browser-logos/master/src/edge/edge_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png) |
--- | --- | --- | --- | --- | --- |
Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | 11 ✔ |
[![Browser Matrix](https://saucelabs.com/open_sauce/build_matrix/axios.svg)](https://saucelabs.com/u/axios)
## Installing
Using npm:
다른 사람들이 쉽게 기여할 수 있도록 저장소에 오픈 소스 라이센스를 포함할 수 있습니다.
패키지 전역에 LICENSE
혹은 LICENSE.md
(Markdown) 파일(모두 대문자)을 생성합니다.
다음은 MIT License 샘플입니다.
MIT License
Copyright (c) 2019 HEROPY <thesecon@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
GitHub에서 저장소를 관리한다면 라이센스 템플릿(License template)을 선택하여 제출할 수 있습니다.
자세한 내용은 Adding a license to a repository를 참고하세요.
패키지에서 배포하지 않을 파일이나 디렉터리를 지정합니다..npmignore
없이 .gitignore
파일만 사용할 수도 있습니다.
단, 빠른 패키지 배포와 효율적인 프로젝트 저장소 관리를 위해 각 파일을 따로 분리해서 작성하는 것이 좋습니다.
gitignore.io Template Source를 사용하면 쉽고 빠르게 .npmignore
혹은 .gitignore
파일을 생성할 수 있습니다.
*.iml
.idea
.tscache
.DS_Store
node_modules/
typings/
coverage/
test/typescript/axios.js*
sauce_connect.log
package-lock.json
**/.*
*.iml
coverage/
examples/
node_modules/
typings/
sandbox/
test/
bower.json
CODE_OF_CONDUCT.md
COLLABORATOR_GUIDE.md
CONTRIBUTING.md
COOKBOOK.md
ECOSYSTEM.md
Gruntfile.js
karma.conf.js
webpack.*.js
sauce_connect.log
NPM에 모듈을 배포하기 위해서는 사용자 등록(회원가입) 및 로그인을 해야 합니다.
이 때 사용해야 하는 CLI 몇 가지를 간단하게 살펴봅시다.
npm adduser
or npm login
NPM 회원으로 가입하기(NPM 홈페이지에 진행하는 것을 추천)
아이디가 있으면 NPM 로그인
회원가입 후 바로 이메일 인증을 받으세요!
npm logout
NPM에 로그인된 아이디가 있으면 로그아웃
npm whoami
로그인 된 아이디(username)를 표시
배포 전에 로컬 환경에서 테스트할 수 있습니다.
내가 작성한 패키지 디렉터리(my_npm_module/
)를 기준으로 다음과 같이 새로운 테스트 디렉터리를(npm_install_test/
)를 생성합니다.
$ cd ..
$ mkdir npm_install_test
$ cd npm_install_test
$ npm init -y
나의 패키지가 정상적으로 동작하는지 확인하기 위해 상대경로로 npm install
을 진행할 것입니다.
다음과 같이 상대경로는 파일이 아닌 나의 패키지 디렉터리로 합니다.
패키지를 제대로 작성했다면 package.json
의 main
(browser
) 옵션에 맞게 잘 동작하겠죠?!
$ npm install ../my_npm_module
새로운 테스트 프로젝트 내에서 나의 패키지를 가져와 정상적으로 동작하는지 테스트 하겠습니다.
다음 예시와 같이 내가 원하는 기능이 정상적으로 동작한다면 실제 배포할 준비가 끝났습니다.
import myModule from 'my_npm_module';
// const myModule = require('my_npm_module');
const message = myModule.run();
console.log(message);
// 'Hello world!'
이제 작성한 모듈을 NPM에 배포합니다.
npm publish
배포가 정상적으로 이루어졌다면 가상의 모듈 my_npm_module
을 기준으로 다음과 같은 메시지를 확인할 수 있습니다.
# ...
npm notice === Tarball Details ===
npm notice name: my_npm_module
npm notice version: 0.1.0
npm notice package size: 591.2 kB
npm notice unpacked size: 6.3 MB
npm notice shasum: ab1234aa331abcd30f0f8d854ab6390123456789
npm notice integrity: sha512-AbcDEfGHuBczK[...]27123Cd65mMTQ==
npm notice total files: 422
npm notice
+ my_npm_module@0.1.0
실제 NPM 검색 결과에 반영되는 것은 시간이 조금 필요할 수 있습니다.
따라서 배포된 나의 패키지를 확인하기 위해 https://www.npmjs.com/package/my_npm_module
로 접속할 수 있습니다.
설정한 모듈이 정상적으로 나오는지 확인합니다.
이제 모든 것이 끝났습니다.
평소 다른 패키지들을 사용하듯 설치하여 사용할 수 있습니다.
$ npm install my_npm_module
https://docs.npmjs.com/about-package-readme-files
https://help.github.com/articles/adding-a-license-to-a-repository/
https://blog.outsider.ne.kr/829
https://heropy.blog/2018/02/18/node-js-npm/
https://trustyoo86.github.io/webpack/2018/01/10/webpack-configuration.html
https://medium.com/webpack/the-state-of-javascript-modules-4636d1774358