RAKSUL TechBlog

ラクスルグループのエンジニアが技術トピックを発信するブログです

ノバセルのコンポーネントライブラリ「novasell-ui」

この記事は ラクスルの2022年アドベントカレンダー12日目の記事です。

こんにちは!ノバセル株式会社 NA(ノバセルアナリティクス)グループのmartonです。主にノバセルアナリティクスのフロントエンドの開発を担当しています。

今回はノバセルのデザインシステムの一部として、GitHub Organization内で共通利用できるように公開した、コンポーネントライブラリ「novasell-ui」について紹介したいと思います。

背景

そもそもコンポーネントライブラリとは、デザインシステム内で定められた規格やガイドラインに従ったコンポーネント(ボタンやフォームなど)をまとめたライブラリのことです。コンポーネントライブラリを利用することでデザインに一貫性を持たせることができ、複数プロダクト全体の体験を向上させることができます。

ノバセルでは現在、ノバセルアナリティクスとノバセルトレンドの2つのプロダクトを開発しています。ノバセルアナリティクスはVue、ノバセルトレンドはReactを採用しているため、同じ見た目でも共通のコンポーネントを使うことができていません。

この課題を解決して、複数プロダクト全体にデザインの一貫性を持たせるために、コンポーネントライブラリのnovasell-uiを公開するに至りました。

novasell-uiはライブラリ問わず連携できるWeb Componentsで構築する案も考えましたが、社内でプロダクトをReactに置き換えていく機運が高まっていることや、フロントエンドエンジニアが少ないことを考慮して、Reactを採用しました。novasell-uiを全プロダクトで使うためには、Vueで開発しているノバセルアナリティクスをReactに置き換えるという障壁はありますが、少しずつ対応していき、プロダクトの体験を向上させていきたいと思っています。

ここからはnovasell-uiがこれまで行ってきたことについて、ライブラリの公開方法を中心に紹介していきたいと思います。

コンポーネントのビルド方法

さて、まずは公開するコンポーネントのビルドの設定について紹介していきます。

novasell-uiでは、コンポーネントをstyled-componentsを使って作成し、src/index.tsでエクスポートしています。tscでコンパイルした後に、このファイルがnovasell-uiのエントリーポイントになります。

src/index.tsx

export { Button } from './components/buttons/Button';
export { TextLinkAnchor, TextLinkButton } from './components/buttons/TextLink';

export { CheckBox } from './components/inputs/CheckBox';
export { Tooltip } from './components/tooltips/Tooltip/Tooltip';
...

tsconfigは2つ作成し、ビルド用のtsconfig.build.jsonにはテストやStorybookなど、novasell-uiには含めたくないファイルをexcludeの配列に追加しています。

tsconfig.json

