Vue + TypeScript で自作モジュールを作り、GitLabを用いて共有する

Vue CLI3から標準でライブラリの書き出し機能が付いたので、それを使用してVue + TypeScriptで作成したライブラリを書き出すまでの手順をまとめます。
また、作成したライブラリは```npm```に公開するのではなく、```GitLab```上で共有してみたいと思います。

##参考プロジェクト

今回の僕の要件ドンピシャな事をしていた方がいました。
全面的にこの記事、及びソースコードを参照しながら進めていきます。

https://qiita.com/coppieee/items/dcf120d6b8eef68ecb34

https://github.com/coppieee/vuterial

#:rocket:ライブラリ作成

まずは、ライブラリを作成します。

###プロジェクトを作る

コマンドから新しいプロジェクトを作ります。

```shell
vue create token-check
```

適宜必要なオプションを追加しますが、今回は```router```と```TypeScript```を追加しました。
しばらく時間が必要なので、待ちましょう。

###フォルダを作成

今回は```modules```フォルダを作って、その中に必要なソースを入れる形でいきます。

###dependancesを全てdevDependancesへ

初期状態だと、```vue```関連のモジュールが```dependances```に入っています。今回作るのは```vue```のライブラリで、```vue```が既にインストールされている環境で動作する前提なので、```devDependances```へ移動します。

###機能を作って、exportする

今回は、```modules```の中に任意の名前のファイルを作って、exportを書いていきます。僕は```Exporter.ts```というファイルを作りました。

```ts
function checkToken(to: any, from: any, next: any) {
    // トークンチェック
}

export {checkToken as check};
```

今回作成したのは、ページに入る毎にトークンが有効かどうかチェックするためのモジュールです。```router```の```beforeEach```に設定して使用します。

###動作確認

動作を確認するため、プロジェクト内のrouterに実際に設定して使ってみます。

```ts
import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';

import {check} from './modules/Exporter';

Vue.use(Router);

const router: Router = new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
        path: '/',
        name: 'home',
        component: Home,
    },
    {
        path: '/about',
        name: 'about',
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        component: () => import(/* webpackChunkName: "about" */ './views/About.vue'),
    },
  ],
});

router.beforeEach(check);

export default router;
```

普通に動作を確認します。

```shell
npm run serve
```

動作したら、コーディングは完了です。

###ライブラリとして書き出す

Vue CLIの機能を使います。  

```shell
vue-cli-service build --target lib
```

というコマンドを使う事で、ライブラリ書き出しができます。デフォルトはスタンドアロンvueアプリを作る```app```で、他にもWebComponent形式に書き出す```wc```等あるようですが、ここでは割愛します。

↑のコマンドを普通に実行してもエラーが出るので、以下のように```package.json```にスクリプトとして登録します。


```json
{

    ...

    "scripts": {

        ...

        "build:lib": "vue-cli-service build --target lib --name token-check ./src/modules/Exporter.ts",
        "build:type": "tsc --emitDeclarationOnly --declaration -P tsconfig.types.json"

        ...

    }

    ...

}
```

####vue-cli-service build

引数で指定している```token-check```や、```./src/modules/Exporter.ts```は、それぞれ **コンポーネント名** と **エントリーポイントとなるスクリプトファイルへのパス** になります。個々の環境に合わせて、適切なものを指定してください。

####tsc

今回はTypeScriptで作ったので、他のTypeScript環境で恩恵を受けるために ```d.ts``` ファイルを作る必要がありますが、これも```tsc```がやってくれます。
ただ、普通に```tsc```してしまうと全ての```ts```ファイルの横に```d.ts```ファイルが出来てしまうので、専用の設定が必要です。

以下のような内容で```tsconfig.types.json```を設定し、```tsc```に参照させます。

前述の記事を参考に設定を変更していますが、僕も勉強不足で個々の設定が何を意味するのか、全てを理解していません…
ひとまず、僕が使用した設定ファイルを載せておきます。

```json
{
    "compilerOptions": {
        "target": "esnext",
        "module": "esnext",
        "strict": true,
        "jsx": "preserve",
        "importHelpers": true,
        "moduleResolution": "node",
        "experimentalDecorators": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "sourceMap": true,
        "baseUrl": ".",
        "outDir": "./dist/types/",
        "types": [
            "webpack-env"
        ],
        "paths": {
            "@/*": [
                "src/*"
            ]
        },
        "lib": [
            "esnext",
            "dom",
            "dom.iterable",
            "scripthost"
        ]
    },
    "files":[
        "src/modules/Exporter.ts"
    ],
    "include": [
        "src/shims-vue.d.ts"
    ],
    "exclude": [
        "node_modules",
        "lib",
    ]
}
```

