Edited at

TypeScript で作ったパッケージを TravisCI で npm に公開するときの Tips

More than 1 year has passed since last update.

個人で作った msgpack-rpc-lite という Node.js 向けパッケージを npm で公開しています。その CI 環境には GitHubTravis CICodacy を使っています。

当初 JavaScript で書いていたものを TypeScript で書き直しました。その時悩んだことやハマったことで学んだコツを備忘録としてまとめました。

なお、TypeScript での書き直しで行った変更点は Comparing v0.0.6...v0.1.5 · naokikimura/msgpack-rpc-lite でご覧いただけます。


[Travis CI] skip_cleanup: true でデプロイ前のクリーンアップをスキップする

Travis CI のデプロイは、デフォルトではリリース前に installscript などのそれ以前のステップで追加や変更されたファイルをクリーンアップします。 tsc のコンパイル結果や npm install で取得した依存パッケージは消されてしまいます。それを回避するために deplyskip_cleanup オプションに true を設定します。


.travis.yml

  language: node_js

deploy:
provider: npm
+ skip_cleanup: true
email: "YOUR_EMAIL_ADDRESS"
api_key: "YOUR_AUTH_TOKEN"
on:
tags: true
repo: "YOUR_REPO"


ハマったこと

このような .travis.yml だったとき、デプロイが sh: tsc: command not found となって失敗しました。 install ステップでは失敗しなかったのに、なぜって感じでした。


.travis.yml

language: node_js

node_js:
- "8"
deploy:
provider: npm
email: "YOUR_EMAIL_ADDRESS"
api_key: "YOUR_AUTH_TOKEN"
on:
tags: true
repo: "YOUR_REPO"

Releasing build artifacts - npm Releasing - Travis CI にちゃんと書いてありました。ドキュメントはよく読まないとダメですね。


参考


[npm] .npmignore でパッケージに含めるファイルを制御する

.gitignore がある場合は .npmignore で別途パッケージに含めないファイルを指定しましょう。 .npmignore がないと .gitignore で無視しているファイルはパッケージに含まれません(逆に言うと、必要なファイルがパッケージに含まれないことがあります)。


ハマったこと

tsconfig.jsonoutDir コンパイラーオプションを設定してコンパイル結果の出力先を指定しました。 package.jsonmain フィールドもそれに合わせて変更しました。 また Git のトラッキング対象外するため .gitignore にも追記しました。


tsconfig.json

  {

"compilerOptions": {
"target": "es6",
"module": "commonjs",
+ "outDir": "./dist",


package.json

  {

"name": "msgpack-rpc-lite",
"version": "0.1.1",
- "main": "./index.js",
+ "main": "./dist/index.js",


.gitignore

  coverage

.nyc_output
node_modules/
+ dist/

この状態で npm publish すると、npm はパッケージにコンパイル結果を含めてくれません。公開したパッケージを利用しようとしても Error: Cannot find module 'msgpack-rpc-lite' となってしまいます。

そこで .npmignore.gitignore と同じ場所に作って、パッケージに含めたくないファイルを別途指定しました。なお、 node_modules.npmignore には不要です。

別途指定といいましたが、実際は .gitignore をコピー & リネームして、パッケージに含めたいものを除外エントリーから取り除いただけです。


.npmignore

coverage

.nyc_output


参考


[npm] prepublish / prepublishOnly / prepare の違いを理解する

npm にパッケージを公開するためには、その準備として TypeScript コンパイラー tsc を実行してコンパイル結果を出力しておく必要があります。

npm install の後と npm publish の前の両方で発生する prepare イベントは、 tsc を実行するタイミングとして適しています。

しかし、 Node.js v6 以前 (厳密に言うと npm v4.2.0 より前) は、 prepare イベントは発生しません。そのため、必要であれば適宜自前で npm run prepare と実行する必要があります。 Travis CI であれば before_scriptbefore_deploy のステップが prepare イベント発生に近いタイミングです。


.travis.yml

language: node_js

node_js:
- lts/*
- 6
before_script:
- if [ $(echo "`npm -v 2>&1 | cut -d. -f-2` < 4.2" | bc) -eq 1 ]; then npm run prepare; fi
...
before_deploy:
- if [ $(echo "`npm -v 2>&1 | cut -d. -f-2` < 4.2" | bc) -eq 1 ]; then npm run prepare; fi
...


悩んだこと

TypeScript コンパイラー tsc を npm スクリプトで定義したいけど、どのスクリプトが適切なのかで悩みました。

Travis CI のデプロイライフサイクルは、ざっくりいうと npm i && npm t && npm publish だといえると思います。このライフサイクルで発火するイベントのスクリプトに tsc を実行するように定義したと考えました。


  • build


  • prepublish / prepublishOnly / prepare

悩んだ末、今回は prepare に定義しました。


package.json

{

"name": "msgpack-rpc-lite",
"version": "0.1.3",
"main": "./dist/index.js",
"scripts": {
...
"prepare": "tsc"
},
...
}


build

よく見かけるのが、 build スクリプトで定義しているケース。

ただ、イベントで発火するスクリプトではない様子。 npm installnpm publish と連動して実行してほしいのに。 npm build としても定義したスクリプトは実行されず、 npm run build としないと実行されない。

...なんかしっくりこない。流儀に則っていない感がする。 Visual Studio Code を使っていて、手動ビルドやウォッチはビルドタスクで実行できるので、 build スクリプトとして定義しておく必要性がとくにない。ただ tsc を実行したいだけだし。

あと npm build は何に使うのかがよくわからない。


prepublish / prepublishOnly / prepare

npm publish に連動して実行される prepublish / prepublishOnly / prepare ですが、 npm のバージョンによって振る舞いがかなり異なります。詳しくは npm prepublish の現状と今後どう変わっていくか - Qiita を参照してください。


参考


[TypeScript] モジュールなら宣言ファイル (.d.ts) も公開する

パッケージをモジュールとして公開するなら宣言ファイル (.d.ts) も合わせて公開しましょう。

tscdeclaration コンパイルオプションに true を設定し、 package.jsontypes フィールドに出力される宣言ファイルを設定します。


ハマったこと

公開したパッケージを TypeScript でモジュールとして利用しようと import してコンパイルします。

import * as from 'msgpack-rpc-lite';

すると、次のようなエラーがでます。コンパイラーが「モジュール 'msgpack-rpc-lite' の宣言ファイルが見つかりませんでした。」と怒っています。

error TS7016: Could not find a declaration file for module 'msgpack-rpc-lite'. '~/Documents/workspace/jubaclient/node_modules/msgpack-rpc-lite/dist/index.js' implicitly has an 'any' type.

Try `npm install @types/msgpack-rpc-lite` if it exists or add a new declaration (.d.ts) file containing `declare module 'msgpack-rpc-lite';`

そこで、モジュールの tsconfig.json"declaration": true を追加しました。


tsconfig.json

  {

"compilerOptions": {
"target": "es6",
"module": "commonjs",
+ "declaration": true,
"sourceMap": true,
"outDir": "./dist",
"strict": true,
"esModuleInterop": true
}
"include": [
"src/**/*"
]
}

加えて、 package.json"types": "./dist/index.d.ts" を追加しました。


package.json

  {

"name": "msgpack-rpc-lite",
"version": "0.1.4",
"main": "./dist/index.js",
+ "types": "./dist/index.d.ts",


参考