FlaskでMermaid簡易エディタを作る|最小構成からWebアプリを起動する

「FlaskでMermaid簡易エディタを作る|最小構成からWebアプリを起動する」の内容を表す技術イラスト
目次

はじめに

このシリーズでは、PythonのWebフレームワークであるFlaskと、テキストから図を生成できるMermaid.jsを組み合わせて、ローカルPCで動作するMermaid簡易エディタを8回に分けて作ります。

完成時には、次のような機能を持つ小さなWebツールになります。

  • Mermaidコードを入力する
  • 入力内容をリアルタイムで図にする
  • Mermaid構文エラーを表示する
  • .mmdファイルを保存・読み込む
  • SVGとして出力する
  • Mermaidコードをクリップボードへコピーする
  • よく使う図をテンプレートから挿入する

ただし、最初から全部を作ることはしません。

Day 1では、機能を追加するための土台だけを作ります。

今回の到達点は非常に明確です。

ブラウザでFlaskアプリを開き、「Mermaid Editor」というページが表示されるところまで。

Mermaid.jsはまだ使いません。

小さなWebツールでも、最初に責務とディレクトリ構造を整理しておくと、その後の機能追加が格段に楽になります。


今回作るもの

最終的なMermaidエディタでは、大きく分けて次の2つの世界が動きます。

Python / Flask側

  • Webページを配信する
  • 必要に応じてファイルを扱う
  • 将来的にテンプレートデータなどを管理する

ブラウザ側

  • Mermaidコードを入力する
  • Mermaid.jsで図を描画する
  • 入力イベントを処理する
  • SVGを取得する
  • ファイルをダウンロードする
  • クリップボードへコピーする

ここで重要なのは、

Mermaidの描画処理をPythonに担当させない

という設計です。

Mermaid.jsはブラウザ上で動作するJavaScriptライブラリです。そのため、図の描画はブラウザ側へ任せます。

Flaskは必要以上に仕事を抱えません。

Day 1では、この境界を意識しながら最小構成を作ります。


Flaskとは何か

FlaskはPythonでWebアプリケーションを作るための軽量なWebフレームワークです。

Flask公式ドキュメントでは、Flaskを軽量なWSGI Webアプリケーションフレームワークとして説明しています。小さく始めやすい一方で、必要に応じてより複雑なアプリケーションへ拡張できます。 Flask

今回Flaskを採用する理由は、Mermaidエディタそのものが目的だからです。

巨大なWebフレームワークを先に理解するのではなく、

Python
    ↓
Flask
    ↓
HTML / CSS / JavaScript
    ↓
Mermaid.js

という比較的小さな構成でWebツールを作れます。

機械設計で例えるなら、必要以上に巨大なユニットを採用せず、必要な機能を持つ最小構成から始める考え方に近いでしょう。


Flaskとブラウザの役割を分ける

今回のシリーズでは、最初から責務を分離します。

処理担当
Webページ配信Flask
HTML生成Flask / Jinja
画面レイアウトHTML / CSS
ユーザー操作JavaScript
Mermaid描画Mermaid.js
.mmd操作主にブラウザ
SVG生成Mermaid.js / ブラウザ
テンプレート管理JavaScriptまたはFlask

この分け方には理由があります。

たとえばユーザーがMermaidコードを1文字入力するたびに、

ブラウザ
↓
Flask
↓
Python
↓
Flask
↓
ブラウザ

と通信する必要はありません。

ブラウザ内だけで、

入力
↓
JavaScript
↓
Mermaid.js
↓
SVG

と処理したほうが単純です。

サーバーで行う必要がない処理は、サーバーへ送らない。

これが今回の設計方針です。


Python仮想環境を作る

Pythonでは、プロジェクトごとに使用するライブラリを分離するために仮想環境を使えます。

標準ライブラリのvenvを使えば、プロジェクト専用のPython環境を作成できます。Python公式ドキュメントでも、仮想環境は他のPython環境から基本的に分離されたパッケージ環境として説明されています。 Python documentation

まず作業用ディレクトリを作ります。

例として次の名前を使います。

mermaid-editor

ターミナルまたはPowerShellで、このディレクトリへ移動します。

mkdir mermaid-editor
cd mermaid-editor

続いて仮想環境を作成します。

python -m venv .venv

