アバターの画像

@kou_hey3

最終更新日:

ポスト

viteのlib modeを使ってnpmパッケージを公開する

先日 react-use-polling を公開したのですが、その際に使用した vite の lib mode が便利だったので記録。

はじめに

今回 library として作成した react-use-polling は、 React の custom hooks です。
本記事は custom hooks を公開する場合の lib mode の使用に関して記述しています。
言語は TypeScript を使用しているため、本記事では TypeScript での環境として記述していきます。

公開したライブラリのリポジトリは、 hey3/react-use-polling です。

lib mode とは

vite.config.tsbuild.lib を設定すると、ライブラリとしてビルドするというものです。

昨今、web の開発環境構築はイージーなものになりました。
vite を使うと、 vite.config にプラグインを設定するのみで構築できるほど簡単になりました。また、エコシステムも充実しており、テストを書くにも vitest を使うことでそれぞれの設定を vite.config に一貫して記述することができます。
この環境を利用しながらライブラリ開発を行う際に、 lib mode も同様に vite.config に設定を記述するだけのため、とても便利です。

各種設定

では、実際にライブラリを開発する際に意識して設定する項目を記述していきます。

vite.config.ts

import { resolve } from 'path'
import reactPlugin from '@vitejs/plugin-react-swc'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [reactPlugin()],
  build: {
    emptyOutDir: false,
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      name: 'MyLib',
      fileName: 'index',
    },
    sourcemap: true,
    rollupOptions: {
      external: ['react'],
      output: {
        globals: {
          react: 'React',
        },
      },
    },
  },
})

重要なのは build.lib です。
build.lib.entry に指定したファイルがエントリーポイントとなります。
build.lib.formats には出力形式を指定することができ、 entry が単体の場合は ['es', 'umd'] で、配列として複数指定された場合は ['es', 'cjs'] となります。

emptyOutDir を指定することで、出力ディレクトリをビルド毎にクリーンにすることができます。
修正の際に過去のビルド結果が残る場合があるので、都度クリーンにしておくほうが安全です。

今回公開したライブラリは React で使われる前提のため、 React 自体は利用者がインストールしているはずです。そのため、バンドルサイズを軽減するためにライブラリ自体には React をバンドルしないようにしたいです。
そこで使用するのが rollupOptions.external となります。
rollupOptions.external に指定したものはバンドルに含まれなくなります。

UMD での利用を考慮する場合、 rollupOptions.output.globals も設定しておくと親切です。

tsconfig.json

{
  "compilerOptions": {
    // ...
    "declaration": true,
    "declarationDir": "./dist/types",
    "declarationMap": true,
    "emitDeclarationOnly": true,
    "noEmitOnError": true
  },
  "include": ["./src/**/*.ts"],
  "exclude": ["./**/dist"]
}

vite は型情報を出力しません。
そのため、型定義ファイル( *.d.ts )は tsc を使って出力しています。

vite-plugin-dts などのプラグインを使うことも可能ですが、個人的には公式のものを使いつつ処理は分けておいた方が好みです。

package.json

{
  "name": "my-lib",
  "main": "./dist/index.umd.js",
  "module": "./dist/index.mjs",
  "types": "./dist/types/index.d.ts",
  "files": ["dist"],
  "exports": {
    ".": {
      "types": "./dist/types/index.d.ts",
      "import": "./dist/index.mjs",
      "require": "./dist/index.umd.js"
    }
  },
  "sideEffects": false,
  "scripts": {
    "prebuild": "rimraf dist",
    "build": "tsc && vite build",
    "prepare": "npm run build"
  },
  "peerDependencies": {
    "react": ">= 16.8.0"
  }
}

package.json にはビルドの出力に合わせて設定を記述します。

vite のデフォルトの出力先は dist であるため、 files'dist' を指定します。
その他型定義ファイルの指定や、エントリーポイントを指定します。この辺りは vite の使用に限りません。

vite.config.ts にて、 React をバンドルに含めないようにしているため、 peerDependencies に React を指定しておくと親切です。

prepare を指定しておくことで、 npm publish 時にビルドを行います。
出力結果の確認は、 npm pack コマンドで確認できるため、 publish 前に確認すると良さそうです。

まとめ

今回、 vite の lib mode を使ったライブラリ開発をしてみて「これは便利だな」と思ったので、メモとして淡々と設定周りを記述しました。

vite を使うことで、開発やテスト、ビルド周りの設定が簡単になったのでめちゃくちゃ良いですね。

記事一覧に戻る