Open54

Reactコンポーネントをnpmに公開したい

ゴール

複数のリポジトリで使われる共通のコンポーネントをnpmで公開する

Lerna

複数npmパッケージを一つのリポジトリで管理できるもの

https://github.com/lerna/lerna

lernaはConventional Commitsでコミットメッセージを書くと自動で次のバージョンを推論してくれる

コミットメッセージのテンプレート

<type>[optional scope]: <description>

[optional body]

[optional footer]

patchになるもの

  • fix: A bug fix

minorになるもの

  • feat: A new feature
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  • refactor: A code change that neither fixes a bug nor adds a feature
  • perf: A code change that improves performance
  • test: Adding missing or correcting existing tests
  • chore: Changes to the build process or auxiliary tools and libraries such as documentation generation

major

BREAKING CHANGEがtypeかbodyに含まれているもの?

BREAKING CHANGEをコミット文に入力してもmajorアプデはされなかったのでコマンド作った方が良さそう
"versionup:major": "lerna version major --conventional-commits",

lerna run --parallellerna run --streamの違い

parallelの方は並行して実行
streamは順番通りに実行してくれる

TODO

この記事に記載されてる手順をやってみる

https://blog.cybozu.io/entry/2020/04/21/080000
  • リポジトリ作ってLernaインストール
  • Lerna と Yarn Workspacesを共存する設定にする
  • root直下に必要そうなパッケージ入れる(typescript, eslint, prettier, jest)
  • npmパッケージをLernaで新しく作る
  • tsの関数をnpmに公開する
  • cliをnpmに公開する
  • react, storybook等コンポーネント開発に必要なパッケージを入れる
  • サンプルのコンポーネント作る
  • npmにパブリッシュする
  • CICD入れる
  • packages間で依存関係作ってみる

やったこと

  • リポジトリ作った
  • node-versionとかyarn init
  • yarn add -W --dev lerna
  • yarn lerna init --independent
  • lerna.jsonの設定変更
  • yarn lerna createでパッケージ作成
  • commit messageをConventional Commitsで書く
  • packageのcommitしたらlerna version --conventional-commits
  • npm loginでnpmにログインしとく
  • 公開するパッケージのpackage.jsonにpublischConfigを追加してaccessをpublicにする(scopedなモジュールの場合)
  • lerna publish from-package でnpmに公開する

TypeScriptで書いたものをpublishする

  • rootに必要なパッケージをインストール yarn add -W --dev typescript prettier eslint
  • rootのtsconfigの設定
  • packagesのtsconfigの設定
  • typescriptのビルド
  • lerna version --conventional-commitsでpackageのバージョンを上げる
  • lerna publish from-packageでnpmに公開する

cliをnpmに公開する

  • nodejsで実行するscriptをtsで書く
    • #!/usr/bin/env nodeを1行目に追記する
  • pacakge.jsonのbinにビルド後のscriptのjsファイルのパスを指定する

reactのコンポーネントをnpmに公開する

  • 必要なパッケージをrootにインストール
    • yarn add -W --dev react react-dom @types/react vite @vitejs/plugin-react-refresh vite-react-jsx tailwindcss postcss autoprefixer postcss-nested
  • 雛形を作るyarn create vite p-component --template react-ts
  • rootのdevDependenciesに必要なパッケージはインストールしたので、pacakge側のdependenciesは削除
  • tailwindcssに必要なpostcss.config.jsとtailwind.config.jsを追加 yarn tailwindcss init -p
  • Viteは何の設定もなしにCSS Modulesが書ける
  • package.jsonをnpmで公開するように変更
  • index.d.tsファイルがビルド後に作成されるように修正する vite build && tsc -p ./tsconfig.build.json
  • 公開したコンポーネントを使う側でスタイルを適応させたければビルド後のcssファイルをimportするようにする

モノレポで複数のパッケージを管理した時に

  • モノレポ内でのパッケージ同士の依存が簡単になる(公開してなくてもインポートできる)
  • ルートディレクトリのyarn.lockで一元管理できる

