セキュリティを考慮した最新のnpmパッケージ作成のベストプラクティス
2025年2月4日
0 分で読めますテクノロジーは常に変化しており、プロセスやプラクティスもその変化に対応していく必要があります。npmは2025年時点で15年の歴史がありますが、npmパッケージの作成に関するプラクティスは、できればもっと最新のものにしておきたいところです。少し古くなっているかもしれないと思ったら、ぜひ読み進めてください。
このチュートリアルでは、2025年時点の最新のベストプラクティスに沿って、npmパッケージを作成する手順を一つずつ解説します。まずはnpmパッケージの作成方法を学び、npmレジストリへのパッケージのビルドと公開に慣れていきましょう。次に、テストフレームワーク、継続的インテグレーション/デプロイメントのパイプライン、セキュリティチェック、自動化されたセマンティックバージョン管理によるリリースを設定し、より堅牢で本番環境に対応したnpmパッケージを作る方法を学びます。このチュートリアルを終えるころには、最新かつ持続可能なnpmパッケージを作成できる自信が身についているでしょう。それでは始めましょう。
前提条件
1. Node.js、JavaScript/TypeScript、GitHub、GitHub Actionsの基本的な知識
2. npmパッケージの作成を支援する開発ツールが利用できること
シンプルなnpmパッケージの例
まずは、シンプルな例を使ってnpmパッケージの作成と公開の流れを確認しましょう。すでにご存じの場合は、より高度な内容を扱う本番環境に対応したnpmパッケージのセクションに進んでください。
プロジェクトをセットアップする
始めるにはGitHub上にプロジェクトが必要です。次の手順に沿ってプロジェクトを作成してください。すでに利用できるプロジェクトがある場合は次のセクションに進んでも構いませんが、このセクションのステップ5でパッケージ名を確認することを忘れないでください。
GitHubリポジトリを作成します: https://github.com/new
リポジトリをローカルにクローンします。
例:git clonehttps://github.com/snyk-snippets/simple-npm-package.gitターミナルを開き、クローンしたプロジェクトのフォルダーに移動します。
例:cd simple-npm-packagenpm init -yを実行してpackage.jsonファイルを作成します。注: サンプルリポジトリをクローンした場合、この手順は不要です。package.jsonのnameプロパティを、スコープ付きの名前に更新します。
例:@clarkio/simple-npm-package。@clarkioの代わりに、自分のユーザー名または組織名を使用してください。パッケージのコードを作成します(またはindex.jsのHello Worldの例をそのまま使います)。
プロジェクトを作成したら、npmアカウントの作成に進みましょう。
npmアカウントをセットアップする
npmパッケージを他の人が利用できるように公開するには、npmアカウントが必要です。以下の手順では、アカウントをまだお持ちでない場合の新規作成、アカウントのセキュリティを高めるための2要素認証(2FA)の有効化、ローカルマシンへのアカウント接続の方法を説明します。
1. https://www.npmjs.com/signupでnpmに登録します。
2. セキュリティを強化するため、npmアカウントで2FAを有効にします: https://docs.npmjs.com/configuring-two-factor-authentication
3. ターミナルでnpm loginコマンドを実行してnpmアカウントにサインインし、画面の指示に従います。例:
npmパッケージを公開する方法
npmプロジェクトとnpmアカウントを用意したら、公式のnpmjsパブリックレジストリにnpmパッケージを公開し、他の人が利用できるようにしましょう。公開前に公開対象を確認し、実際に公開するまでの手順は次のとおりです。
ターミナルで
npx pack --dry-runを実行し、パッケージの公開バージョンに含まれるファイルを確認します。
これにより、パッケージを正しく動作させるために必要なソースコードファイルが漏れていないことを確認できます。また、データベースの認証情報やAPIキーが含まれるローカル設定ファイルなど、機密情報を誤って公開しないように確認することも大切です。
2. ターミナルでnpm publish --dry-runを実行し、コマンドを実際に実行した場合の処理を確認します。
3. ターミナルでnpm publish --access=publicを実行し、パッケージをnpmに公開します。注: スコープ付きパッケージ(@clarkio/modern-npm-package)はデフォルトで非公開のため、--access=publicが必要です。スコープがなく、package.jsonの非公開フィールドがtrueに設定されていない場合も、パッケージは公開されます。
これで完了です。独自のnpmパッケージをビルドしてデプロイできました。続いて、本番環境で利用でき、より幅広く使える堅牢なパッケージの作成方法を学びましょう。
本番環境に対応したnpmパッケージ
先ほどのサンプルパッケージも本番環境で利用できる可能性はありますが、継続的なメンテナンスには手作業が必要です。ツールや自動化に加えて、適切なテストとセキュリティチェックを取り入れることで、パッケージを円滑に運用し続けるための総作業量を削減できます。具体的な方法を詳しく見ていきましょう。
以下のセクションでは、次の内容を扱います。
1. modern-npm-packageプロジェクトのセットアップ
2. ECMAScript(ESM)モジュール形式向けのビルド
3. ユニットテストのセットアップと作成
4. セキュリティチェックの導入
5. バージョン管理と公開の自動化
この記事を読み進める際に使えるプロジェクトをお持ちでない場合は、次のサンプルプロジェクトを参考にしてください: https://github.com/snyk-snippets/modern-npm-package。
ECMAScriptモジュール形式向けのビルド
ECMAScriptモジュール形式は、Node.jsバージョン12以降でネイティブにサポートされています。最新の長期サポート(LTS)バージョンは22.xです。また、Bun.jsやDenoといった選択肢が登場し、JavaScriptランタイムの競争も進んでいます。これらの環境では、ESM形式を簡単に利用できます。ここではTypeScriptを使って、npmパッケージをESM形式に対応させます。
まず、
tsconfig.jsonという名前のTypeScript設定ファイルを作成します。このファイルでは、ESMを使ってパッケージをビルドする際のコンパイル設定を指定します。プロジェクトに合わせて自由に調整してください。特に、サンプルとは異なるプロジェクト構成を使う場合は、filesプロパティを構成に合わせて変更しましょう。
libプロパティは、プロジェクトのコードを書く際にTypeScriptが参照する型を指定します。targetプロパティは、プロジェクトのコードをどのJavaScriptバージョンにコンパイルするかをTypeScriptに指定します。moduleプロパティは、プロジェクトのコードをコンパイルする際に使用するJavaScriptモジュール形式をTypeScriptに指定します。moduleResolutionプロパティは、TypeScriptが「import」文の参照先を判断するのに役立ちます。outDirとdeclarationDirの各プロパティは、コードのコンパイル結果と、コード内で使用する型定義の出力先をTypeScriptに指定します。
2. package.jsonファイルにfilesフィールドを追加し、TypeScriptによるビルド結果を格納するlibフォルダーを指定します。
3. package.jsonファイルのmainフィールドとtypes フィールドを更新し、ビルド/コンパイル済みパッケージの出力先を指定します。これらのフィールドはデフォルトのフォールバックとして機能します。
4. package.jsonファイルにfilesフィールドを追加し、npmが公開用にコードをパッケージ化する際に含めるファイルを指定します。
5. package.jsonのscriptsフィールドでコマンドを作成し、tscを使ってパッケージをコンパイルします。これにより、libフォルダーにソースファイルが生成されます。
cleanスクリプトは、過去のビルド出力を削除し、クリーンな状態から始めるために使用します。buildスクリプトは、過去の出力ファイルを削除してから、TypeScriptコンパイラーを使ってパッケージを出力ディレクトリにビルドします。prepackスクリプトは、レジストリへの公開準備としてnpmがパッケージを作成する前に実行されます。
6. これらを動作させるために必要な開発用依存関係をインストールします。npm install -D typescript del-cliを実行してください。
7. これでターミナルからnpm run buildを実行し、利用と公開に向けてTypeScriptでプロジェクトをビルドできます。
以上で、CommonJSとECMAScriptモジュール形式に対応したnpmパッケージをTypeScriptでビルドするためのセットアップは完了です。次に、npmパッケージのコードが期待どおりの結果を出すことを確認するため、テストをセットアップして実行する方法を説明します。
テストのセットアップと追加
コードの動作と結果に確信を持つには、テストプロセスを導入する必要があります。テストを行うことで、コードを作成するときに想定する通常の成功パターン以外にも、さまざまな観点から機能について考えるようになります。たとえば、関数にエラーを発生させたり、意図しない結果を返させたりする方法を検討できます。こうすることで、アプリケーションの耐障害性と持続可能性が高まり、機能を追加したときに既存の動作が壊れないことも確認できます。
テストについてさらに詳しく学び、ベストプラクティスを知りたい方は、Yoni GoldbergのJavaScript Best Practicesリポジトリをご覧ください。
ユニットテスト
パッケージが意図したとおりに動作することを確認するには、コードに対するテストを作成する必要があります。ユニットテストを実行し、その結果を表示するようプロジェクトをセットアップするには、いくつかのツールが必要です。これらのツールは、Node.jsの組み込みモジュールとして利用できます(バージョン20.xおよび18.xから。16.17.xでは実験的フラグが必要です)。以下の手順に沿って、npmパッケージのテストをセットアップして実行してください。
ターミナルで次のコマンドを実行して、開発用依存関係をインストールします:
npm i -D @types/nodeプロジェクトのルートディレクトリに
testsフォルダーを作成します。testsフォルダーにindex.test.tsファイルを作成します。index.test.tsファイルにユニットテストを記述し、index.tsのコードをテストします。
注: npmパッケージのサンプルリポジトリを参考にできます: https://github.com/snyk-snippets/modern-npm-package。
5. package.jsonファイルのscriptsセクションにtestsプロパティを追加し、値にnode --experimental-strip-types --testを指定します。
6. プロジェクトのルートフォルダーからターミナルでnpm testを実行し、テストを実行して結果を確認します:
パイプラインでのテスト
コードの動作を検証するテストが用意できたら、パイプラインで実行できます。これにより、リポジトリへの変更によってコードの動作が壊れないことを確認できます。以下の手順に沿って、プロジェクトのパイプラインにテストワークフローを作成しましょう。
リポジトリ用のGitHub Actionを新規作成します:
https://github.com/<your-account-or-organization>/<your-repo-name>/actions/newワークフローの名前を
tests.ymlに変更します。次のSnyk GitHub Actionスクリプトをワークフローファイルに挿入します:
このYAMLスクリプトは、最新のコードをチェックアウトして依存関係をインストールし、npm testコマンドを実行してテストします。node-versionフィールドに記載されたNode.jsの各バージョンで実行するため、それぞれのランタイムでコードが期待どおりに動作することを確認できます。
これで、npmパッケージのコードに対するテストを実行・評価するためのプロジェクト設定が完了しました。ただし、「別のプロジェクトで自分のnpmパッケージを使ってテストするにはどうすればいいのだろう」と思っているかもしれません。次に、その方法を見ていきましょう。
パッケージのテスト
npmパッケージのコードにユニットテストを通じて自信を持つことと、npmパッケージ全体の使用感を確かめることは別の話です。後者では、npmパッケージを別のプロジェクトの依存関係として取り込み、想定どおりスムーズに使えるかを確認します。テスト方法を5つ紹介します。
npm packの出力を使ってインストール相対パスを使ってインストール
npm linkを使ってインストールレジストリを使ってインストール(npmjs.comにあるnpm公式パブリックレジストリなど)
Verdaccio(オープンソースのnpmプライベートレジストリプロジェクト)を使い、CIの一環としてパッケージの公開からインストールまでのエンドツーエンドテストを実行する
npm pack
この方法では、npm packコマンドを使ってnpmパッケージをまとめ、1つのファイル(<package-name>.tgz)に圧縮します。その後、パッケージを使用するプロジェクトに移動し、このファイルを使ってインストールできます。手順は次のとおりです。
npmパッケージのディレクトリで、ターミナルから
npm packを実行します。生成された.tgzファイルとその保存場所を確認してください。npmパッケージを使用するプロジェクトのディレクトリに移動します。例:
cd /path/to/projectclientプロジェクトのディレクトリで、
npm install /path/to/package.tgzを実行します。手順1で確認した.tgzファイルの場所に合わせて、パスを置き換えてください。これで、clientプロジェクトでパッケージを使い、動作をテストできます。
この方法なら、npmパッケージを本番環境で使う場合に最も近い体験を確認できます。
npm link
この方法では、npm linkコマンドを使って、clientプロジェクトへのインストール時にパッケージのディレクトリを参照します。手順は次のとおりです。
npmパッケージのディレクトリで、ターミナルから
npm linkを実行します。npmパッケージを使用するプロジェクトのディレクトリに移動します。例:
cd /path/to/projectclientプロジェクトのディレクトリで、
npm link <name-of-your-package>を実行します。
これにより、コード内でパッケージを参照するときに、clientプロジェクトからnpmパッケージのディレクトリを参照するようになります。パッケージを本番環境に近い形で使う体験は得られませんが、想定どおりに機能することを確認できます。
相対パス
この方法では、使い慣れたnpm installコマンドを利用します。npm linkに似ていますが、linkのような新しいコマンドを覚える必要はありません。
clientプロジェクトのディレクトリで、ターミナルから
npm install /path/to/your/packageを実行します。
npm linkと同様に、クライアントプロジェクト内ですばやくパッケージの機能をテストできますが、本番環境に近い体験は得られません。npmレジストリにあるビルド済みのパッケージではなく、パッケージのソースコードがあるディレクトリ全体を参照するためです。つまり、レジストリに公開されているビルド済みバージョンは使いません。
npmレジストリ
この方法では、npmパッケージ用のパブリックレジストリ(または独自のレジストリ)を利用します。パッケージを公開し、他のnpmパッケージと同じようにインストールします。
この記事の前半で説明した手順に従い、
npm publishコマンドでnpmパッケージを公開します。npmパッケージを使用するプロジェクトのディレクトリに移動します。例:
cd /path/to/projectclientプロジェクトのディレクトリで、
npm install <name-of-your-package>を実行します。
ライブ配信中に得た知見をまとめたTwitterのスレッドを作成してくれたMirco Kraenz(@MKraenz)に感謝します。
これで、最新のモジュール形式に対応したパッケージを構築し、ユニットテストとパッケージングテストを通じて想定どおり動作することを確認できました。次は、npmパッケージにセキュリティ上の問題がないことを確かめ、新たな問題の混入を防ぐ必要があります。
セキュリティチェックの実装
自分のプロジェクトにセキュリティ脆弱性を持ち込みたくないのと同じように、他の人のプロジェクトにも脆弱性を持ち込むべきではありません。多くのプロジェクトで利用されるnpmパッケージを構築するには、安全性を確保するための責任がより大きくなります。脆弱性を監視し、アラートを出し、軽減を支援するセキュリティチェックが必要です。こうした作業を簡素化できるのがSnykのようなツールです。
このnpmパッケージの例では、ソース管理ツールとしてGitHubを使うため、GitHub Actions機能を利用してワークフローにSnykを統合します。Snykには、この作業をすぐに始めるのに役立つGitHub Actionsのリファレンスプロジェクトがあります。利用する可能性のある他のプログラミング言語やツールの例も紹介しています。
1. Snykは無料で利用できます。登録してSnyk API Tokenを取得しましょう。
2. Snyk API TokenをGitHubのリポジトリシークレットとして追加します。https://github.com/<your-account-or-organization>/<your-repo-name>/settings/secrets/actions/new
3. リポジトリ用の新しいGitHub Actionを作成します。https://github.com/<your-account-or-organization>/<your-repo-name>/actions/new
4. ワークフローの名前をsnyk.ymlに変更します。
5. 次のSnyk Actionスクリプトをワークフローファイルに挿入します。
6. 変更をコミットします。
7. Actionが正常に実行されたことを確認します。 https://github.com/<your-account-or-organization>/<your-repo-name>/actions
これで設定は完了です。リポジトリに誰かがプッシュしたり、プルリクエストを作成したりするたびに、パッケージに脆弱性が持ち込まれないかを確認するセキュリティチェックが実行されます。問題が見つかった場合、Actionは失敗し、検出されたセキュリティ問題の詳細を通知します。次は、npmパッケージのバージョン管理と公開のプロセスを自動化しましょう。
リポジトリに変更をプッシュする前にセキュリティ問題を把握したいですか?お好みの開発ツールにSnykプラグインをインストールしましょう。CLIツールを使いたい場合は、Snyk CLIもツールチェーンに追加してください。開発中にセキュリティ問題を検出し、プロジェクトのワークフローの早い段階で通知を受け取れます。
現在の設定では、Snyk Open Source(SCA)のみを利用しており、Snyk Code(SAST)は利用していない点にご注意ください。Snyk Codeは当社のコードセキュリティ製品です。最大限活用するには、まずSnykアカウントで(無料で)有効にしてから、こちらのワークフロースクリプトに追加してください。パイプラインでのSnyk Codeの使い方については、GitHub Actionsでセキュアなパイプラインを構築するの記事をご覧ください(この記事ではJavaとMavenを使用していますが、Node.jsとnpmに置き換えられます)。
バージョン管理と公開の自動化
mainブランチの変更をマージするたびに、npmパッケージのバージョンを手動で更新し、公開するのは避けたいものです。代わりに、このプロセスを自動化しましょう。この記事の前半で紹介したシンプルなnpmパッケージの例で、次のコマンドを使ってパッケージを公開したことを覚えているでしょうか。
また、業界標準のセマンティックバージョニングに従うことで、レジストリに公開するバージョンの変更がどのような影響をもたらすのか、パッケージの利用者に伝えられます。
セマンティックバージョニングとは?
セマンティックバージョニングでは、バージョンを3つの要素で表します。1つ目がメジャーバージョン、2つ目がマイナーバージョン、最後がパッチバージョンです。セマンティックバージョニング、バージョン管理、ロックファイルについて詳しくは、Package Lock JSONとは?ロックファイルとYarn・NPMパッケージの仕組みをご覧ください。
これらの作業を手動で行わず、npmパッケージの公開を処理するGitHub Actionsの自動ワークフローを設定できたらどうでしょうか。朗報です。Semantic Releaseというツールがあり、GitHub Actionsと連携できます。このプロセスを自動化する鍵は、プロジェクトの変更をコミットする際にConventional Commitsを使うことです。これにより、必要な更新を自動で行い、次のリリースをどのように準備すべきか判断できるようになります。
次の手順に沿って、最新のnpmパッケージ向けに設定しましょう。
1. ターミナルで次を実行します。npm i -D semantic-release
2. ターミナルで次を実行します。npx semantic-release-cli setup
3. ターミナルのプロンプトに従い、必要なトークンを入力します。
GitHubの個人アクセストークンが必要です。作成するには、
https://github.com/settings/tokens/new?scopes=public_repoにアクセスします。このトークンを作成する際は、次のスコープを選択します。

