ReactのUIコンポーネントを自作してみる
やりたいこと
-
npm install @xxx/yyy
oryarn add @xxx/yyy
みたいにインストールできる - ゼロから作るのは大変なので、
Material UI
をカスタマイズする -
Material UI
にないコンポーネントなども自作コンポーネントに組み込む感じにする - 1つのリポジトリでコンポーネントの管理をする
モノレポ
1つのリポジトリで複数のパッケージを管理することを モノレポ
と呼ぶ。モノレポ(monorepo)とは「一枚岩のリポジトリ(monolithic repository)」のこと。
モノレポの例
- サーバーとフロントを1つのリポジトリで管理する
- WEBのReactとスマホアプリのReact Nativeとでコンポーネントを共有できる
- React, Material UI, Chakra UIなど各コンポーネントごとに管理できる
モノレポのメリット
- 1つのブランチで複数のpackageを管理できる
- すべてにおいて現時点でコミットされたものが動きます
- コードを構成可能なモジュールへ簡単に分割できます
- 依存関係をより簡単に管理できます
- 単一ツールチェーンでのセットアップできます
- コードエディタやIDEは “ワークスペース単位” で動かします
- 一貫した開発者エクスペリエンスがあります
モノレポのデメリット
- トランクベース開発は、より一段と重要になります
- すべてのサービスがモノレポで上手く動くわけではありません
- より精巧なCIセットアップが必要です
- 大規模な変更について考える必要があります
参考サイト
eslint, prettier など。lernaのversionはfixed
monorepoのメリットデメリットとユースケース
azuさんのリポジトリ。リリース手順など網羅できてる
azuさんの記事。lerna version Fixed, Independent の違いやリリースフローなど詳しく書いてある。
Lerna package追加手順
yarn v3
に上げる
作業ディレクトリを作って Yarn Workspaces機能は v3
のほうが安定してるらしい
$ mkdir example && cd example
$ yarn set version berry
$ yarn -v
> 3.x.x
yarnをv1からv2(Berry)へ移行する
https://zenn.dev/kkoudev/articles/5b440e1e341458
.yarnrc.yml を編集する
yarn v2 以降は node_modules が生成されません。node_modules ディレクトリがあること前提で作られてるmodulesが多いので、node_modules ディレクトリが作れるように設定し直します。node-modules
はハイフン区切りです
nodeLinker: node-modules
yarn init
private を ture にするのでオプションにprivateをつける
$ yarn init --private
.gitignore を追加
Lerna init
yarn global に lerna を add しなくても良さそう
$ npx lerna init --independent
$ yarn install
lerna.json を変更します
{
"packages": [
"packages/*"
],
"npmClient": "yarn",
"useWorkspaces": true,
"version": "independent"
}
-
npmClient: "yarn"
内部的にyarn
を使います。 -
useWorkspaces: true
Yarn Workspaces を設定をLernaでも使えます -
"version": "independent"
packages内の各packageのバージョンを独立させます
package.json を編集
workspaecsを追加
"workspaces": [
"packages/*"
],
typescriptをインストール
typescriptをインストール。ルートに共通で使うパッケージとしてインストールする場合には、インストールのオプションに明示的に -W
オプションを付ける必要があります
$ yarn add -D typescript -W
tsconfig.json 生成
$ npx tsc --init
tsconfig.json を編集
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es6",
"sourceMap": true,
"lib": [
"es6"
]
},
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
pakcageの追加
$ npx lerna create package_name
Lerna Publish手順
lerna publish
セマンティックバージョニングのメジャー、マイナー、パッチをコマンドにつけることで自動的にpackage.json内のversionが書き換わり、github 上の release ページが自動で更新されます。バージョン X.Y.Z
に対して、 major
が X
、 minor
が Y
、 patch
が Z
部分がインクリメントされます。また、今回はnpmのレジストリには登録しないので --skip-npm
を付けます。 gitを無視するオプションは --skip-git
です。
$ npx lerna publish major
$ npx lerna publish minor
$ npx lerna publish patch
github repository から yarn install する横着はあかん
私の経験では、Gitの依存関係は、すべてのnpmで最も複雑でエラーが発生しやすい機能の1つです。 Lernaは、実際にはこのように消費されることを意図したものではなく、パッケージを公開することを目的としています(ただし、必ずしもパブリックパッケージであるとは限りません)。
lernaを使用してパッケージを開発している場合は、いつでも内部のプライベートレジストリに公開するか、パブリックレジストリのプライベート(スコープ)パッケージとして公開できます。 gitの依存関係を完全に回避することを強くお勧めします。
つまり、公開したくないpackagesをインストールするにしろ、レジストリからインストールしたほうがよいとのこと。
ようやく理解した
例えば、 @cotapon/react-ui
というリポジトリの中にある packages
には、 eslint-conf
、ボタンやインプットなどの要素のUIをまとめた elements
とかがあるとして、それらを使いたい場合は、 yarn add @cotapon/eslint-conf
yarn add @cotapon/elements
でインストールしたい。そうするには、 npx lerna publish
で packages
内のパッケージを個別でレジストリにアップロードする必要がある。
pckage.jsonにgitHeadがついてしまう
publish時にnpm registryの認証エラーで付いてしまう。--skip-npmをつける
npx lerna publish --conventional-commits --skip-npm
Verdaccio(GitHub Packages Registryを使うのでVardaccioは使わない)
プライベートなnpmレジストリが作れる決定版的なツール
docker pull できるのでやってみる
docker pull verdaccio/verdaccio:nightly-master
.npmrcを追加する
lerna publish
コマンドを実行するとcommitされてるところまで自動でpushしてくれます。そのため、github からパーソナルアクセストークンを発行して設定する必要があります。
repo
, write:packages
, read:packages
, delete:packages
tokenが発行されたら、 .npmrc
ファイルを新規作成し、下記の内容を追加します。
@GITHUB_USERNAME:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=発行したtoken
.npmrc
package.jsonを編集
repositoryを追加
lerna publish
した時にpushされる先のリポジトリを指定
"repository": {
"type": "git",
"url": "git+https://github.com/xxx/xxx.git"
},
publishConfigを追加
private repository に push するので、npmjs には push しないけど、publishConfig を書いておかないと lerna publish 時にエラーがでます。 private: true
でかつ、 publishConfig の access: restricted
にしておくとパブリックに公開されることはない。不安ならnpmjsからログアウトしておく。
"publishConfig": {
"access": "restricted",
"registry": "https://npm.pkg.github.com/"
}
Verdaccio の使い方
Verdaccioをインストール
$ npm i -g verdaccio
Verdaccio を起動
$ verdaccio
ユーザー作成
$ npm adduser --registry http://localhost:4873/
.yarnrc
registry "http://localhost:4873"
GitHub Package を使ってみる
クイックスタートどおりにやってみる
git push で Error が出た
refusing to allow a Personal Access Token to create or update workflow
.github/workflows/release-package.yml
withoutworkflow
scope
Personal access tokenのSelect scropeで workflow
にチェックを入れる
Homeディレクトリにある .gitconfig
に書いてもよし?
npx lerna publish 時に Error が出た
lerna ERR! E401 Unable to authenticate, need: Basic realm="GitHub Package Registry"
.npmrc
に Personal access token を入れる
//npm.pkg.github.com/:_authToken=発行したtoken
いや、、これらのエラーは関係ないかも。手順としては、
- git push (いる?)
- npx lerna publish (git push される?)
- release が追加されたらgithub actionsが動く。なのでregistryを指定する必要はない
GitHub Actions でエラー
Run npm ci でエラーが出る
npm ERR! cipm can only install packages with an existing package-lock.json or npm-shrinkwrap.json with lockfileVersion >= 1. Run an install with npm@5 or later to generate it, then try again.
package-lock.json
がどうしてみるみたい。lerna と yarn と npm 共存してもええんか???
publish-gpr の npm publish でコケる
npm ERR! Remove the 'private' field from the package.json to publish it.
package.json
の private : true がいらない。と書いてあった
npx lerna publish で github packages registry にあげてみる
そのままpublishするとnpmのregistryを参照してしまうのでオプションをつける
$ npx lerna publish --registry=https://npm.pkg.github.com/
変更なしでも強制的にpublishする場合は --force-publish
をつける
$ npx lerna publish --registry=https://npm.pkg.github.com/ --force-publish
lerna ERR! E404 The expected resource was not found.
このエラーにずっとはまっていた。
├── packages
│ ├── packae-1
│ └── packae-2
この場合、各packages内のpackage-1, package-2のpackage.jsonにrepositoryの設定が必要。
"repository": {
"type": "git",
"url": "git@github.com:org/repo.git"
},```
GitHub Pacakges Registry にあげたpackagesをnpm installする
privateなリポジトリではもちろんそのままインストールできないので、.npmrc
に書き加える
registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=token
この場合の token
はパーソナルトークンを発行しておく。
conventional commitsとsemantic-release
Conventional Commits
git commit のメッセージをある一定のルールに沿って書くこと。fix, featがあることによって、lerna publish時にpatchなのかminorなのかを自動で判断してくれる
semantic-release
github actionsでsemantic-releaseを実行すると、コミットログからConventional Commitsのルールにそって自動でrelease noteを作ってくれる
release手順構想
packagesの中の各packageが独立しててlerna.jsonのversionがindependentの場合
使用例は、lintなどをまとめたpackages。lint-configというリポジトリに、eslint-configとprettier-configを作るとします。eslintとprettierは依存関係はないのでpackageは独立、independentで良いと思います。
まとめ
色々ごちゃごちゃ書いたけど、最終的なまとめをここに書きます。
Lernaを使ったpackagesのバージョン管理とPrivateなResistryにリリースする手順
- やりたいことと運用指針
- Lernaのセットアップ
- Lerna Publish
- GitHub Actionsでリリースする
やりたいことと運用指針
- 1つのリポジトリで複数のpackagを管理したい
- packageのデプロイ先はPrivateなRegistryにしたい
- プルリクからmasterにマージしたらRegistryにデプロイしてリリースしたい
- リリースノートを自動化したい
1つのリポジトリで複数のpackagを管理したい
1つのリポジトリで複数のパッケージを管理することを「モノレポ」と呼びます。モノレポ(monorepo)とは「一枚岩のリポジトリ(monolithic repository)」のことを意味すそうです。monorepoの方法は幾つかあり、yarn workspaces
か Lerna
を使う2つの方法が有名です。1つのリポジトリのプロジェクト内のみ依存関係が成立し、monorepo化したpackageをRegistryで公開しないのであれば、 yarn workspaces
で管理するほうがyarnだけで完結するので良いと思います。また、monorepoで管理しているpackagesをregistryにデプロイするのであれば、 Lerna
を使うほうがvarsion管理をした運用がしやすいメリットがあります。詳しくは後述します。
packageのデプロイ先はPrivateなRegistryにしたい
npm install
や yarn add
でインストールできるpackageはnpmjsのregistryに公開されています。しかし、世の中に公開したくないpackageをチーム内や社内だけで使いたいという時はどうすればよいでしょうか。パターンとしては3つ考えられます。
- npmに課金してprivateなregistryが使えるようにする
- Verdaccioを使って自前でregistryサーバーを建てる
- GitHub Packages Registry(GPR)を使う
GitHubでプライベートリポジトリからGPRにpublishすればプライベートなregistryで出来る要件は満たし、npmに課金せずにすみ、Verdaccioを運用する手間もなく、GitHub上で一元管理できるのであればGitHub Packages Registry(GPR)一択と思います。