typescript導入したprivateなnpmパッケージの作り方

はじめに

開発の規模を大きくなってくると、共通化したコンポーネントを利用したいこともあると思います。
git submoduleをつかって共通部分を切り出すことも可能ですが、branchの変更忘れてしまうと反映されないので、個人的には好みではないです。 一方privateなnpmパッケージで実現することも可能だと思います。

npm private registoryを利用することも可能ですが、こちらの場合 US $7/月という月額料金がかかってしまいます。 一方、github privateは無料になったので、githubをつかってprivate npmパッケージを作ってみたいと思います。

また共通利用するなら型情報があったほうがありがたいので、typescriptを導入してみたいと思います。

目標

  1. github privateリポジトリの作成
  2. 他のリポジトリからimport確認
  3. npm version を利用してバージョン管理する

1. my private npm moduleの作成

npm moduleの作成

共通ライブラリのnpmパッケージを作っていきます。

  1. npm moduleの作成
mkdir myNpmModule
cd myNpmModule
git init
npm init -y

.gitignoreの設定は割愛します。

  1. typescript設定
npm i -D typescript
npx tsc --init

npx tsc --init で自動生成された.tsconfig.jsonに以下追加してコンパイル設定を修正する。

.tsconfig.json

 {
 ...
 "declaration": true,
 "sourceMap": true,
 "outDir": "./build",
 "rootDir": "./src",
 ...
}

rootDir でbuild対象のファイルを指定し、outDir でbuild後のファイル保存先を指定する。

declaration でビルド時にxxx.d.tsとして型定義ファイルを出力させる。
sourceMap でtsとjsの対応関係をつくっておく。

  1. package.json修正

共通ライブラリの設定を追加します。

package.json

{
  ...
  "main": "build/index.js",
  "files": [
    "build"
  ],
  "scripts": {
    "build": "tsc",
    "prepare": "npm run build"
  },
  ...
}

files ではパッケージ利用側にどのディレクトリ・ファイルをダウンロードさせるかを指定できる。
ただし、package.jsonとREADME.mdは指定しなくてもダウンロードされる。

main でパッケージ利用側がimportコマンドを使用したときにどのファイルをロードするのかを指定する。

scripts では、typescriptのbuildコマンドに加えて、 prepare を設定する。

prepare はパッケージ利用側が、パッケージをインストールする直前に実行させる処理を定義できる。
srcからビルドされたファイルを作成してくれるため、パッケージ管理側はbuildファイルをgit管理しなくてよい。

つまり、利用側で勝手にsrcからbuildディレクトリを生成してくれるため、.gitignoreにbuildディレクトリを指定しなくてよいわけとなります。

  1. 公開モジュール作成
mkdir src
touch src/Person.ts

src/index.ts

class Person {
  private name: string;
  private age: number;

  public constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  public call(): string {
      return this.name;
  }
}

export { Person };
git add .
git commit -m 'my first commit';

github private repoとして登録

githubページより、新しいリポジトリ作成から、privateにチェックをつけて作成する.

f:id:poppon555:20200405122203p:plain

git remote add origin git@github.com:karuta0825/myNpmModule.git
git push -u origin master

f:id:poppon555:20200405122217p:plain

buildディレクトリ管理しなくてよしです。

2. 他のリポジトリからimport確認

package.json

{
  "dependencies": {
   ...
   "myNpmModule": "git+ssh://git@github.com:karuta0825/myNpmModule.git",
   ...
  },
}

利用側のpackage.jsonのdepenenciesで、使用したいprivate moduleを指定する。git+ssh//に続けて、githubのclone or dowloaddに表示されているパスをコピーすればよき。

f:id:poppon555:20200405122242p:plain

npm i を実行すると、node_modulesに作成したprivate packageが作成されてます。

.
├── node_modules
│   ├── @types
│   ├── myNpmModule <-- 追加されてる
│   └── typescript
├── package-lock.json
├── package.json
├── sample.ts
└── tsconfig.json

node_modulesのmyNpmModuleのディレクトリ構成も設定したとおり。

myNpmModule
├── build
│   ├── index.d.ts
│   ├── index.js
│   └── index.js.map
└── package.json

package.jsonのfilesに指定したbuildディレクトリのみがあり、そこには、型定義ファイルのindex.d.tsとコンパイルされたjsとsourceMapの.mapファイルがある。

では、実際にインストールした共通パッケージを利用できるか確認してみます。

f:id:poppon555:20200405123146p:plain importでき、候補も表示されています。

3. my npm moduleをバージョン管理する

共通パッケージを使用していくならば、バージョン管理をしておくも考えられると思います。
ということで、npmのバージョン管理設定も説明しておきます。
とっても簡単。commit後に npm version を使用するだけです。

import dayjs from "dayjs";

class Person {
  private name: string;
  private age: number;
  public constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  public call(): string {
    return this.name;
  }

  // 追加
  public tellBirthYear(): string {
    return dayjs().subtract(this.age, "year").format("YYYY");
  }
}

git commitする

git add .
git commit -m 'add a method to Person class.'

npm versionのあとに、major, minor, patchのいずれかを指定できます。
majorだと、1.0.0 => 2.0.0
minorだと、1.0.0 => 1.1.0
patchだと、1.0.0 => 1.0.1
にバージョンが変わる。

package.jsonのversionや、git logが変更されていること確認できます。

npm version minor

git log --oneline
// 6a0bb79 1.1.0
// 3d505ff add a method to Person class.
// 351675f my first commit

package.json

{
  ...
  "version": "1.1.0",
  ...
}

git pushして、利用側でnpm updateをして確認すると、

npm update

+ myNpmModule@1.1.0
added 1 package from 1 contributor, updated 3 packages and audited 5 packages in 19.281s
found 0 vulnerabilities

1.1.0のmyNpmModuleが利用できるようになりました。

実際下図の通り、追加したメソッドが候補に上がるようになります。

f:id:poppon555:20200405122235p:plain

まとめ

github privateを利用して、typescript導入npmパッケージを作成しました。
また npm version を利用してバージョン管理する方法をかんたんに説明しました。

ライブラリとして使用されるならば、以下のことも今後対応方法見つけられたらと思ってます。

  • パッケージのmin化 現状だとsrcのディレクトリ構成のままbuildディレクトができるので、一本にまとめたほうがよい。
  • material-uiやlodashのようにmyNpmModue/Personみたいな感じでロードファイルを指定できる

参考にしたサイト

https://dev.classmethod.jp/articles/private-npm-modules-to-package-json/https://medium.com/cameron-nokes/the-30-second-guide-to-publishing-a-typescript-package-to-npm-89d93ff7bccd