「Generate token」ボタンをクリックし、ページに表示された値をコピーして保存します。
また、アカウントの2FAを回避してCI環境でのみ使用できる、npmのAutomationタイプのアクセストークンも必要です。作成するには、
https://www.npmjs.com/settings/<your-npm-account>/tokensにアクセスします。CI/CDワークフローで使用するため、トークンの種類で「Automation」を選択してください。

4. npmトークンをGitHubリポジトリのリポジトリシークレットとして追加します。https://github.com/<your-name-or-organization>/<your-repository>/settings/secrets/actions/newにアクセスし、シークレット名をNPM_TOKENに設定して、前の手順で取得した値を入力します。

5. プロジェクトに戻り、package.jsonファイルに次のようなreleasesキーを追加します。リポジトリのプライマリブランチがmasterではなく、まだmainという名前の場合は、上記のbranchesの値を適宜変更してください。
6. package.jsonファイルにpublishConfigキーも追加します。
7. semantic-release npmスクリプトを使い、ドライランで動作をテストします。次のコマンドのNPM_TOKEN=とGH_TOKEN=の値を、それぞれのトークンに置き換えてください。その後、コマンド全体をコピーしてターミナルで実行し、正常に動作するか確認します。処理のログはターミナルの出力に表示されます。問題が発生した場合はここに詳細が表示されるため、解決に役立ちます。
8. ドライランが正常に完了したことを確認したら、新しいGitHub Actionを使って公開プロセスを処理するようにGitHubリポジトリを設定します。GitHubでリポジトリを開き、「Actions」をクリックします。
9. New workflowを選択します。
10. ワークフローの名前をrelease.ymlに変更します。
11. 次のYAMLスクリプトを新しいワークフローファイルに追加します。このスクリプトは、Snyk Security Checkの処理が正常に完了したら、リリースジョブを実行するという内容です。リリースジョブでは、コードをチェックアウトし、Node.js環境をセットアップして依存関係をインストールした後、GitHubとnpmのトークンを使ってsemantic-releaseを実行します。
このスクリプトは、Snyk Security Checkとテストが正常に完了したら、リリースジョブを実行するという内容です。リリースジョブでは、コードをチェックアウトし、Node.js環境をセットアップして依存関係をインストールした後、GitHubとnpmのトークンを使ってsemantic-releaseを実行します。
注: GitHub ActionsにはGITHUB_TOKENシークレット/環境変数が組み込まれているため、この環境で個人アクセストークンを指定する必要はありません。PATは、semantic-releaseの設定をローカルでテストする場合にのみ使用します。
12. ローカルの変更をコミットし、GitHubリポジトリにプッシュします。
ターミナルで
git commit -am '<your commit message>'を実行し、続けてgit pushを実行します。VS Codeのバージョン管理機能を使って実行することもできます。
13. すべて設定できたら、Conventional Commitsを使ってメインブランチに変更をプッシュ(またはプルリクエストをマージ)すると、リリースワークフローが実行されます(もちろん、その前にSnyk Security Checkが行われます)。実行例は、modern-npm-packageのリポジトリワークフローで確認できます。
GitHubと連携したSnykによる継続的なセキュリティ監視
コードをコミットするプロセスにセキュリティチェックを直接組み込むのは効果的ですが、コミットの合間に発見された脆弱性を見逃す可能性があります。たとえば、数か月間リポジトリにコードをプッシュしていなければ、その間に新たに発見された脆弱性に気づけません。そんなときにもSnykが役立ちます。GitHubリポジトリをSnykに接続すると、プロジェクトでどれくらいの頻度で開発しているかにかかわらず、新しい脆弱性を自動的に監視して通知します。さらに、セキュリティ上の問題に対処するためのプルリクエストも自動で作成します。
npmパッケージのコードと依存関係のセキュリティ確保に特に役立つSnykの製品が2つあります。Snyk Codeはパッケージのコードを保護し、Snyk Open Sourceはオープンソースの依存関係にある脆弱性を監視します。
無料のSnykアカウントを最大限に活用するには、次の手順に従ってください。
1. 無料のSnykアカウントにサインインする
2. Add projectを選択し、次にGitHubを選択します。

3. プロジェクトのリポジトリを名前で検索し、リポジトリの横にあるチェックボックスをオンにします。

4. リポジトリがSnykに正常にインポートされたことを確認します。

最新のnpmパッケージを作成する
この記事で学んだことを振り返りましょう。まず、シンプルなnpmパッケージをセットアップし、作成してデプロイする方法を学びました。npmパッケージを初めて公開するために必要なことを知るうえで、よい機会になったはずです。しかし、本番環境で使うnpmパッケージを作成する場合、この方法はかなり手作業が多く、持続可能とはいえません。
本番環境で使えるパッケージを作成するため、CommonJS(CJS)とECMAScript(ESM)の両方のモジュール形式向けにビルドする方法、ユニットテストの設定と作成、セキュリティチェックの実装、バージョン管理と公開の自動化について学びました。これらの知識を活用すれば、コミュニティや自社で簡単に利用できるnpmパッケージを、これから数多く作成できるでしょう。
Snykの無料JavaScriptコードチェッカーを試して、コードの脆弱性を見つけて修正しましょう。
CTFを始めよう
オンデマンドのバーチャル入門ワークショップを視聴して、CTFの課題の解き方を学びましょう。
