読者です 読者をやめる 読者になる 読者になる

PhoneGap(Cordova)アプリで jQuery Mobile で複数画面遷移する HTML ファイルを生成する

HTML ファイルをどう扱うか考えていた

というのが以前の記事 PhoneGap(Cordova) + jQuery Mobile でアプリを構築しようとして調べた雑多なこと - atas
ベタ書きで固定フッターやヘッダーを出力するのはさすがに面倒だし絶対ミスがおこる。一般的な Web フレームワークならテンプレートエンジンでどうこうできるし、サーバーなら SSI で include できる。しかし今回は PhoneGap アプリなので中身は HTML + CSS + JS になるからそれはできない。じゃあ $(selector).load(template) したらどうか?というのを昨日やっていたりしたのだけど、アイコンが二重に表示されるバグ(仕様?)があったり、結局スマホのアニメーションを jQuery Mobile で扱おうとするとこれはまたベタ書きで面倒なことになる。さて、どうしよう。やっぱり1枚の HTML にするしかないのか、しかし疎結合にしたいし、さて。

別にテンプレートエンジンで HTML 出力できた

結論としては Python を扱っているし普段 Django 使ってるので Jinja2 というテンプレートエンジンを採用することにした。Jinja2 自体は Flask のテンプレートエンジンとしてもお馴染み。Django のテンプレートエンジンが先か Jinja が先かはわからないけど、似たような感じでかけるのでとても楽です。
参考までにコード。まず base.html を定義してやる

<!DOCTYPE HTML>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>hoge</title>
  <link rel="stylesheet" href="hoge/css/jquery.mobile-1.2.0.min.css" />
  <script type="text/javascript" src="cordova-2.2.0.js"></script>
  <script type="text/javascript" src="hoge/js/jquery-1.8.2.min.js"></script>
  <script type="text/javascript" src="hoge/js/jquery.mobile-1.2.0.min.js"></script>
</head>
{% block body %}{% endblock %}
</html>

で、メインとなる index.html はこんな感じ

{% extends "base.html" %}
{% block body %}
<body>

<div data-role="page">

{% include "header.html" %}

<div data-role="content">
  <ul data-role="listview" id="index">
    <li class="ui-btn ui-btn-icon-right">
      <div class="ui-btn-text">
        <a href="#page2" data-transition="slide">page2</a>
      </div>
    </li>
    <li class="ui-btn ui-btn-icon-right">
      <div class="ui-btn-text">
        <a href="#moge" >moge</a>
      </div>
    </li>
  </ul>
</div>

<div id=debug></div>

{% include "footer.html" %}

</div>

</body>
{% endblock %}

base.html を継承していて、中身で include で部分的に入れてますね。例えばヘッダーは

<div data-role="header">
  <h2>Hoge Project</h2>
</div>

これだけ。でもヘッダーとかは共通で使われたりするし、やっぱりこうして部品化しておきたい。
最終的にはこれらのテンプレートファイルを1枚の index.html に組みなおしてやる必要がある。簡単な Python スクリプト main.py をかいた

# coding: utf-8

from jinja2 import Environment, FileSystemLoader

args = []
kwargs = {}

env = Environment(loader=FileSystemLoader('templates'))
tmpl = env.get_template('index.html')
html = tmpl.render(*args, **kwargs)
print(html)

with open("index.html", 'w') as f:
    f.write(html)

サーバーからどう値を受け取ったりなんなりはわからないから、とりあえず *args **kwargs しておいた。PackageLoader のサンプルが多いけど今回はそういうパッケージじゃないからまあ FileSystemLoader でいいかなと。で、print(html) で実際のペラ1枚になった HTML が出力されます。とりあえずてきとうにファイル書き込みにしておいた。
だいたいそんなところですかね。

補足::いろいろ Python のテンプレートエンジンを調べた & おしえてもらった

まあいろいろある。意見をもらったのも踏まえて箇条書きにする

  • Jinja2
    • とりあえず Django に慣れてるなら楽
  • Mako
    • Pyramid でつかわれたりするテンプレートエンジン
    • 高機能で実行速度が早いらしい、が、Jinja2 もけっこうできがいいので無理に使う必要はないかもしれない
    • PHP ではないが Pyhton コードを埋め込んだりできるし、そこらへんの拡張性がいいのかもしれない
  • Cheetah
    • ちょっと前(2007,8年?)にはわりと使われていたりしたらしいが、いまはメンテナンスされてないし選ぶ理由もなさそう
  • hyde
    • というのもあるようだ。日本語情報はないですね(別にそれ自体はいいけど、結局 Jinja2 が楽そうなのでいいや)
  • from string import Template
    • 標準モジュールの string でそもそも Template がある
    • ざっと調べた限りたしかに簡単に出力できる。が、しかしまあ Jinja2 あるから使う必要もないかな
  • Genshi
    • XML ベースでどうとか。なんかデザイナーにわたすときには使いやすいかもしれないらしい
  • mighty
    • Cheetah と Mako の間にそういうプロジェクトがあったらしい
  • ClearSilver
    • Trac でつかわれてたとかどうとか?
  • Chameleon
    • XML ベースらしい
  • Kajiki