.venvというディレクトリが作成されます。

Windows PowerShellでは、一般的には次のように有効化します。

.\.venv\Scripts\Activate.ps1

有効化されると、ターミナルの表示に.venvなどの環境名が現れます。

環境によってPowerShellの実行ポリシーによりActivate.ps1が実行できない場合があります。Python公式ドキュメントもWindowsでは実行ポリシーの設定が必要になる場合があると説明しています。 Python documentation

なお、仮想環境の有効化そのものは必須ではありません。仮想環境内のPythonを直接指定して実行することもできます。


Flaskをインストールする

仮想環境を有効にした状態でFlaskをインストールします。

python -m pip install Flask

インストールできたか確認します。

python -m flask --version

ここでバージョン情報が表示されれば、Flaskを利用できる状態です。


requirements.txtを作る

プロジェクトで必要なPythonパッケージを記録します。

今回はFlaskだけなので、まずはシンプルにします。

Flask

これをrequirements.txtとして保存します。

ディレクトリは次の状態になります。

mermaid-editor/
├── .venv/
└── requirements.txt

別環境では、

python -m pip install -r requirements.txt

とすれば必要なパッケージを導入できます。

ここで重要なのは、

仮想環境そのものではなく、環境を再構築するための情報を残す

ことです。

Python公式ドキュメントでも仮想環境は再作成可能なものとして扱われ、ソース管理へ含めないことが推奨されています。 Python documentation

つまり、

.venv

を別PCへコピーするのではなく、

requirements.txt

から再構築します。

これは再現可能な開発環境を作るうえで重要な考え方です。


Flask最小アプリを作る

プロジェクト直下にapp.pyを作ります。

from flask import Flask, render_templateapp = Flask(__name__)@app.get("/")def index():    return render_template("index.html")

わずか数行ですが、これでWebアプリケーションとして成立します。

Flask公式Quickstartでも、

app = Flask(__name__)

によってFlaskアプリケーションを作り、ルートを関数へ関連付ける構造が基本になっています。 Flask

Flask(__name__)の意味

app = Flask(__name__)

では、Flaskクラスからアプリケーションオブジェクトを生成しています。

__name__を渡すことで、Flaskはアプリケーションの位置を基準としてテンプレートや静的ファイルなどのリソースを探せます。 Flask

@app.get("/")の意味

@app.get("/")

は、

/

へGETリクエストが来た場合に、直後の関数を実行するという指定です。

つまり、

http://127.0.0.1:5000/

へアクセスすると、

index()

が呼び出されます。

render_template()の意味

return render_template("index.html")

はHTMLファイルをテンプレートとして読み込み、ブラウザへ返します。

Flaskは標準構成ではtemplatesディレクトリからテンプレートを探します。 Flask

PythonコードへHTMLを直接大量に書かず、

Python
HTML
CSS
JavaScript

を分離するための第一歩です。


templatesディレクトリを作る

次に、

templates

ディレクトリを作ります。

その中へ、

index.html

を作成します。

<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Mermaid Editor</title>
</head>
<body>
    <main>
        <h1>Mermaid Editor</h1>
        <p>Day 1: Flask is running.</p>
    </main>
</body>
</html>

ここでのHTMLは意図的に簡単にしています。

Day 1の目的はデザインではなく、

ブラウザ
↓
Flask
↓
index.html

という経路が成立することを確認することだからです。


staticディレクトリを用意する

さらに、

static

ディレクトリを作ります。

Day 1ではまだCSSやJavaScriptを書かなくても構いません。

最終的な構成は次のようになります。

mermaid-editor/
├── .venv/
├── static/
├── templates/
│   └── index.html
├── app.py
└── requirements.txt

Flaskでは、標準構成ならstaticディレクトリを静的ファイル用として利用できます。CSSやJavaScriptなどをここへ配置できます。 Flask

Day 2以降では、たとえば次のように成長していきます。

static/
├── css/
│   └── style.css
└── js/
    └── editor.js

最初から責務別の置き場所を考えておくことで、index.htmlへCSSもJavaScriptも全部書き込む状態を避けられます。


Flaskアプリを起動する

プロジェクトのルートディレクトリで次を実行します。

python -m flask --app app run