https://numb86-tech.hatenablog.com/entry/2020/07/21/155343

pacakge.jsonのworkspacesの中にはパッケージ用だけでなくexampleのようなサンプルのディレクトリも含めることができる

pacakge.json
{
  "workspaces": [
    "packages/*",
    "examples/*"
  ]
}

package.jsonのプロパティ

bin

実行したいスクリプト(cli)を名前をつけて設定できる感じっぽい

{
  "bin": {
    "myapp": "./cli.js"
  }
}

でnpm run-scriptとかからmyappで./cli.jsの内容を実行できそう

main

エントリーポイント
このエントリーポイントで指定されたpathのファイルがexportしたものがpackageとしてexportしたものになる

publishConfig

registryの設定でnpmjs以外でjsライブラリを管理したい場合に使う
独自の npm registry を使う

files

filesフィールドを指定するとnode_modulesに保存されるファイルサイズが減る

target

どの動作環境に向けてトランスパイルするか指定する

tsconfig/basesをみてるとReact、Next.jsでES5を使っていて、NodejsではそれぞれのバージョンにあったESバージョンを使っている
recommended.jsonではES2015/ES6が選択されている

Can I UseでみたES6の各ブラウザの対応状況ではIE11が部分的にサポート、Opera Miniがサポートしていない状況

なので、ReactやNext.jsのtsconfigではES5を使ってる感じかな

動作環境として指定できる値
Default:
ES3
Allowed:
ES3 (default),
ES5,
ES6/ES2015 (synonymous),
ES7/ES2016,
ES2017,
ES2018,
ES2019,
ES2020,
ESNext
※トランスパイルとPolyfillの違い

トランスパイル

ある言語で書かれたコードを元に別の言語のコードを生成すること

Polyfill

古いブラウザでは実現できないAPIを、古いブラウザでも同等の機能を使用できるように補うための小さなライブラリのようなもの

https://qiita.com/Sekky0905/items/4515203428d9715fde5f

module

どのモジュールパターンでTypeScriptをJavaScriptに変換するか指定する

