npmパッケージのバージョンがロックされない問題

# はじめに

github等から直接URL指定でインストールしたパッケージを使用して、reactのアプリを作成した際、インストールしたパッケージのパージョンがロックできていないことに気付きました。

reactアプリとnpmパッケージを用意して、ロックする方法をご紹介します。


# 今回作成したアプリとパッケージのディレクトリ構成

それぞれ`Github`に上げています。

- [sample-npm-pkg](https://github.com/pure-adachi/sample-npm-pkg) → パッケージ
- [sample-npm-pkg-link-app](https://github.com/pure-adachi/sample-npm-pkg-link-app) → アプリ

```
sample-npm-package-link/
├── sample-npm-pkg
│   ├── README.md
│   ├── lib
.......
│   ├── package-lock.json
│   ├── package.json
│   ├── src
│   │   └── Message
│   │       └── index.tsx
│   └── tsconfig.json
└── sample-npm-pkg-link-app
    ├── README.md
    ├── package-lock.json
    ├── package.json
   ...
    ├── src
    │   ├── App.tsx
   ... ...
    │   └── serviceWorker.ts
   ...
    └── tsconfig.json
```

# パッケージの作成

まずはパッケージ側を用意します。
※`package.json`や`tsconfig.json`の準備は[こちら](https://github.com/pure-adachi/sample-npm-pkg)を参照してください。

```tsx:src/Message/index.tsx
import * as React from "react";

const Message = () => {
  return <>Hello World !!</>;
};

export default Message;
```

`Hello World !!`と表示される`Message`コンポーネントを作成しました。
コンポーネントの準備が出来次第、`build`します。

```sh
$ npm run build
```

# アプリの作成

`create-react-app`で雛形を作成します。

```sh
$ create-react-app sample-npm-pkg-link-app --typescript
$ cd sample-npm-pkg-link-app
```

## ローカルでパッケージの動作を確認しながら作成してみます。

パッケージディレクトリを指定してインストールします。

```sh
$ npm i --save ../sample-npm-pkg
```

`package.json`を確認すると、ローカルのファイルが参照されていることが分かります。

```:package.json
"sample-npm-pkg": "file:../sample-npm-pkg"
```

## パッケージを使用

```tsx:src/App.tsx
import React from "react";
import logo from "./logo.svg";
import "./App.css";
import Message from "sample-npm-pkg"; // 追加

const App: React.FC = () => {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <Message /> {/* 追加 */}
      </header>
    </div>
  );
};

export default App;
```

実行して確認します。

```sh
$ npm run start
```

`Hello World !!`と表示されました。

![スクリーンショット 2019-09-18 0.09.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/293a7ce0-37b7-c1b2-9634-200ad26ed174.png)

# パッケージをGithubにPush

パッケージ側をGithubにPushし、インストール方法を変更します。

```sh
$ npm i --save git+https://github.com/pure-adachi/sample-npm-pkg.git
```

`package.json`を確認するとGithubから参照されていることが分かります。

```:package.json
"sample-npm-pkg": "git+https://github.com/pure-adachi/sample-npm-pkg.git"
```

※パッケージをGithubから直接インストールする方法は[Githubまたはローカルのnpm のパッケージをinstallする方法 - Qiita](https://qiita.com/pure-adachi/items/ba82b03dba3ebabc6312)を参照してください。

# パッケージのバージョンアップ

パッケージをパージョンアップして`Hello New World !!`と表示されるようにします。

```diff:src/Message/index.tsx
 import * as React from "react";

 const Message = () => {
-  return <>Hello World !!</>;
+  return <>Hello New World !!</>;
 };

 export default Message;
```

```diff:package.json
-  "version": "1.0.0",
+  "version": "2.0.0",
```

`build`して`Github`へ`Push`します。

# アプリ側への影響は？

パッケージのバージョンを上げただけでは、アプリ側へ影響がないと感じます。

`package-lock.json`を確認しても、`sample-npm-pkg`の参照先コミットIDは、
`Hello World!!`と表示される時のものとなっています。

しかし、アプリ側で`npm install`を実行すると最新のパッケージがインストールされてしまいます。

`npm install`後、`npm run start`で画面を確認すると

![スクリーンショット 2019-09-18 0.36.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/471ca94e-4d5a-b170-d78e-34363ac34997.png)

`Hello New World !!`が表示されてしまいました。

**想定していないバージョンのパッケージがインストールされていることから、パッケージがバージョンでロックできていないことが分かります。**

# git tagを使う

パッケージのコミットにタグを付け、バージョン管理します。
今回は1つ目のコミットに`v1`、2つ目のコミットに`v2`とタグを付けます。

```sh
$ git tag -a v1 e713415 -m "Version 1"
$ git tag -a v2 32ec1c1 -m "Version 2"
$ git push origin --tags
```

# v1タグ時点のバージョンを取り込む

URLの最後に`#`を挟んでタグを指定するとタグ指定でインストールできます。

```sh
$ npm i --save git+https://github.com/pure-adachi/sample-npm-pkg.git#v1
```

`npm run start`で画面を確認します。

![スクリーンショット 2019-09-18 0.47.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/13acb309-dd8d-10b5-2411-c40449e96aeb.png)

想定している`v1`時点の`Hello World !!`が表示されています。

# 終わりに

- 想定していない最新バージョンが取り込まれてしまうと、予期せぬエラーや表示方法に勝手に変わってしまうので、怖いですね。
- `npm`にパッケージを公開すれば、`package.json`にもあるようにバージョンが付与されますが、Githubから直接URL指定でインストールする場合は、今回のようにタグ指定や、コミットIDを指定しないと最新が入ってしまいます。
- `package-lock.json`に想定しているコミットIDが指定してある場合は、`npm ci`で、そのコミットID時点のパッケージをインストールすることも出来ます。

# 参考文献

- [初めてのnpmパッケージ公開（TypeScript） - Qiita](https://qiita.com/kik4/items/5a89b413882af629bb8a)
- [Gitのtagを理解する - Qiita](https://qiita.com/k-penguin-sato/items/c62b47dd79f144c68dad)
- [package-lock.jsonについて知りたくても聞けなかったこと - Qiita](https://qiita.com/yfujii1127/items/7ca887a45e0855917279)