Reactコンポーネントライブラリを作ろう!npmパッケージ開発入門

こんにちは!今回は、npmパッケージの作り方について学んだ内容をまとめてみました。特にReactコンポーネントをライブラリとして公開する方法を中心に、初心者にもわかりやすく解説していきます。

目次

npmパッケージって何?

npmパッケージとは、簡単に言うと「みんなで使える便利なコードの塊」のことです。例えば、日付を扱うライブラリや、UIコンポーネントなど、一度作ったものを他の人も使えるように公開できる仕組みです。

事前準備:npmアカウントを作ろう

まずはnpm公式サイトでアカウントを作成します。

知っておきたいポイント:

  • 無料プランではパブリック(公開)パッケージのみ作成可能
  • プライベート(非公開)パッケージには有料プランが必要
  • 個人開発なら基本的に無料プランで十分!
Pro Teams Pricing Documentation npm Search packages Search Sign Up Sign In Build amazing things We’re GitHub, the company behind the npm Registry and npm CLI. We offer those to the community for free, but our day job is building and selling useful tools for developers like you. Take your JavaScript development up a notch

ステップ1:基本的なnpmパッケージを作ってみよう

プロジェクトの初期化

mkdir study-package
cd study-package
npm init --scope=@your-username

--scopeをつけることで、@your-username/package-nameという形式のパッケージが作れます。これの嬉しいポイントは:

  • 名前の衝突を避けられるreact-datepickerという名前が取られていても、@your-username/react-datepickerなら使える
  • ブランド化:自分専用の名前空間ができる

package.jsonの重要なポイント

{
  "name": "@your-username/study-package",
  "version": "0.1.0",
  "main": "index.js",
  "scripts": {
    "build": "tsc"
  }
}

バージョンについて:

  • 0.1.0から始めるのが一般的(完成前のため)
  • 左から順に:メジャー.マイナー.パッチ
  • 開発中は主にマイナーとパッチを上げていく

簡単なサンプルを作成

// index.js
console.log("Hello");

パッケージを公開

npm publish --access public

注意: 無料プランでは--access publicが必須です!

ステップ2:TypeScriptに対応させよう

TypeScriptの導入

npm install --save-dev typescript
npx tsc --init

ES Modulesに対応

// index.mjs (ES Modules用)
export function sayHello() {
    console.log("Hello World");
}

ポイント:

  • .mjs拡張子でES Modulesとして認識される
  • requireではなくimport/exportを使用
  • package.jsonのmainindex.mjsに変更が必要

TypeScriptファイルの作成

// src/index.ts
export function sayHello(): void {
    console.log("Hello World");
}

ビルド設定(tsconfig.json)

{
  "compilerOptions": {
    "target": "ES2016",
    "module": "ESNext",
    "outDir": "./dist",
    "declaration": true,
    "jsx": "react"
  },
  "include": ["src/**/*"]
}

重要: declaration: trueを忘れずに!これで型定義ファイル(.d.ts)も一緒に生成されます。

ステップ3:Reactコンポーネントライブラリを作ろう

必要なパッケージをインストール

npm install react react-dom
npm install --save-dev @types/react @types/react-dom

Reactコンポーネントの作成

// src/index.tsx
import React from 'react';

export const HelloComponent: React.FC = () => {
    return <div>Hello World</div>;
};

Rollupを使ったビルド設定

Reactコンポーネントをビルドするには、TypeScriptコンパイラだけでは不十分です。ここでRollupの登場です。

Rollupとは?

  • ES Modulesネイティブなバンドラー
  • ライブラリ開発に特化
  • Tree-shakingが優秀
  • Webpackよりもライブラリビルドに適している

WebpackとRollupの違い:

  • Webpack: アプリケーション開発向け、CommonJS時代から存在
  • Rollup: ライブラリ開発向け、ES Modulesネイティブ

Rollupの設定

npm install --save-dev rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-typescript tslib
// rollup.config.mjs
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import pkg from './package.json' assert { type: 'json' };

export default {
  input: 'src/index.tsx',
  output: [
    {
      file: pkg.main,
      format: 'cjs',
      sourcemap: true,
    },
    {
      file: pkg.module,
      format: 'esm',
      sourcemap: true,
    },
  ],
  plugins: [
    resolve(),
    commonjs(),
    typescript({
      tsconfig: './tsconfig.json',
    }),
  ],
};

プラグインの役割:

  • resolve: node_modulesの依存関係を解決
  • commonjs: CommonJS形式のライブラリを読み込み可能に
  • typescript: TypeScriptのコンパイル

package.jsonの調整

{
  "name": "@your-username/study-package",
  "version": "0.1.0",
  "main": "dist/cjs/index.js",
  "module": "dist/esm/index.js",
  "types": "dist/index.d.ts",
  "files": ["dist"],
  "scripts": {
    "build": "rollup -c",
    "publish:patch": "npm version patch && npm publish --access public",
    "publish:minor": "npm version minor && npm publish --access public",
    "publish:major": "npm version major && npm publish --access public"
  },
  "devDependencies": {
    "typescript": "^4.9.5",
    "rollup": "latest",
    "@rollup/plugin-node-resolve": "latest",
    "@rollup/plugin-commonjs": "latest",
    "@rollup/plugin-typescript": "latest",
    "tslib": "latest"
  },
  "peerDependencies": {
    "react": ">=16.8.0",
    "react-dom": ">=16.8.0"
  }
}

