目次を表示
進捗状況
0%
2024-09-04
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にアクセスすることで確認できる。