app.pyという標準的なファイル名ならFlaskが自動検出できる場合もありますが、このシリーズでは何を起動しているのか分かりやすくするため、--app appを明示して進めます。

Flask公式Quickstartでも、flask --app hello runまたはpython -m flaskによる開発サーバーの起動方法が案内されています。 Flask

正常に起動すれば、ターミナルにはローカルURLが表示されます。

一般的な初期状態では、

http://127.0.0.1:5000

です。

ブラウザで開き、

Mermaid Editor

Day 1: Flask is running.

と表示されれば成功です。


開発時はデバッグモードも使える

開発中は次のように起動できます。

python -m flask --app app run --debug

デバッグモードではコード変更時の自動リロードなどが利用できます。

ただし、Flask公式ドキュメントは組み込みデバッガを本番環境で使用しないよう警告しています。デバッガにはブラウザからPythonコードを実行できる機能があるためです。 Flask

したがって、

ローカル開発
→ --debugを利用可能

公開・本番
→ 開発サーバーやデバッガをそのまま使用しない

と区別します。

今回作るMermaidエディタは、まずローカルツールとして進めます。


なぜHTMLをPythonへ直接書かないのか

Flaskでは次のようなコードも動きます。

@app.get("/")def index():    return "<h1>Mermaid Editor</h1>"

最小動作確認だけなら十分です。

しかし、この方法でエディタを作り続けると、

return """<html>...<style>...<script>...</script></html>"""

のようになり、Python、HTML、CSS、JavaScriptの境界が崩れていきます。

今回のシリーズでは、

app.py
    → Webアプリ側の処理

templates/
    → HTML

static/css/
    → 見た目

static/js/
    → ブラウザ側ロジック

という分離を基本にします。

これはファイルを増やすこと自体が目的ではありません。

変更理由が違うものを分離する

ことが目的です。

UIデザインを変えるためにPythonを触る必要はありません。

Mermaid描画ロジックを変えるためにFlaskのルーティングを触る必要もありません。

この分離が、後半の機能追加で効いてきます。


Day 1完成コード

今回必要なPythonコードはこれだけです。

app.py

from flask import Flask, render_templateapp = Flask(__name__)@app.get("/")def index():    return render_template("index.html")

templates/index.html

<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Mermaid Editor</title>
</head>
<body>
    <main>
        <h1>Mermaid Editor</h1>
        <p>Day 1: Flask is running.</p>
    </main>
</body>
</html>

requirements.txt

Flask

そしてディレクトリ構造は、

mermaid-editor/
├── .venv/
├── static/
├── templates/
│   └── index.html
├── app.py
└── requirements.txt

です。

これが今後7回の基礎になります。


動作確認チェックリスト

起動前に次を確認します。

  • Pythonが実行できる
  • .venvを作成した
  • 仮想環境へFlaskをインストールした
  • app.pyがプロジェクト直下にある
  • templates/index.htmlが存在する
  • staticディレクトリが存在する

起動します。

python -m flask --app app run

ブラウザで、

http://127.0.0.1:5000/

を開きます。

ページが表示されればDay 1は完了です。


よくある失敗

No module named 'flask'

代表的な原因は、FlaskをインストールしたPythonと、現在実行しているPythonが違うことです。

まず確認します。

python -m pip show Flask

表示されなければ、

python -m pip install Flask

を実行します。

pipだけでなく、

python -m pip

とすることで、現在使用しているPythonとpipの対応を明確にできます。

TemplateNotFound

たとえば、

jinja2.exceptions.TemplateNotFound: index.html

が出た場合は、ディレクトリ構造を確認します。

正しい基本形は、

app.py
templates/
└── index.html

です。

templateではなく、

templates

であることにも注意します。

Address already in use

5000番ポートを別アプリが使用している可能性があります。

Flask公式Quickstartでも、ポート5000が使用中の場合はアドレス使用中のエラーが発生すると説明されています。 Flask

開発時には別ポートを指定できます。

python -m flask --app app run --port 5001

その場合は、

http://127.0.0.1:5001/

へアクセスします。

flask.pyという名前を付ける

アプリケーションファイルを、

flask.py

と命名するのは避けます。

Flask本体のモジュール名と衝突するためです。Flask公式Quickstartでもこの名前を使わないよう明記されています。 Flask

今回は、

app.py

を使用します。


