DockerでVite + Pugを動かす:フロントの下地をつくってみました

こんにちは、さるまりんです。

最近、フロントっていろんな選択肢がありますよね。
Vue / React / Next など、すぐ実務に入れるツールが揃っています。

でもその前に
HTML = マークアップ を快適に書ける土台が欲しい…
とずっと感じていました。

そこで今回は、

  • Pug:HTMLをシンプルに書けるテンプレートエンジン
  • Vite:めちゃ速いdev server
  • Docker:環境を固定できる安心感

この3つを組み合わせて、
Vite + Pug を “複数ページ(MPA)” で動かす環境
を作るまでをまとめます。

== やること ==

  • DockerでNode環境
  • Viteを動かす
  • Pugでテンプレート/ページ作成
  • buildして dist/ を出し配布可能にする

1. まず完成形のイメージ

作るページは2つです。

  • /(index)
  • /about.html(about)

構成は↓こうなります

pug-vite-docker/
├── docker-compose.yml
├── Dockerfile
├── package.json
├── vite.config.js
└── src/
    ├── main.js
    ├── layouts/
    │   └── layout.pug
    ├── pages/
    │   ├── index.pug
    │   └── about.pug
    └── styles/
        └── style.css

2. Docker環境を用意する

まずはDocker周りからはじめます。

Dockerfile

FROM node:20-alpine

WORKDIR /workspace

COPY package.json package-lock.json* ./
RUN npm install

COPY . .

EXPOSE 5173

CMD ["npm","run","dev","--","--host","0.0.0.0"]

docker-compose.yml

services:
  app:
    build: .
    ports:
      - "5173:5173"
    volumes:
      - ./:/workspace
      - /workspace/node_modules
    environment:
      - CHOKIDAR_USEPOLLING=true
    tty: true

docker compose環境でホットリロードが効きにくい場合があるので、
CHOKIDAR_USEPOLLING=true を指定しています。

3. Vite + Pug の設定

次はviteとpugの設定です。

package.json

{
  "name": "pug-vite-docker",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview --host 0.0.0.0 --port 4173"
  },
  "devDependencies": {
    "vite": "^5.4.0",
    "vituum": "^1.2.0",
    "@vituum/vite-plugin-pug": "^1.0.0"
  }
}

vite.config.js

import { defineConfig } from "vite";
import vituum from "vituum";
import pug from "@vituum/vite-plugin-pug";

export default defineConfig({
  plugins: [
    vituum({
      pages: {
        dir: "src/pages",
        extension: "pug"
      }
    }),
    pug()
  ]
});

4. Pugファイルを作る

実際のHTMLを作るためのpugファイルを作っていきます。

共通レイアウト: src/layouts/layout.pug

doctype html
html
  head
    meta(charset="utf-8")
    meta(name="viewport", content="width=device-width, initial-scale=1")
    link(rel="stylesheet", href="/src/styles/style.css")
    script(type="module", src="/src/main.js")

    block vars
      - var pageTitle = "Pug + Vite Demo"

    title #{pageTitle}

  body
    header.site-header
      h1.site-title Pug + Vite + Docker
      nav
        a(href="/") Home
        span  /
        a(href="/about.html") About

    main
      block content

    footer.site-footer
      small © salumarine

HOMEページ: src/pages/index.pug

extends ../layouts/layout.pug

block vars
  - var pageTitle = "Home | Pug + Vite"

block content
  h2 Home
  p まずはPugをViteで回してみます。
  ul
    li Dockerで環境を固定
    li Viteで爆速 dev server
    li Pug で HTML 生成(MPA)

aboutページ: src/pages/about.pug

extends ../layouts/layout.pug

block vars
  - var pageTitle = "About | Pug + Vite"

block content
  h2 About
  p これは /about.html のページです。
  p 共通レイアウトを使ってページだけ差し替えています。

5. CSSとJS

HTML(pug)から利用するCSSとJSも作ります。

src/styles/style.css

body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans JP", sans-serif;
  margin: 0;
  line-height: 1.7;
  background: #ffe9f0;
}

.site-header,
.site-footer {
  padding: 16px 24px;
  background: #f5f5f5;
}

.site-title {
  margin: 0 0 8px;
  font-size: 18px;
}

main {
  padding: 24px;
  max-width: 900px;
  margin: 0 auto;
}

a {
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

nav a {
  margin-right: 12px;
}

footer {
  text-align: center;
}

src/main.js

import "./styles/style.css";

console.log("Pug + Vite + Docker Ready!");

6. 起動

ファイルの準備ができたので起動です!

まずはbuildして

docker compose build

コンテナ起動!

docker compose up

起動すると👇

app-1  |   VITE v5.4.21  ready in 771 ms
app-1  | 
app-1  |   ➜  Local:   http://localhost:5173/
app-1  |   ➜  Network: http://172.22.0.2:5173/
app-1  |   ➜  press h + enter to show help

これでhttp://localhost:5173/にアクセスすると画面を見ることができます。
次のような画面が表示されます。

index

about

7. buildして配布可能にする

配布できるようbuildします。

docker compose run --rm app npm run build

実行するとこんな表示になります。

vite v5.4.21 building for production...
✓ 5 modules transformed.
dist/about.html                 0.60 kB │ gzip: 0.48 kB
dist/index.html                 0.65 kB │ gzip: 0.50 kB
dist/assets/style-Bpp9bF9U.css  0.39 kB │ gzip: 0.27 kB
dist/assets/main-QLzSQhV0.js    0.74 kB │ gzip: 0.41 kB
✓ built in 215ms

次のような構成でファイルが出力されています。

dist/
├── index.html
├── about.html
└── assets/
     ├── main-*.js
     └── style-*.css

8. devとbuildの違い(大事なポイント)

今回HTML内では /src/main.js や /src/styles/style.css を直接読み込みました。

これは Vite dev server が内部で変換して供給してくれているためです。

✔ dev (npm run dev)

  • /src のファイルをそのまま読む
  • 超高速
  • ホットリロードあり

✔ build (npm run build)

  • JS/CSSをdist/assets/*.js/*.cssに変換
  • HTML内のパスも自動書き換え
  • minify/bundle/tree-shake 完了

つまり

本番サイトは dist をそのまま置けば動く

のです。

9. つまずきポイント

試していてハマったポイントがあったのでちょっとメモです。

  • CHOKIDAR_USEPOLLING=true を忘れると、Docker Desktopで監視が止まりがち
  • port 5173 が他で使われてたら 5174:5173 と変更で回避
  • layoutのPug構文ミスで build/表示できず(extends やblockのスペースに注意)

10. おわりに

今回は

✔ DockerでNode環境を固定
✔ Viteで開発
✔ Pugで複数ページ
✔ buildでdist

というところまで “ひとまとめ” に動かしてみました。

ちょっとした静的サイトなら、
この構成だけで配信できちゃいます。

今後は:

  • Pugでパーツ化(mixin/include)
  • buildしたdistを nginx or S3に配置
  • ブログテンプレとして組み立てる

と色々できたらいいなと思っています。

それではまた!

✅ そのまま実行する手順まとめ(チェックリスト)

# 1) フォルダ作って移動
mkdir pug-vite-docker && cd pug-vite-docker

# 2) 上のファイルを作成(Dockerfile, compose, package.json, vite.config.js, src配下)

# 3) ビルド
docker compose build

# 4) 起動
docker compose up

# 5) ブラウザで確認
# http://localhost:5173/
# http://localhost:5173/about.html

# 6) distを作る
docker compose run --rm app npm run build