###npmで呼び出すための設定

####package.jsonの編集

```json
{
    "name": "token-check",
    "version": "0.1.3",
    "main": "dist/token-check.common.js",
    "typings": "dist/types/Exporter.d.ts",

    ...

}
```

- name --- npmで使用するライブラリ名です。```npm install ここで指定した名前```となります。
- version --- 現在のバージョンです。```npm install token-check```とした際に、ここが更新されていたら自動的に更新版がDLされます。
- main --- ライブラリのエントリーポイントとなる```js```ファイルです。```vue-cli-service build```で作成しているので、```**.common.js```を指定すれば問題ないはずです。
- typings --- ```TypeScript```を使用する時に参照する```d.ts```ファイルです。

####.gitignoreの編集

標準では```dist```ディレクトリは無視するようになっていますが、今回はここを見に行ってもらうことになるので、無視リストから外しておきます。

####.npmignoreの追加

```npm install```した時に必要なのは基本的に```dist```の中身だけなので、不要なものは```.npmignore```に記載していきます。
僕はこんな感じにしました。

```.npmignore
/src
/public
tsconfig.json
tsconfig.types.json
tslint.json
```

###GitLabにアップロード

今回は、オンプレミスで動いているGitLabのオムニバス版にアップします。
とはいえ、やる事はクラウドのGitHubやGitLabと変わりません。粛々とpushします。

```shell
git add .
git commit
git remote add origin <URL>
git push
```

#:computer:作ったライブラリを使用

作成したライブラリを実際に使用してみます。

###プロジェクトを作る

確認用に新しいプロジェクトを作ります。

```shell
vue create module-use
```

こちらのプロジェクトでも、今回は```router```と```TypeScript```を追加しました。

###自作ライブラリをインストール

満を持してインストールします。  
```npm```にアップロードしていないので、```npm i -S token-check```としても落とせません。しかし、なんと、**gitから直接落とせます。**

```shell
npm i -S <Git URL>
```

ここでいうURLは、```git clone <Git URL>```とした時に```clone```ができるURLで、末尾が```.git```で終わっているはずです。

####ハマったところ

僕のケースでは、GitLab上でURLが

> git@アドレス/モジュール名.git

あるいは

> ssh://git@アドレス/モジュール名.git

のような形で提供されていたのですが、

> git+ssh://git@アドレス/モジュール名.git

**というように```git+ssh```プロトコルにする必要がありした。**

また、```http```あるいは```https```で取得する場合も

> git+http(s)://アドレス/モジュール名.git

というように、やはり```git+```をつける必要があります。

###使用する

今回はルーターに作用するライブラリを作ったので、```router.ts```を編集します。

```ts
import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';
import {check} from 'token-check';

Vue.use(Router);
const r: Router = new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue'),
    },
  ],
});
r.beforeEach(check);

export default r;
```

テスト時と同じ挙動になれば成功です。

#:family_mwgb:複数コンポーネントの書き出し

今回は一つの機能だけを書き出して使いましたが、例えば以下のように```export```を複数回使う事で複数のコンポーネントを書き出す事ももちろん可能です。


```ts
function checkToken(to: any, from: any, next: any) {
    // トークンチェック
}

function anotherMethod() {
    // 何か他の処理
}

export {checkToken as check};
export {anotherMethod as another};
```

今回参考にさせてもらったVuterialではVueのコンポーネント自体をexportしているのですが、その際は以下のようにexportすると良いようです。

https://github.com/coppieee/vuterial/blob/master/src/components/index.ts

```ts
import { PluginObject} from 'vue';
import { Vue } from 'vue-property-decorator';
import { SomeComponent } from 'src/some-component'; // カスタムコンポーネント

export const LoginModule: PluginObject<any> = {
    install(vue: typeof Vue, options?: any): void {
        vue.component('コンポーネント名', SomeComponent);
    },
};
```

インストールするコンポーネントが複数あれば、やはり複数回```vue.component```を呼び出す事で複数登録できます。