今回あえて実装しなかったもの

Day 1では、次の機能を実装していません。

  • Mermaid.js
  • コード入力欄
  • 2ペインUI
  • リアルタイム描画
  • .mmd保存
  • SVG出力
  • テンプレート
  • API
  • データベース

これは不足ではありません。

Day 1の責務ではないからです。

小さなMVPでも、最初から機能を詰め込むと問題発生時に原因を切り分けにくくなります。

今日は、

Python
↓
Flask
↓
HTML
↓
ブラウザ

だけを成立させます。

次回はその上へ、

HTML
+
CSS
+
Mermaid.js

を追加します。

段階ごとに正常状態を確定してから次へ進むことで、問題が起きた場所を特定しやすくなります。


実務ツールとして考える

今回の構成はMermaid専用ではありません。

FlaskがHTMLを配信し、ブラウザ側JavaScriptが主要処理を担当する構成は、小さな社内ツールや設計支援ツールにも応用できます。

たとえば、

入力フォーム
↓
JavaScript
↓
計算
↓
結果表示

だけで済む計算なら、処理をブラウザだけで完結できます。

一方、

入力
↓
Flask
↓
Python計算
↓
結果

とすれば、既存のPython計算ロジックをWeb UIから利用できます。

さらに、

Flask
↓
JSON
↓
Python計算モジュール

と責務を分ければ、将来的に別UIから同じ計算ロジックを再利用することもできます。

つまりFlaskを学ぶ目的は、Webサイトを作ることだけではありません。

Pythonで作ったロジックへ、人間が使いやすいWeb UIを付ける方法を身につけること

にもあります。

Mermaidエディタは、その練習として扱いやすい題材です。


練習問題

練習問題:表示文章を変更する

index.htmlの、

<p>Day 1: Flask is running.</p>

を任意の文章へ変更してください。

Flaskを再起動せずブラウザを再読み込みし、変更が反映されるか確認します。

確認観点

HTMLテンプレートの変更とPythonコードの変更が別物であることを確認してください。

練習問題:新しいURLを追加する

app.pyへ次のルートを追加してみます。

@app.get("/health")def health():    return "OK"

ブラウザから、

http://127.0.0.1:5000/health

へアクセスします。

OKと表示されれば成功です。

確認観点

同じFlaskアプリケーションの中で、

/

と、

/health

が別々のPython関数へ対応していることを確認します。

練習問題:存在しないURLへアクセスする

たとえば、

http://127.0.0.1:5000/not-found

へアクセスしてみてください。

ルートを定義していないため404になります。

確認観点

Flaskは「Python関数を上から順番に実行してページを探している」のではありません。

URLとビュー関数の対応関係、つまりルーティングによって処理を選択しています。


まとめ

Day 1ではMermaidエディタそのものの機能はまだ作っていません。

代わりに、

Python
↓
Flask
↓
templates/index.html
↓
ブラウザ

というWebアプリケーションの最小経路を作りました。

今回押さえておきたいポイントは次のとおりです。

  • プロジェクトごとにPython仮想環境を分ける
  • FlaskはWebアプリケーションの入口として使う
  • HTMLをPythonコードへ埋め込まずtemplatesへ分離する
  • CSSやJavaScriptはstaticへ分離していく
  • Mermaidの描画はPythonではなくMermaid.jsへ担当させる
  • 必要以上の機能をDay 1へ持ち込まない
  • 正常動作する最小構成を確定してから機能を追加する

この時点では非常に小さなプログラムです。

しかし、ここで決めた、

入力
描画
保存
出力
テンプレート

を別々の責務として扱う考え方が、後半の実装を支えます。

Day 1の成果物は「Hello World」そのものではありません。

今後7回の変更を受け止められる、最小のアプリケーション骨格を作ったこと

が今回の成果です。

参考情報

Flaskの最小アプリ、ルーティング、テンプレート、静的ファイル、開発サーバーについてはFlask公式Quickstartで確認できます。 Flask

Python仮想環境の作成方法と性質についてはPython公式venvドキュメントを参照してください。

参考になったらシェアしてください
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

機械設計・油圧・CAD・Python・AIなど、ものづくりに関わる技術を扱っています。工学知識を整理・構造化し、設計や自動化に再利用できる形へ変えていくことを目指しています。

目次