1. ホーム
  2. JavaScript
  3. かゆいところに手が届く!patch-packageでnpmパッケージを乗りこなそう

かゆいところに手が届く!patch-packageでnpmパッケージを乗りこなそう

目次

  1. はじめに
  2. npmパッケージを修正するには
  3. patch-packageの導入
  4. パッチの作り方
  5. まとめ

はじめに

npmパッケージを利用する際、バージョンの違いなどで動かなかったり、少しだけカスタマイズしたいといったような場面に遭遇することはないでしょうか?そんなときに使える patch-package というツールをご紹介します。

npmパッケージを修正するには

npm install によって追加されたパッケージはプロジェクトのnode_modulesというディレクトリ内に保存されます。
このnode_modules内のファイルを変更してしまえばnpmパッケージを修正できるのですが、いくつか方法があります。

node_modules内を直接修正する方法

node_modules内のファイルは一般的にはJavaScriptですので、そのファイルを直接変更してしまうことが可能です。
しかし、node_modules内のファイルは npm install 時などに上書きされる可能性がありますし、.gitignoreとしてGitの管理から除外することが一般的ですので、その都度修正する必要があり実用的ではありません。

パッケージをForkする方法

npm install で依存関係を追加する際、npmのパッケージ名の他にGitリポジトリのURLやGitHubのプロジェクト名を指定することが可能です。
これを利用して、ライブラリのGitプロジェクトをForkして修正し、依存関係にはそちらのForkしたプロジェクトを追加するという方法があります。
こちらの方法は広く使われているのですが、ちょっとした変更であってもForkしたGitプロジェクトを作成する必要があったり、元となるライブラリの更新に追従していくのが大変だったりと、実際やってみると大変なことが多いです。

postinstallで修正する方法

npmには、package.jsonのscriptsに postinstall という名前のスクリプトを追加すると、 npm install 後に任意のコマンドを実行できるという機能があります。(npmの公式ドキュメント
これを利用して、 npm install 後にnode_modules内のファイルが自動的に修正されるような仕組みになれば良さそうなのですが、ファイル内の特定の部分を修正するスクリプトを自分で書く必要が出てきます。

patch-packageは、複雑なシェルスクリプトを書くことなくpostinstallでパッチを当てることができるツールです。

patch-packageの導入

patch-packageは開発時に使われるツールですので、devDependenciesとして依存関係に追加します。

npmパッケージの使い方については以前の記事も参考にしてみてください。

npm install patch-package --save-dev

その後、package.jsonの scriptsに "postinstall": "patch-package" を追加します。

{
...
scripts: {
...
"postinstall": "patch-package"
}
}

これで npm install 後にpatch-packageが実行されます。

npmコマンドではなくyarnを使う場合、postinstall-postinstallというパッケージも追加することが推奨されています。詳しくはpatch-packageのREADMEを確認してください。

パッチの作り方

例として react-native-parallax-view をみてみましょう。このパッケージはReact NativeのScrollViewにパララックス(視差効果)を追加するものですが、React Nativeのバージョン0.8.0がのころにメンテナンスされていたライブラリで、最新のReact Nativeで動かすにはいくつかの問題点があります。

  • 問題点1: React.PropTypesという廃止された機能を使っている
  • 問題点2: コンポーネントの定義にReact.createClassという廃止された方法を使っている

実際に npm install react-native-parallax-view で依存関係に追加し、 import ParallaxView from 'react-native-parallax-view' という記述をコードに追加すると以下のようなエラーが発生します。

undefined is not an object (evaluating 'React.PropTypes.number')

問題点1のPropTypesというのはFlowやTypeScriptを使わないときにコンポーネントのpropsの型チェックを動的に行うための機能ですが、動作には関係のないところですのでPropTypesを使っているところを全て削除してしまいましょう。

問題点2については、現在の書き方に従うならReact.Componentを継承したクラスに書き換えたいところですが、書き換え箇所が多くなってしまいます。今回は、 create-react-class という互換用のパッケージを使いましょう。

// create-react-classを読み込むために追加
var createReactClass = require('create-react-class'); 
// React.createClassから書き換え
var ParallaxView = createReactClass({

これらの修正を node_modules/react-native-parallax-view/lib/ParallaxView.js に対して直接加えると、エラーが発生しなくなるはずです。(今回は例ですので、実際にParallaxViewを使うのは割愛します)
修正が終わったら、 patch-package <パッチを作りたいパッケージ名> という形式でpatch-packageを実行します。

npx patch-package react-native-parallax-view

正しく実行されていれば、プロジェクト内に以下のような内容の patches/react-native-parallax-view+2.0.6.patch というパッチファイルが作成されていると思います。

patch-package
--- a/node_modules/react-native-parallax-view/lib/ParallaxView.js
+++ b/node_modules/react-native-parallax-view/lib/ParallaxView.js
@@ -9,32 +9,17 @@ var {
ScrollView,
Animated,
} = ReactNative;
+var createReactClass = require('create-react-class');
/**
* BlurView temporarily removed until semver stuff is set up properly
*/
//var BlurView /* = require('react-native-blur').BlurView */;
var ScrollableMixin = require('react-native-scrollable-mixin');
var screen = Dimensions.get('window');
-var ScrollViewPropTypes = ScrollView.propTypes;
-var ParallaxView = React.createClass({
+var ParallaxView = createReactClass({
mixins: [ScrollableMixin],
-    propTypes: {
-        ...ScrollViewPropTypes,
-        windowHeight: React.PropTypes.number,
-        backgroundSource: React.PropTypes.oneOfType([
-          React.PropTypes.shape({
-            uri: React.PropTypes.string,
-          }),
-          // Opaque type returned by require('./image.jpg')
-          React.PropTypes.number,
-        ]),
-        header: React.PropTypes.node,
-        blur: React.PropTypes.string,
-        contentInset: React.PropTypes.object,
-    },
-
getDefaultProps: function () {
return {
windowHeight: 300,

patch-packageを導入していると、このpatchesというディレクトリに作成されたパッチがpostinstallで適用されます。そのためpatchesディレクトリをGitで管理することで、他の開発メンバーが npm install したときにもnode_modules内が修正されます。
パッチファイルのファイル名に注目すると、パッケージ名の後にバージョンが入っており、node_modules内のパッケージが該当のバージョンのときのみ適用されます。パッケージのバージョンアップをするごとにパッチの見直しをして、不要になったらパッチを使わないようにしましょう。

まとめ

patch-packageを使うことによって簡単にnpmパッケージを修正することができました。
特にReact Native向けのライブラリではnode_modules内で管理されているネイティブモジュールのコードに対してもパッチを当てることが可能ですので、使いたくなる場面が多くなります。
npmライブラリをそのまま使えないという状況自体が好ましくはないため、あくまで一時的な手段としてとらえるとしてとらえるのがいいでしょう。ですが、どんな状況でも逃げ道があるということを知っておくと安心です。

Author Profile

しんのき
新しい技術が好きなWebエンジニアです。

元々インフラやPHPをやっていたのですが、最近はReact NativeとFirebaseを使って頑張ってます。

この記事は
参考になりましたか?

PAGE TOP