Karan Engineering Blog
進捗状況
0%

2024-09-04

ElmをコンパイルしTailwindを利用する

ElmをコンパイルしTailwindを利用する

Elmを利用した環境構築

参考資料

tailwind

https://tailwindcss.com/docs/installation

概要

Elm + Express + Tailwindでの環境構築。
目的としてElmの学習での振り返りとして何か作ってみようというもの。

Expressに関しては今回はElmに集中したいためモックデータを返すだけのサーバー扱い。

Mock Service Workerでも良かったかもしれない。

やりたいこと

ElmをビルドしてHTMLファイルを生成。

学習ということでElmのViewの記法も勉強したいためHTMLファイルを生成しているが,実際に利用していくとなったらコンパイル先は HTMLファイルではなくJsファイルとして事前に自分で作っておいたHTMLファイルで利用する方法になると思う。

そのため今回はElmでもViewを記述しているが,コンパイル先がJsの場合は必要ない。

事前に作っておいた HTML に Elm のコンパイルされた JS ファイルをロード

事前に作成していたHTMLやデザインに統合しやすい反面,Elm側でViewが分離されているため完全な状態管理は行われない。

Elm でそのまま HTML ファイルをコンパイル

アプリケーションを一貫して管理でき,Elmの型システムと仮想DOMの恩恵を最大限に受けることができる反面,Viewの記法を学習するコストが発生しうる。

構築

目標

アーキテクチャ

├── backend
│   ├── app.js
│   ├── package-lock.json
│   └── package.json
├── frontend
│   ├── dist
│   │   ├── index.html
│   │   └── style.css
│   ├── elm.json
│   └── src
│       ├── Main.elm
│       ├── add-tailwind.js
│       └── tailwind.css
├── package-lock.json
├── package.json
└── tailwind.config.js

NPMスクリプト

buildは基本的にそれぞれのビルドに必要なものを繋げたものになる。

"reactor": "cd frontend && elm reactor",
"express": "cd backend && node app.js",
"css": "npx tailwindcss -i ./frontend/src/tailwind.css -o ./frontend/dist/style.css --watch",
"html": "cd frontend && elm make src/Main.elm --output=dist/index.html && node src/add-tailwind.js",
"build": "npx tailwindcss -i ./frontend/src/tailwind.css -o ./frontend/dist/style.css && cd frontend && elm make src/Main.elm --output=dist/index.html && node src/add-tailwind.js"

実行結果

Rebuilding...

Done in 277ms.
Success!     

    Main ───> dist/index.html

Tailwind CSS link added to HTML file.

フロントエンド

index.htmlファイルが作成された際に自動でstyleを追加するスクリプト

const fs = require("fs");
const path = "../frontend/dist/index.html";

fs.readFile(path, "utf8", (err, data) => {
  if (err) {
    console.error("Error reading HTML file:", err);
    return;
  }

  const tailwindLink = '<link rel="stylesheet" href="style.css" />';

  if (data.includes(tailwindLink)) {
    console.log("Tailwind CSS link is already added.");
    return;
  }

  const updatedData = data.replace("<head>", `<head>\n    ${tailwindLink}`);

  fs.writeFile(path, updatedData, "utf8", (err) => {
    if (err) {
      console.error("Error writing HTML file:", err);
      return;
    }
    console.log("Tailwind CSS link added to HTML file.");
  });
});

Elmファイル

今回の場合は最低限の構成でexpressサーバーからFetchして表示するだけの構成になっている。

module Main exposing (..)

import Browser
import Html exposing (Html, div, text)
import Html.Attributes exposing (class)
import Http


type alias Model =
    { message : String }


init : flags -> ( Model, Cmd Msg )
init _ =
    ( { message = "Loading..." }, fetchMessage )


type Msg
    = GotMessage (Result Http.Error String)


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        GotMessage (Ok response) ->
            ( { model | message = response }, Cmd.none )

        GotMessage (Err _) ->
            ( { model | message = "Failed to fetch message." }, Cmd.none )


view : Model -> Html Msg
view model =
    div [ class "bg-green-500 text-white p-4 text-xl" ]
        [ text model.message ]


fetchMessage : Cmd Msg
fetchMessage =
    Http.get
        { url = "http://localhost:3000/api"
        , expect = Http.expectString GotMessage
        }


main : Program () Model Msg
main =
    Browser.element { init = init, update = update, view = view, subscriptions = \_ -> Sub.none }

tailwindの追加

@tailwind base;
@tailwind components;
@tailwind utilities;

バックエンド

Express用のパッケージ管理をする。

今回の場合であればローカルホストのポート番号が違うためCORSの設定が必要となっており,そのパッケージも入れておく。

  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.19.2"
  }

Expressの起動スクリプト

const express = require("express");
const cors = require("cors");
const app = express();
const PORT = process.env.PORT || 3000;

app.use(
  cors({
    origin: "http://localhost:8000",
  })
);

// APIのルート
app.get("/api", (req, res) => {
  res.json({ message: "Hello from Express!" });
});

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

実行

npm run express // バックエンドサーバーの起動
npm run build && npm run reactor // フロントエンドの起動

http://localhost:8000にアクセスすることで確認できる。

© 2023 Karan. All Rights Reserved.