npmパッケージを開発したい

ツイート
2021年05月18日
2021年05月20日

動機

1.GitHubからNode.jsのPackageをforkし、

2.ローカルで開発する

という流れを作って、OSSにPRを送ってみたい。

①forkしてgit cloneする

1.GitHubでforkし

2.git clone urlを実行する。

Couldn't find the binary git

Dockerコンテナ内(node14.15.3-alpine)で実行していたら、上記のエラーが出たので、gitをインストールする。Dockerfileにも記載しておく。

bash
apk add git

②package.jsonを確認する

package.json

  • main: 一番最初に実行されるファイル。ここを真っ先に確認すると良さそう。設定されていない場合は、デフォルトでパッケージのルートディレクトリindex.jsが設定される。
js
const modules = require("modules") // CommonJS // ES modules import Foo from "modules" // 1つ import { Foo } from "modules" // 複数ある場合 import { Foo as MyFoo } from "modules" // 名前をつけて import { default as MyFoos } from 'modules'; // default exportの場合 import { * as MyFoos } from 'modules'; // まとめて // ※あまり詳しくないので、これから勉強

を実行した場合、index.jsに記載されているexportsのオブジェクトが返ってくる。

json
{ "main": "dist/index.js" }
  • name: パッケージ名。
  • version: バージョン。nameと共に、一意になることが想定されている。
  • scripts: ShellScriptを実行するaliasを貼る。
  • repository: ソースコードの管理場所を指定する。
  • private: trueの場合、モジュールの公開ができない。エンドユーザアプリなどは基本、falseになると思う。

※結構出てくるesmはES modulescjsはCommonJSをだいたい意味する。

③installとbuild

npm installした際に、package.jsoninstallの記述がない場合、node-gyp rebuildが実行されるみたい。

だが、Docker内で実行したら、dist/が生成されなかったので、npm installした後に、npm run buildを実行し、dist/の生成を確認。(scriptsdist/に吐き出す設定は書いてある。)

ex) install ライフサイクル

  • preinstall
  • install
  • postinstall
  • prepublish
  • preprepare
  • prepare
  • postprepare

の順番で実行される。実際にログを見るとこの順番で実行されている。

④ローカルリポジトリにmodulesをインストール

fork_modulesというディレクトリを作り、forkしてきたリポジトリを置いてみた。

bash
mkdir fork_modules cd fork_modules npm install npm run build

dist/index.jsができていることを確認する。

プロジェクトに戻り、

bash
yarn add ./fork_modules/{modules}

package.jsonにはこのような形で、記載された。

json
{ "dependencies": { "modules": "./fork_modules/modules/" } }

※プロジェクトにyarnを使っていて、moduleのビルドにnpmを使っています。

forkしたGitHubリポジトリからインストール

"modules": "git+{https://github.com/username/リポジトリ名}"で指定する。

ブランチ・タグ・コミットハッシュ値を指定する場合は、#で指定する。

json
{ "dependencies": { "modules": "git+https://github.com/username/リポジトリ名.git" }

上記が完了したら、npm installを実行する。

そのまま相対パスでimportする

冷静に考えて、毎回ファイルを変更する度に、npm run buildした後に、yarn installするのも面倒くさいので、そのまま相対パスで読み込むことにした。

ex) ビルド前

ビルド前のソースコードはsrc/にあったので、そのまま読み込む。

js
import { Foo as Bar } from '../fork_modules/modules/src/index'

ex) ビルド済 dist/

js
import { Foo as Bar } from '../fork_modules/modules/dist/index'

実際のscriptsは以下のような形。

json
"scripts": { "build": "npm run build:cjs && npm run build:esm && webpack", "build:cjs": "BABEL_ENV=cjs babel src --out-dir ./dist/cjs", "build:esm": "BABEL_ENV=esm babel src --out-dir ./dist/esm" }

そして...

そしてよく見てみたら、開発サーバーの起動もありましたw 読みづらいなあと思っていたが、webpackのbundle済ファイルでした。ちゃんと読みやすかった。

json
"dev": "webpack-dev-server --hot --inline"
bash
npm run dev

注釈

  • npm: Node Package Manager。Node.jsのPackageを管理する。
  • Node.js Package: modulesとほぼ同義で扱われる。インストールしたmodulesはnode_modulesに配置される。
  • Modules: ある一定の機能を持ったコード群。JavaScript Modules: From IIFEs to CommonJS to ES6 Modulesこの投稿が良いかも。
  • ES modules: ES2015で決められたJavaScriptファイルから別のJavaScriptファイルを読み込む仕組みのこと(export, import, etc)
  • CommonJS: ES2015より前に決められたAPIの仕様(module.exports, require(), etc)
  • Webpack: Module Bundlers。コードをまとめる。色々なサポート機能がある。(ex) 開発サーバ)
  • babel: JavaScriptコンパイラ。

現在および古いブラウザまたは環境でECMAScript2015 +コードを下位互換性のあるバージョンのJavaScriptに変換するために主に使用されるツールチェーンです。

  • トランスパイル: ある言語で書かれたコードを元に別の言語のコードを生成すること。
  • Polyfill: 古いブラウザでは実現できないAPIを、古いブラウザでも同等の機能を使用できるように補うための小さなライブラリのようなもの。

参考