{
  "compilerOptions": {
    "outDir": "./lib",
    "lib": ["es2020", "dom"],
    "target": "es2020",
    "module": "commonjs",
    "moduleResolution": "node",
    "declaration": true,
    "sourceMap": true,
    "types": ["node", "react", "jest", "@testing-library/jest-dom"],
    "typeRoots": ["types", "node_modules/@types"],
    "jsx": "react",
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "allowSyntheticDefaultImports": true,
    "noEmitOnError": true,
    "esModuleInterop": true,
    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "exclude": ["node_modules"],
  "include": ["src/**/*"]
}

tsconfig.build.json

{
  "extends": "./tsconfig.json",
  "exclude": [
    "node_modules",
    "src/**/*.test.ts",
    "src/**/*.test.tsx",
    "src/**/*.stories.tsx"
  ]
}

package.jsonにビルドコマンドを追加し、コンポーネントのビルドの準備が完了しました。

package.json

{
    "scripts": {
    "build": "tsc -p tsconfig.build.json",
  }
}

novasell-uiの公開準備

novasell-uiは、GitHubのプライベートリポジトリを使用してライブラリを管理できるGitHub Package Registryにホスティングしています。公開に必要なpackage.jsonの設定のみ抜粋して紹介していきます。

{
  "name": "@raksul/novasell-ui",
  "version": "1.0.0",
  "main": "lib/index.js",
  "scripts": {
    "build": "tsc -p tsconfig.build.json && tsc-alias",
        ...
  },
  "files": [
    "lib"
  ],
  "publishConfig": {
    "registry": "https://npm.pkg.github.com/"
  },
  "dependencies": {
    ...
  },
  "devDependencies": {
    ...
  },
}
  • name:ライブラリの名前。nameの頭文字に @〇〇 を付けることでscoped packagesにすることができます。scoped packagesとは、特定のオーガニゼーション内でのみ共有されるライブラリのことです。novasell-uiはラクスルのGitHub Organization内にあるリポジトリでのみ利用可能にしたいので、@raksul を頭文字につけています。
  • version:ライブラリのバージョン。同じバージョンを公開することはできないので、新しいバージョンを公開するときは、この番号を更新する必要があります。更新の仕組みについては後ほど紹介していきます。
  • main:ライブラリの中で最初に呼ばれるスクリプト。先ほど設定したtscの出力先のファイルを指定します。
  • publishConfig:公開するレジストリを指定します。今回はGithub Package Registryを指定しています。
  • files:ライブラリをインストールしたときにnode_modulesへコピーするファイル。ライブラリに必要なファイルのみ含めます。

Github Actionsを用いて公開する

novasell-uiの公開にはRelease Pleaseを使用しています。これはgitのコミット履歴の中でConventional Commitに沿ったコミットメッセージを探して、リリース用のPRを作成してくれるGithub Actionsです。

このPRにはCHANGELOG.mdとバージョン番号の更新が含まれています。

Release Pleaseで作成されるPR

バージョン番号はコミットメッセージに以下の接頭辞が付くと自動的に変更をPRに含めてくれます。

  • fix: バグの修正を表し、SemVer パッチを上げる
  • feat:新機能を表し、SemVer のマイナーを上げる
  • feat! fix!:refactor!:破格の変更を表し、SemVer のメジャーを上げる
{
- "version": "1.4.2",
+ "version": "1.4.3"
}

コミットメッセージに前述の接頭辞を付けるのをよく忘れてしまうので、コマンドラインで接頭辞を選択できるgit-czや、コミット前にコミットメッセージがConventional Commitに沿っているかチェックしてくれるcommitlintがおすすめです。

Release Pleaseで作成されたPRがmainブランチへマージされたときに、novasell-uiの公開作業を行うようにします。Release Pleaseで作成されたPRがマージされたかの判断は、 ${{ steps.release.outputs.release_created }} によってできるので、この条件がtrueのときのみnpm publish コマンドが実行されるように設定しています。

on:
  push:
    branches:
      - main
name: release-please
jobs:
  release-please:
    runs-on: ubuntu-latest
    steps:
      - uses: google-github-actions/release-please-action@v3
        id: release
        with:
          release-type: node
      - uses: actions/checkout@v3
        if: ${{ steps.release.outputs.release_created }}
      - uses: actions/setup-node@v3
        with:
          node-version: 16
          cache: 'yarn'
          registry-url: 'https://npm.pkg.github.com'
          scope: '@raksul'
        if: ${{ steps.release.outputs.release_created }}
      - run: yarn install
        if: ${{ steps.release.outputs.release_created }}
      - run: yarn build
        if: ${{ steps.release.outputs.release_created }}
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        if: ${{ steps.release.outputs.release_created }}

novasell-uiを他のリポジトリで使う

次に、公開したnovasell-uiをGitHub Organization内にある他のリポジトリからインストールする方法について紹介していきます。

novasell-uiを使用するためには他のリポジトリのRead権限が必要なので、Creating a personal access tokenを参考に、read:packages権限の Personal access tokens を生成します。

生成したPersonal access tokens をプロジェクト配下に作成した.npmrc へ追加することで、インストールすることができます。

@raksul:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=<Personal access tokensを追加する>

yarn addするときはバージョンを指定してインストールします。

yarn add @raksul/novasell-ui@1.1.0

Github Actiionsでyarn installをするときは、リポジトリデフォルトの secrets.GITHUB_TOKEN では権限が足らないため、インストールに失敗してしまいます。先ほど作成したものでも構いませんが、GITHUB_TOKENとは異なる名前で、read:packages権限の Personal access tokens を環境変数に追加することでyarn installができます。今回の場合はGH_TOKENとしています。

name: build and test

on: push

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 16.x
          registry-url: 'https://npm.pkg.github.com'
          scope: '@raksul'

      - name: Cache dependencies
        uses: actions/cache@v1
        with:
          path: ./node_modules
          key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-node-

      - name: Install packages
        run: yarn install --frozen-lockfile
        env:
          NODE_AUTH_TOKEN: ${{ secrets.GH_TOKEN }}
 
      - name: Build app
        run: yarn run build

おわりに

novasell-uiを始めとしたデザインシステムは作るだけではなく、社内に浸透させていくことが重要になります。ノバセルにはデザインシステムを構築する専任のチームは存在しないため、普段の業務とは別に、毎週決まった時間にペアプロをしてnovasell-uiのコンポーネントを作るなどしています。

まだまだやるべきことはたくさんあるので、デザインシステムを一緒に育ててくれる方を募集しています!ご応募お待ちしております。