記事一覧へ
7/18/2023

monorepoでSass Modulesを使ったコンポーネントを共通化する

こんにちは、木瓜丸です。

最近、関わっている新規のプロダクトや個人開発で、pnpm-workspaceを使っています。 pnpm-workspaceを使うと、monorepoを割と簡単にセットアップできます。

monorepoを使っていると、一つのプロダクトで複数のサイトを配信する時(例えば、管理画面やLPなどを別環境で配信したい時)にコンポーネントを共通化したい時があります。

今回、コンポーネントを共通化させる上で、Sass Modulesを使えるようにするのに軽くハマったため、そのセットアップ方法をまとめておきます。

共通化する上で困ること

コンポーネントを共通化する上で、Sass変数の扱いが課題になります。

例えば、Next.jsでサイト全体で扱うカラーパレットを変数にまとめることがあると思います。 このような時、共通化されたパッケージからもその変数の色を使えなければなりません。

monorepo設計

monorepoのディレクトリ構成は以下の通りです。

.
├── apps
│   └── app1 --> Next.js                
├── node_modules
├── package.json
├── packages
│   ├── tsconfig
│   │   ├── package.json
│   │   └── tsconfig.base.json
│   └── ui   --> 共通化したコンポーネント
├── pnpm-lock.yaml
└── pnpm-workspace.yaml

apps配下には、デプロイするパッケージをまとめます。また、packagesにはappsが依存する共通化したパッケージなどを入れます。

このようにディレクトリを切ることで、触るべきコードが分かりやすくなったり、依存関係が整理されたりすると思います。 今回、扱う共通化されたコンポーネントはuiパッケージから読み込みます。

monorepo管理を行うため、pnpm-workspace.yamlにパッケージ一覧を書いておきましょう。

# pnpm-workspace.yaml

packages:
  - 'apps/*'
  - 'packages/*'

Next.jsからuiを使う

さて、Next.jsからuiパッケージを読み込むため、まずは依存関係を定義しましょう。

{
  ...
  "dependencies": {
    ...
    "ui": "workspace:*"
  }
}

これに加え、Next.jsから他のパッケージのtsxを読むためにはnext.config.jsを書き換える必要があります。 transpilePackagesuiなどpackages配下のパッケージ名を書きましょう。

/** @type {import('next').NextConfig} */
const nextConfig = {
  transpilePackages: ["ui"],
}

module.exports = nextConfig

共通のSass変数もuiパッケージに入れちゃう

上記のapp1で使う変数をuiでも使う...というのは多分良くないので、uiに使い回す全ての変数を定義してapp1から読み込みます。

/* packages/ui/colors.scss */

$primary: #ffb3d9;
$base: #444444;
$text: #ffffff;

app1側のSassでは、先頭に~を付けることによって、他のパッケージからscssを読むことができます。

/* apps/app1/src/app/global.scss */

@import "~ui/colors.scss";

これで、Sass変数も共通化することができました。

まとめ

今回は、Sassを使ったコンポーネントを共通化してNext.jsで使い回す方法を書きました。

CSS in JSだと割と簡単にデザインを共通化することができますが、Sass Modulesではどのようにするべきかあまりシェアされていない気がしたので、お役に立てればいいなと思っています。

今後、共通化したコンポーネントでWasmやAudio Workletを使う方法を模索する予定なので、まとまったらそれも記事にしようと思います。


書いた人

木瓜丸

Webエンジニア。2022年に「木瓜丸屋」を開業し、個人開発をしています。

その他プロフィールをチェック