📝

Nx で shadcn/ui

2023/11/25に公開

参考記事 How to get started with shadcn/ui and Next.js within a Nx Monorepo

概要

shadcn/uiNx ワークスペースに導入する方法

前提

Nx ワークスペースがあり、web という名前の Next.js プロジェクトがあること

パッケージをインストール

Manual Installation の手順にある必要なパッケージをインストールする:

npm install tailwindcss-animate class-variance-authority clsx tailwind-merge
npm install lucide-react

shadcn/ui をセットアップ

shadcn/ui の components.json をルートに作成する:

components.json
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "default",
  "rsc": false,
  "tailwind": {
    "config": "libs/web/ui/src/tailwind.config.js",
    "css":    "libs/web/ui/src/globals.css",
    "baseColor": "stone",
    "cssVariables": true
  },
  "aliases": {
    "components": "libs/web/ui/src",
    "utils": "@libs/web-ui-util"
  }
}

※ rsc を true にすると use client が自動で入る

shadcn/ui cli を使えるようにするために tsconfig.json を作成
これを作成しておかないと Failed to load tsconfig.json. Couldn't find tsconfig.json とおこられてしまう

tsconfig.json
{
  "_COMMENT": "only used by shadcn/ui cli to generate shadcn/ui components",
  "extends": "./tsconfig.base.json"
}

web-ui ライブラリを作成

コンポーネントを置くために web-ui ライブラリを作る
@nx/next:library で生成し、不要なものを削除する

$ nx g @nx/next:library web-ui --directory=libs/web/ui --style=none --importPath=@libs/web-ui

>  NX  Generating @nx/next:library

✔ What should be the project name and where should it be generated? · web-ui @ libs/web/ui
UPDATE nx.json
UPDATE package.json
UPDATE .gitignore
CREATE libs/web/ui/project.json
CREATE libs/web/ui/.eslintrc.json
CREATE libs/web/ui/README.md
CREATE libs/web/ui/src/index.ts
CREATE libs/web/ui/tsconfig.lib.json
CREATE libs/web/ui/tsconfig.json
CREATE libs/web/ui/src/lib/web-ui.spec.tsx
CREATE libs/web/ui/src/lib/web-ui.tsx
UPDATE tsconfig.base.json
CREATE libs/web/ui/src/server.ts
CREATE libs/web/ui/src/lib/hello-server.tsx

不要なものを削除:

- libs/web/ui/src/lib
- libs/web/ui/src/server.ts
- libs/web/ui/src/index.ts
tsconfig.base.json
{
  "compilerOptions": {
    "paths": {
-      "@libs/web-ui/server": ["libs/web/ui/src/server.ts"]

Tailwind CSS の設定ファイルを作成する
content だけ shadcn/ui のドキュメントの tailwind.config.js と変更する:

libs/web/ui/src/tailwind.config.js
const { fontFamily } = require('tailwindcss/defaultTheme');

/** @type {import('tailwindcss').Config} */
module.exports = {
  darkMode: ['class'],
-  content: ["app/**/*.{ts,tsx}", "components/**/*.{ts,tsx}"],
+  content: [
+    './{app,components}/**/*.{ts,tsx}',
+    '../../libs/web/ui/src/ui/**/*.{ts,tsx}',
+  ],
  省略

ドキュメント Configure styles の通りに libs/web/ui/src/globals.css を作成する

web-ui-util ライブラリを作成

cn 関数を置くために web-ui-util ライブラリを作る
@nx/js:library で生成し、不要なものを削除する

nx g @nx/js:library web-ui-util --directory=libs/web/ui-util --bundler=swc --unitTestRunner=none --importPath=@libs/web-ui-util

>  NX  Generating @nx/js:library

✔ What should be the project name and where should it be generated? · web-ui-util @ libs/web/ui-util

CREATE libs/web/ui-util/tsconfig.json
CREATE libs/web/ui-util/README.md
CREATE libs/web/ui-util/src/index.ts
CREATE libs/web/ui-util/src/lib/web-ui-util.ts
CREATE libs/web/ui-util/tsconfig.lib.json
CREATE libs/web/ui-util/.swcrc
CREATE libs/web/ui-util/package.json
CREATE libs/web/ui-util/project.json
CREATE libs/web/ui-util/.eslintrc.json
UPDATE tsconfig.base.json

不要なものを削除:

- libs/web/ui-util/src/lib

パスマッピングを修正:

tsconfig.base.json
{
  "compilerOptions": {
    "paths": {
-      "@libs/web-ui": ["libs/web/ui/src/index.ts"],
+      "@libs/web-ui/*": ["libs/web/ui/src/ui/*"],

index.tsAdd a cn helper の cn 関数を定義しエクスポートする:

libs/web/ui-util/src/index.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

web プロジェクトをセットアップ

以下の内容で globals.css を作成する

apps/web/globals.css
@import '../../../libs/web/ui/src/globals.css';

@nx/react:setup-tailwind を使って Tailwind CSS をセットアップする

nx g setup-tailwind --project=web

このコマンドを実行すると、以下パッケージのインストールがされ、設定ファイルが生成される

package.json
  "devDependencies": {
+    "autoprefixer": "10.4.13",
+    "postcss": "8.4.21",
+    "tailwindcss": "3.2.7",
+ apps/web/postcss.config.js
+ apps/web/tailwind.config.js
postcss.config.js
postcss.config.js
const { join } = require('path');

// Note: If you use library-specific PostCSS/Tailwind configuration then you should remove the `postcssConfig` build
// option from your application's configuration (i.e. project.json).
//
// See: https://nx.dev/guides/using-tailwind-css-in-react#step-4:-applying-configuration-to-libraries

module.exports = {
  plugins: {
    tailwindcss: {
      config: join(__dirname, 'tailwind.config.js'),
    },
    autoprefixer: {},
  },
};

tailwind.config.js については以下のように web-ui ライブラリの設定ファイルを読み込むよう書き換える:

apps/web/tailwindcss.config.js
const TailwindConfig = require('../../libs/web/ui/src/tailwind.config');

module.exports = {
  ...TailwindConfig,
};
補足

Dependency npm:postcss:8.4.21 is vulnerable, safe version 8.4.31 のワーニングが出ていたので npm i postcss@8.4.31 を実行。

以上ですべてのセットアップは完了

試しにコンポーネントを作成

npx shadcn-ui@latest add skeleton

を実行すると component.json の aliases.components で設定したディレクトリ libs/web/ui/srcui/skelton.tsx が作成される

作成されたコンポーネント

cn 関数のインポート元のパス @libs/web-ui-utilcomponent.json の aliases.utils で設定したパスになる

libs/web/ui/src/ui/skeleton.tsx
import { cn } from '@libs/web-ui-util';

function Skeleton({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) {
  return (
    <div
      className={cn('animate-pulse rounded-md bg-muted', className)}
      {...props}
    />
  );
}

export { Skeleton };

これで web プロジェクト内で Skeleton コンポーネントが使えるようになる

import { Skeleton } from '@libs/web-ui/skeleton';

Discussion