Open54

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

nus3nus3

ゴール

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

nus3nus3

Lerna

複数npmパッケージを一つのリポジトリで管理できるもの
https://github.com/lerna/lerna

nus3nus3

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",

nus3nus3

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

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

nus3nus3

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間で依存関係作ってみる
nus3nus3

やったこと

  • リポジトリ作った
  • 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に公開する
nus3nus3

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に公開する
nus3nus3

cliをnpmに公開する

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

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するようにする
nus3nus3
nus3nus3

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

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

nus3nus3

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に保存されるファイルサイズが減る

nus3nus3
nus3nus3

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

nus3nus3

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
nus3nus3

lib

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

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

libで指定できる値

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

nus3nus3

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
nus3nus3

共通のlinter formatterの設定をする

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

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

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

nus3nus3

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

nus3nus3

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当たらなかったし、ビルド時の問題?
nus3nus3

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

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

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

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

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

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

nus3nus3

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するとか)
nus3nus3

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ではない想定っぽい

nus3nus3

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を起動したいタイミングのはできそう

nus3nus3
  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作ってみる