tsconfig/basesのReactやNext.jsではesnextが指定されている
(webpackの中でTypeScriptを扱ってる場合はesnextを指定することでTree Shakingなどの最適化ができる https://gist.github.com/azu/56a0411d69e2fc333d545bfe57933d07)

指定できるモジュールパターン
Allowed:
CommonJS (default if target is ES3 or ES5),
ES6,
ES2015,
ES2020,
None,
UMD,
AMD,
System,
ESNext

lib

TypeScriptには標準であるMathなどの関数の型定義やブラウザで見られるDOMの型定義などがデフォルトで含まれている

状況に応じて使う型定義を変更するときにlibで指定する

libで指定できる値

tsconfig/basesではReactやNext.js環境の場合
"lib": ["dom", "dom.iterable", "esnext"],
が指定されている
ブラウザで使用する型定義と最新のjs apiが使えるesnextを指定している

jsx

指定された値によってどのようにコンパイルされるかはこのexampleで確認する

react-jsxreact17から出てきたtransformに対応してる
(import React from 'react';しなくてよくなったやつ)
react17だけが対象ではなく、一応16.14.0とかにも対応してる

React 17 RC already includes support for the new transform, so go give it a try! To make it easier to adopt, we’ve also backported its support to React 16.14.0, React 15.7.0, and React 0.14.10.

指定できる値
Allowed:
react,
react-jsx,
react-jsxdev,
react-native,
preserve

共通のlinter formatterの設定をする

ぐぐると色々な思想の設定が出てきすぎるのでシンプルなやつをベースにする

  • yarn add -W --dev @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-prettier eslint-plugin-prettier
  • eslint用のtsconfigを作成する

モノレポでいい感じにeslintとprettierを反映できないのでshopifyを参考にする

baseのtsconfig

**はディレクトリ再帰の指定
特定ディレクトリ以下の全ディレクトリとか指定できる

tsxで作ったReactコンポーネントをnpmで公開する

viteの環境構築ざっくりメモ

  • 必要なパッケージをrootにインストール
    • yarn add -W --dev react react-dom @types/react @types/react-dom @vitejs/plugin-react-refresh vite
    • 必要なパッケージはyarn create vite p-component --template react-tsで作られたpacakge.jsonに記載されているもの
    • 全てのパッケージをdevDependenciesに入れたのはshopifyのリポジトリを参考にした
  • Lybrary Modeのviteの設定する
  • entry point用のindex.tsファイルを作る
  • ビルドしてみる
    • react17以降のtransformしてくれなかったので、vite-react-jsx使う?
    • yarn add -W --dev vite-react-jsx
  • tailwindcssを入れる
    • yarn add -W --dev tailwindcss postcss autoprefixer
      • yarn add -W --dev postcss-nested(好み)
    • 該当pacakgeの配下でyarn tailwindcss init -p (-pはpostcss.config.jsを自動的に作成するオプション)
  • css modulesの設定入れる
  • pacakge.jsonをnpmで公開するように変更する
  • dist配下にd.tsファイルをビルドする
  • いい感じにindex.d.tsもできたが別リポジトリで公開されたパッケージを使ってみるとstyleが当たってない
    • tailwindcss使わずにビルドしてもstyle当たらなかったし、ビルド時の問題?

ビルドして、npmに公開したコンポーネントのスタイルは

import { Button } from '@nus3/p-component2'
import '@nus3/p-component2/dist/style.css'

みたく、dist配下のstyle.cssをimportすれば適応される

  • 別packageをimportする場合はtsconfigのreferencesに該当packageのpathを追加
  • importされるpackageはtsconfigのcomplilerOptionsにcompositeをtrueで追加する
  • 該当pacakgeでyarn add {pacakge-name}してdependencies(or devDependencies)に追加する

referencesて指定するpacakgeのtsconfigでnoEmitをtrueにするとエラーが出る?

Referenced_project_0_may_not_disable_emit_6310: 参照されたプロジェクト '{0}' は、生成を無効にできません。

Viteのvanilla-tsのtemplateをLibrary modeで試してみる

  • yarn create vite {project-name} --template vanilla-tsでテンプレートから作成する
  • vite configをLibrary modeになるようにする
  • pacakge.jsonの設定をする
  • build用のtsconfig(tsconfig.build.json)の設定する
  • yarn devした際に定義した関数の動作が確認できるようにする(console.logするとか)
  • yarn add -W --dev @testing-library/react @testing-library/jest-dom identity-obj-proxy
  • jest.config.jsの追加
    • testEnvironmentでjsdom
    • transformでts-jest
    • setupFilesAfterEnvでjsdom
    • css modulesはidentity-obj-proxyでモック
  • テストを書く

CICDをGitHub Actionsで作る

フロー例(azu/lerna-monorepo-github-actions-release)

  1. release/のブランチを作成する
  2. yarn run versionup(git tagは打たない)
  3. プルリクエスト作成
  4. プルリクエストのbodyにrelease noteをかく
  5. プルリクエストのマージ
  6. git tagの作成・github releaseの作成・npmへのpublish

./lerna.jsonのversionを見てるからindependentではない想定っぽい

shopifyの見てるとrelease全部自動化してないな

https://github.com/Shopify/quilt/blob/main/documentation/guides/release-and-deploy.md

release作業は手作業でやってそう
(デプロイに関してはShipitっていう多分自作のツール使ってやってそうだけど)

shopifyのgithub actions

https://github.com/Shopify/quilt/blob/main/.github/workflows/node-ci.yml

onでpull_requestとpush指定すればciを起動したいタイミングのはできそう

  1. ciはプルリクエスト作成とかに実行する
  2. mainでプルリクエストマージ
  3. mainからreleaseブランチを生やす
  4. releaseブランチでlerna version --conventional-commitsして各packageをversion upする
  5. プルリクエストのbodyにrelease noteをかく
  6. relaseブランチからmainにマージされたらgithubのreleaseを作る + npmへpublishする

TODO: この流れでGitHub Actions作ってみる

ログインするとコメントできます