🦁

NestJS, HandlebarsでTailwind CSSを使う

2023/08/21に公開

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

NestJS, Handlebarsのセットアップは完了しているものとします。
NestJSでのHandlebarsの使い方を知りたい方は以下を参考に。
https://zenn.dev/hid3/articles/c2999b598ebba0#hbsを用意

以下のようにアクセスするとhello worldと表示される状態から始めます。

src/app.controller.ts
import { Controller, Get, Render } from "@nestjs/common";

@Controller()
export class AppController {
  @Get()
  @Render("example")
  getHello() {}
}
views/example.hbs
<div>
  hello world
</div>

Tailwind CSS の導入

Tailwind CLIを使います。
https://tailwindcss.com/docs/installation

tailwindcssをインストール

yarn add -D tailwindcss

tailwindcssコマンドを使えるようにpackage.jsonに追加します。
(ドキュメントのとおりにpackage.jsonに追加せずにそのままnpxを使うでもよい。お好みみで。)

package.json
...
  "scripts": {
    ...
    "tailwindcss": "tailwindcss"
  },
  ...

configファイル設定

hide@hidenoMacBook-Pro ohamoni % yarn tailwindcss init

Created Tailwind CSS config file: tailwind.config.js

tailwind.config.jsファイルが生成されます。
hbsファイルのパスを設定します。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./views/**/*.hbs"],
  theme: {
    extend: {},
  },
  plugins: [],
}

src/input.cssファイルを用意

src/input.css
@tailwind base;
@tailwind components;
@tailwind utilities;

CSSをbuildするためのコマンドを実行します。
ここで生成されたファイルをhbsファイルで

<link href="/dist/output.css" rel="stylesheet">

のように読み込むことによってCSSが適用されます。
なのでNestJSで静的アセットを配信できるようにしておく必要があります。
参考: https://docs.nestjs.com/techniques/mvc

NestJSで静的ファイル配信設定

src/main.ts
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { NestExpressApplication } from "@nestjs/platform-express";
import { join } from "path";

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule, {
    rawBody: true,
  });

  app.useStaticAssets(join(__dirname, "..", "public"));
  app.setBaseViewsDir(join(__dirname, "..", "views"));
  app.setViewEngine("hbs");

  await app.listen(8080);
}
bootstrap();

app.useStaticAssets(join(__dirname, "..", "public"));でpublicディレクトリ以下の静的ファイルにアクセスできるようになります。

CSSビルド

yarn tailwindcss -i ./src/input.css -o ./public/output.css --watch

public/output.cssが生成されます。

以下のように、生成されたoutput.cssを読み込んでCSSを適用させることができました。

views/example.hbs
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="/output.css" rel="stylesheet">
</head>
<div class="text-3xl font-bold underline">
  hello world
</div>

ちなみに、生成されたoutput.cssにはtailwindのcssすべてが含まれているわけではないです。
.hbsで使われているtailwindのclassに必要なcssのみが出力されます。

その他

output.cssを.gitignoreに追加

このままだと自動生成されるoutput.cssがgitで管理されてしまいます。
commitし忘れたり、PRにoutput.cssが差分で出てきてレビュー時に少し邪魔だったりするので.gitignoreに追加しておくといいかなと思います。
この場合、deploy時にどこかのタイミングでoutput.cssを生成する必要があります。

ローカル開発でNestJSの起動とcssのbuildを一つのコマンドで実行する

npm-run-allを使います。
複数のnpmスクリプトを並列実行や順次実行させることができます。
これを使ってNestJSの起動とcssのbuildを一つのコマンドで並列に実行させます。

yarn add -D npm-run-all
package.json
...
"scripts": {
    "start:debug": "nest start --debug --watch",
    "build:css:dev": "tailwindcss -i ./src/input.css -o ./public/output.css --watch",
    "dev": "run-p start:debug build:css:dev"
  },
  ...

例えば上記のように設定することで

yarn dev

で両者を起動することができます。

Discussion