ys memos

Blog

npmにtypescriptで開発したpackageを公開するための方法


npm

2021/09/28


先日,初めて npm に package を公開した(リンク).

苦戦した点もいくつか合ったので,同じ問題に直面した方のために,記録を残す.

package 内容は README にあるとおり,React Hooks の State で配列の操作を簡単にするカスタムフックである.

ソースコードは TypeScript を用いて開発し,完成物となる package には rollup により es/umd それぞれ作りつつ,もちろん型定義 d.ts も詰め込み,npm に publish した.


以下の順に紹介していく.

  1. ディレクトリ構成
  2. 手順
  3. 各ファイルの内容や意味

普段の React 開発は./src/にソースコードを入れるが,今回は最終的に以下のようなディレクトリ構成にした.

dir_structure
.
├── demo
├── dist
│   ├── index.d.ts
│   ├── index.es.js
│   └── index.umd.min.js
├── .gitignore
├── jest.config.js
├── lib
│   ├── index.ts
│   ├── useArrayAction.test.ts
│   ├── useArrayAction.ts
│   ├── useArray.test.ts
│   ├── useArray.ts
│   ├── useArray.types.ts
│   ├── useRecoilArray.test.ts
│   └── useRecoilArray.ts
├── LICENSE
├── package.json
├── README.md
├── rollup.config.js
├── tsconfig.json
└── webpack.config.js

npm への publish 自体は,npm publishをするだけで簡単に可能である.

publish するための設定はpackage.jsonに記載する.

しかし,私の場合そのまま publish してもうまくインポート出来なかった.(TypeScript だから?)

そのため,下で紹介する rollup を実行した後に publish する.

publish するためのコマンドは以下.

step_to_publish
$ npm login   # if you need
$ npm test    # if you need
$ rollup -c
$ npm publish # (--access=public)

package が動作するデモのソースコードを配置した(普通の ReactApp).

本来は依存をできるだけ少なくして package 使用者が転用できるようにするべきとも思ったが,今回は横着して material-ui を使ってしまった.

デモアプリの公開は Firebase Hosting を使い,リンクをREADME.mdに記載した.

.gitignoreした.

これは,パッケージングされるディレクトリであり,package 使用時にインポートする場所となる.

ちなみに,私の場合はindex.umd.min.js/index.es.js/index.d.tsの 3 ファイルが生成される.

ここをパッケージングするというのは npm のコマンドで指定されているわけではなく,package.jsonで指定するため,好みの名前にしても良い.

.gitignoreである.

テストの設定.

書くと長くなりそうで,かつ,publish するために必須ではないため今回は割愛.

*.test.tsはテスト.それ以外がライブラリである.

テストは書くと長くなりそうで,かつ,(以下略).

importexport は結構好みが分かれると思うが,私の場合は「すべてを持つ Object を default export,それぞれも namede import 可能」という形式をとった.

lib
├── index.ts          # 他のファイルから関数をimportしexport,defaultで全部をexport
├── useArrayAction.ts # 再利用性のあるコードなのでファイル分割した
├── useArray.ts       # react hooks
├── useArray.types.ts # 好みの問題でファイル分割した
└── useRecoilArray.ts # react hooks

LICENSE である.

依存や開発環境依存などが記録されるおなじみのヤツ.

package 用に記載した項目のみ以下に記す.

<your-xxx>のようになっている部分を好みで書き換えると良い.(テストのための設定は,混乱を避けるために手動で削除した.)

package.json
{
  "name": "<package-name>",
  "description": "<your-description>",
  "version": "<your-version(ex: 0.1.0)>",
  "author": {
    "name": "<your-name>",
    "url": "<your-url>"
  },
  "repository": {
    "type": "git",
    "url": "<your-repository>"
  },
  "license": "<your-license>",
  "keywords": ["<your-keywords>"],
  "main": "dist/index.umd.min.js",
  "module": "dist/index.es.js",
  "types": "dist/index.d.ts",
  "files": ["dist"],
  "private": false,
  "dependencies": {
    ...
  },
  "scripts": {
    "test": "jest --env=jsdom --verbose",
    "build": "rollup -c",
    "prepublish": "npm run build",
    "publish": "npm publish",
  },
  "devDependencies": {
    "@rollup/plugin-babel": "^5.3.0",
    "@rollup/plugin-typescript": "^8.2.5",
    "rollup": "^2.57.0",
    "rollup-plugin-dts": "^4.0.0",
    "rollup-plugin-terser": "^7.0.2",
    "tslib": "^2.3.1",
  }
}

package の特徴や使い方,API 一覧などを記入する.

これは,npm の package のページにそのままドキュメントとして扱われつつ,ユーザがインストールした時にライブラリとともにダウンロードされる.

開発したライブラリをいい感じにまとめてくれる rollup の設定ファイル.

内容は以下(js で開発したソースのためには,typescript/dtsを消すと良い).

ちなみに,es_config/dts_config/umd_configについては,変数にせずに一つの配列としてdefault exportしてもよい.

rollup.config.js
import typescript from '@rollup/plugin-typescript';
import dts from 'rollup-plugin-dts';
import babel from '@rollup/plugin-babel';
import { terser } from 'rollup-plugin-terser';

const entry = 'lib/index.ts';

const es_config = {
  input: entry,
  output: {
    file: 'dist/index.es.js',
    format: 'es',
  },
  external: ['react', 'recoil'],
  plugins: [
    typescript(),
    babel({
      extensions: ['.ts'],
    }),
  ],
};

const dts_config = {
  input: entry,
  output: {
    file: 'dist/index.d.ts',
    format: 'es',
  },
  plugins: [dts()],
};

const umd_config = {
  input: entry,
  output: {
    file: 'dist/index.umd.min.js',
    format: 'umd',
    name: 'StructuredState',
    exports: 'named',
    indent: false,
    globals: {
      react: 'react',
      recoil: 'recoil',
    },
  },
  external: ['react', 'recoil'],
  plugins: [
    typescript(),
    babel({
      extensions: ['.ts'],
      exclude: 'node_modules/**',
    }),
    terser(),
  ],
};

export default [es_config, dts_config, umd_config];

cra で生成されるやつを活用. 以下の項目を変更. ただし,以下の項目は変更した.

tsconfig.json
    "declaration": false,

無くてもいける.


最初は TypeScript ファイルをそのまま publish してしまい,謎のエラーを吐いて,焦って unpublish したりと,非常に苦戦した.

unpublish したら 24 時間程度 publish できなくなる点に注意.


開発中にタブを消してしまったので,若干不足しているページもあると思いますが...

以上の参考は publish に際しての参考で,本記事の内容は自分のリポジトリを参考にしました.

ちなみに,ライセンス表示の形式は,いい感じ書き方が無いかと模索した結果,react・angular のリポジトリをミックスして書きました.

世界中の素晴らしいコードを自由に閲覧し勉強できるオープンソースは素晴らしいですね.感謝感謝です.

関連タグを探す