重要なフィールド:

  • main: CommonJS形式のエントリーポイント
  • module: ES Modules形式のエントリーポイント
  • types: TypeScript型定義ファイル
  • files: 配布に含めるファイル
  • peerDependencies: ユーザー側でインストールしてもらう依存関係

ステップ4:不要ファイルを除外しよう

.npmignoreの作成

src/
tsconfig.json
rollup.config.mjs
.git/
node_modules/
*.log

これにより、ソースファイルや設定ファイルがパッケージに含まれなくなります。

メリット:

  • パッケージサイズの削減
  • セキュリティの向上
  • ユーザーの混乱を防げる

バージョン管理のベストプラクティス

セマンティックバージョニング

バージョン番号はメジャー.マイナー.パッチの形式で管理します:

  • パッチ: バグ修正(0.1.0 → 0.1.1)
  • マイナー: 機能追加(0.1.0 → 0.2.0)
  • メジャー: 破壊的変更(0.1.0 → 1.0.0)

npmコマンドでバージョンアップ

npm version patch  # 0.1.0 → 0.1.1
npm version minor  # 0.1.0 → 0.2.0
npm version major  # 0.1.0 → 1.0.0

便利なスクリプト

{
  "scripts": {
    "build": "rollup -c",
    "publish:patch": "npm version patch && npm publish --access public",
    "publish:minor": "npm version minor && npm publish --access public",
    "publish:major": "npm version major && npm publish --access public"
  }
}

実際に使ってみよう

テストプロジェクトでの確認

mkdir test-project
cd test-project
npm init -y
npm install @your-username/study-package

Next.jsプロジェクトでの使用例

npx create-next-app@latest test-app --typescript
cd test-app
npm install @your-username/study-package
// pages/index.tsx
import { HelloComponent } from '@your-username/study-package';

export default function Home() {
  return (
    <div>
      <h1>Welcome to Next.js</h1>
      <HelloComponent />
    </div>
  );
}

よくあるトラブルと解決方法

1. 型定義が見つからない

症状: TypeScriptで型エラーが出る

解決方法:

  • tsconfig.jsondeclaration: trueを設定
  • package.jsontypesフィールドを正しく指定

2. ビルドが失敗する

症状: npm run buildでエラー

解決方法:

  • 必要な依存関係がインストールされているか確認
  • tslibがインストールされているか確認
  • Rollup設定ファイルの構文をチェック

3. パッケージが見つからない

症状: npm publish後にインストールできない

解決方法:

  • --access publicオプションを付けているか確認
  • npmレジストリへの反映に時間がかかる場合がある(数分待つ)

高度な設定

複数の出力形式に対応

// rollup.config.mjs
export default {
  input: 'src/index.tsx',
  output: [
    // CommonJS
    {
      file: 'dist/cjs/index.js',
      format: 'cjs',
      sourcemap: true,
    },
    // ES Modules
    {
      file: 'dist/esm/index.js',
      format: 'esm',
      sourcemap: true,
    },
    // UMD (ブラウザでも使える)
    {
      file: 'dist/umd/index.js',
      format: 'umd',
      name: 'MyLibrary',
      sourcemap: true,
    },
  ],
  // ...
};

外部依存関係の処理

// rollup.config.mjs
export default {
  // ...
  external: ['react', 'react-dom'],
  output: {
    // ...
    globals: {
      react: 'React',
      'react-dom': 'ReactDOM',
    },
  },
};

まとめ:学んだポイント

  1. npm initでプロジェクト初期化(--scopeでネームスペース作成)
  2. TypeScriptで型安全なライブラリ開発
  3. RollupでReactコンポーネントのビルド
  4. CommonJSES Modules両対応で互換性確保
  5. 型定義ファイルで開発者体験向上
  6. npmignoreで配布ファイルの最適化
  7. セマンティックバージョニングで適切なバージョン管理

次のステップ

機能拡張

  • より複雑なコンポーネントの作成
  • Tailwind CSSとの組み合わせ
  • テーマシステムの実装

開発環境改善

  • Storybookでコンポーネントカタログ作成
  • Jestでユニットテスト導入
  • Cypressでインテグレーションテスト

CI/CD構築

  • GitHub Actionsで自動ビルド・テスト
  • 自動リリース機能
  • コードカバレッジ測定

ドキュメント整備

  • README.mdの充実
  • JSDocでAPI仕様書作成
  • 使用例の追加

おわりに

ライブラリ開発は最初は複雑に感じますが、一度慣れてしまえば自分の作ったコンポーネントを世界中の人に使ってもらえる素晴らしい体験です。

実際に有名なOSSライブラリにコントリビュートしている開発者の中には、海外企業からオファーをもらったり、国内でも高い評価を受けているケースがあります。

まずは小さなライブラリから始めて、徐々に機能を拡張していきましょう。皆さんの作るライブラリが、誰かの開発を助ける日が来ることを楽しみにしています!

ぜひチャレンジしてみてください!🚀

この記事を書いた人

目次