npm パッケージを TypeScript で自作して公開、別モジュールからインストールして使うまでの手順
この記事で目指すこと
- TypeScript を用いて npm パッケージの実装を行えること
- パッケージを公開するにあたって、適切な設定がなされていること
- 実際に npm にパッケージが公開されて
npm i <package-name>
でインストールができるようになっていること
やらないこと
- パッケージを非公開にする設定
前提
- Node.js が利用できること
- ※ 今回主に用いる
npm
は Node.js に標準で付いてきます
- ※ 今回主に用いる
プロジェクト毎での切り替えなどの利便性から自分は nodenv
を使用しています。
nodenv
のインストールや初期化手順などは以下が参考になります。
手順
- npm アカウントを作成する
- パッケージを初期化する
- サンプルモジュールを実装する
- TypeScriptを設定する
- パッケージ公開に関する設定を行う
- パッケージを公開する
- インストールして使ってみる
npm アカウントを作成する
npm コマンドを利用してCLIで作成可能です。
以下のようにインタラクティブにデータ入れていけば作れます。
$ npm adduser
npm notice Log in on https://registry.npmjs.org/
Username: ttogane
Password:
Email: (this IS public) ****
npm notice Please check your email for a one-time password (OTP)
Enter one-time password: ****
Logged in as ttogane on https://registry.npmjs.org/.
セッションが切れた場合は npm login
で再度ログインを試行できます。
パッケージを初期化する
npm init
でパッケージのメタデータ(パッケージ本体の情報や、それが依存する他パッケージのリストなど)を管理するための package.json
を作成できます。
※ モジュールにある程度一般的な名前をつける場合、名前空間がないと命名が衝突する場合(すでに登録されていて使えない)が多いので、ここではあらかじめ --scope
オプションをつけます。
$ cd /path/to/somewhere/work_dir # どこか適当な作業ディレクトリに移動しておく
$ mkdir npm-package-example # ※ ディレクトリ名はパッケージ名の既定値に用いられる
$ cd $_
$ npm init --scope=ttogane
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (@ttogane/npm-package-example) # 空Enter
version: (1.0.0) 0.1.0 # セマンティックバージョニングで指定(後述)
description: a sample of implemantation of a npm package # 適当に入力
entry point: (index.js) # 一番最初に実行されるファイル。空Enter(後で変更)
test command: # package.json の scripts のtestに設定されるコマンド。空Enter
git repository: # 今回は空Enter
keywords: # 空Enter
author: Taro Togane
license: (ISC) MIT # 今回は仮にMITに
About to write to /path/to/somewhere/work_dir/greeter/package.json:
{
"name": "@ttogane/npm-package-example",
"version": "0.1.0",
"description": "a sample of implemantation of a npm package",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Taro Togane",
"license": "MIT"
}
Is this OK? (yes) # 空Enter
- 後から
package.json
を直接編集することで修正可能です -
npm init -y
で対話形式での入力をスキップ可能です
バージョンについて
セマンティックバージョニングの仕様を満たす書式である必要があります。
メジャーバージョンは以前のバージョンと互換性のない変更(破壊的変更)が加えられたときにアップします。
ただ、それだと開発初期にメジャーバージョンがどんどん上がっていってしまうので、メジャーバージョンが0の間はメジャーバージョンの更新なしに破壊的変更を行うことが許されます。
その規約を利用して最初はバージョン0.1.0から始めるプラクティスがあるようですが、ここではそれに則っています。
サンプルモジュールを実装する
今回はソースコード(コンパイル前のコード)は src/
に配置することにして、ここに適当なクラスを1つ作ってそれをindexでエクスポートしておきます。
src/Greeter.ts
src/index.ts
$ mkdir src
$ touch src/Greeter.ts
$ touch src/index.ts
export class Greeter {
greet(to: string): void {
console.log(`Hello ${to}`)
}
}
export * from "./Greeter";
TypeScriptを設定する
下記コマンドでインストールと初期化します。
$ npm install typescript
$ npx tsc --init
git を使っている場合は /node_modules
を管理下におかないように .gitignore
を編集しておきます。
/node_modules
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"declaration": true, // ← 追記(コンパイルしたtsファイルの中でexportしているもの全ての型定義ファイルを出力する)
"sourceMap": true, // ← 追記(ソースマップを出力する)
"outDir": "./dist", // ← 追記(コンパイル結果の出力先を指定)
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
"include": ["src/**/*.ts"] // ← 追記(コンパイルする対象ファイルの場所を指定)
}
各オプションの詳細は以下が詳しいです。
上記の設定でコンパイルを行うと以下のような出力結果となります。
$ npx tsc
$ ls -l dist
total 24
-rw-r--r-- 1 kokishima staff 62 3 7 06:44 Greeter.d.ts
-rw-r--r-- 1 kokishima staff 241 3 7 06:44 Greeter.js
-rw-r--r-- 1 kokishima staff 221 3 7 06:44 Greeter.js.map
git を利用している場合は /dist
は管理下に含めないように、 .gitignore
を編集しておきます。
/node_modules
/dist
パッケージ公開に関する設定を行う
.npmignore の追加
パッケージに含める必要がないファイルを指定します。
/node_modules
/src
tsconfig.json
package.json の編集
{
"name": "@ttogane/npm-package-example",
"version": "0.1.0",
"description": "a sample of implemantation of a npm package",
"main": "dist/index.js", // ← 編集(tscの設定に合わせる)
"types": "dist/index.d.ts", // ← 追加(型定義のルート)
"scripts": {
"build": "tsc", // ← 追加(TypeScriptでビルド実行するコマンドの定義)
"prepare": "npm run build", // ← 追加(公開前に自動でビルドするためのコマンド定義)
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Taro Togane",
"license": "MIT",
"dependencies": {
"typescript": "^4.6.2"
}
}
パッケージを公開する
下記コマンドで公開できる。
$ npm publish --access=public
※この記事ではscope付きでパッケージ作成したので --access
オプションで公開パッケージであることを明示している(これがないと npm ERR! code E402
npm ERR! 402 Payment Required
みたいなエラーが出る)
成功したらこんな感じの結果になります。
npm notice
npm notice 📦 @ttogane/npm-package-example@0.1.0
npm notice === Tarball Contents ===
npm notice 62B dist/Greeter.d.ts
npm notice 241B dist/Greeter.js
npm notice 221B dist/Greeter.js.map
npm notice 27B dist/index.d.ts
npm notice 835B dist/index.js
npm notice 129B dist/index.js.map
npm notice 417B package.json
npm notice === Tarball Details ===
npm notice name: @ttogane/npm-package-example
npm notice version: 0.1.0
npm notice filename: @ttogane/npm-package-example-0.1.0.tgz
npm notice package size: 1.1 kB
npm notice unpacked size: 1.9 kB
npm notice shasum: 263bdf609256730979f5c74a0ba9ebc0e88a2188
npm notice integrity: sha512-jVMX6KzfGUnGc[...]+dL4BKEhBLk2g==
npm notice total files: 47
npm notice
npm notice Publishing to https://registry.npmjs.org/
+ @ttogane/npm-package-example@0.1.0
npm にパッケージのページも作成されます。
※ 同じバージョンでは再度 publish はできないそうなのでその点は注意
インストールして使ってみる
パッケージをインストールして ts-node
を使って実行してみます。
$ cd /path/to/somewhere/work_dir # どこか適当な作業ディレクトリに移動しておく
$ mkdir example-package-test
$ cd $_
$ npm i @ttogane/npm-package-example
$ npm install --save-dev typescript ts-node
$ touch app.ts
実行するサンプルコードは以下です。
import { Greeter } from "@ttogane/npm-package-example";
const greeter = new Greeter()
console.log(greeter.greet("Mr.Guest"))
実行結果は以下になります。
$ npx ts-node app.ts
Hello Mr.Guest
undefined
前章で公開したパッケージをインポートし、利用することができました。
最後に
Next.js で決済機能を実装する本を書いたのでよかったら読んでください。
Discussion