Django/Mezzanine Templateにcritical CSS 組み込む思索と施作 1 | Monotalk の続きです。
critical CSS を Django/Mezzanine の template に組み込む方法を検討します。
前提
以下の環境で実行しています。
-
OS
CentOS release 6.9 (Final) -
Python Version
Python 2.7.8 -
Package (必要そうなものだけ抜粋)
Django (1.10.7) Mezzanine (4.2.3) mezzanine-pagedown (1.0)
動的ページ での critical CSS を読み込む際の関心事
critical CSS は、「卵か先か、鶏が先か」な代物で、実装パターンとしては以下、3パターンがあると考えました。
-
ページ描画時に critical css を生成する。次回の読み込み時は cache から取得する。2
[2] 一度目の読み込み時は遅い。 -
デプロイ後に、別タスクで、critical css を生成する。ページ側はファイルが生成されていたら、html 上にインライン展開する。
-
開発環境でデプロイ後に、事前に生成しておく。Production 環境では事前生成したものを組み込み、読み込む。
3 でできると、パフォーマンス、耐障害性は良くなりそうですが、個人 Blog の投稿、デプロイの仕組みとしては組み込みが難しいため、1、2 のどちらかで上手く実装できるかを検討します。
Django pulgin で 作成されているものがあるか ?
Django で、critical CSS の生成、組み込みが可能が plugin があるか調べてみました。
現在、martinblech/django-critical: Inlines critical path CSS and defers loading full CSS asynchronously. が見つかりました。
この記事では、このプラグインをインストールして、具合を見てみようかと思います。
以降は、django-critical
について記載します。
Django-critical を使う
設定の流れ
django-critical
を使用するためには以下が必要になります。
1.前提となる node.js
のライブラリのインストール
django-critical
は、pocketjoso/penthouse: Generate critical css for your urls に依存していて、 penthouse
は npm
に依存していて、npm
は node.js
に依存しているため、周辺のミドルウェアのインストールが必要になります。
2.django-critical のインストール、設定
django-critical
のインストール、設定を実施します。
3.template ファイルの調整
template ファイルに読み込み記述を追加する必要があります。
4.動作確認
1. 前提となる node.js
のライブラリのインストール
node.js
関連のツールをインストールしていきます。
-
node npm のインストール
node.jsをyumでインストールする(centos6.5) - Qiita を参考にしました。
WARNING が出ますが、強行します。yum install gcc gcc-c++ yum install epel-release yum install nodejs npm --enablerepo=epel
パッケージをダウンロードしています: warning: rpmts_HdrFromFdno: Header V4 RSA/SHA1 Signature, key ID f2ee9d55: NOKEY Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo Importing GPG key 0xF2EE9D55: Userid : CentOS SoftwareCollections SIG (https://wiki.centos.org/SpecialInterestGroup/SCLo) <security@centos.org> Package: centos-release-scl-rh-2-3.el6.centos.noarch (@extras) From : /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo
-
penthouse のインストール
django-critical
で使用可能なpenthouse
の version は 結構前のものです。
python からは、index.js
ではなく、penthouse.js
を指定する必要があり、0.4.0
以前だと、penthouse.js
がバンドルされていますので、ここでは、alpha 版ではない1番新しい version の0.3.6
をインストールします。
また、settings.py
の default 設定に従う場合は、django-project の root フォルダの配下にnode_module
フォルダがあると、設定がしやすいので、install コマンドは django-project の root フォルダで実施するのをお勧めします。
npm install penthouse@0.3.6
2.django-criticalのインストール、設定
django-critical には、encoding 関連のバグがあり、マルチバイド文字列を含む html 、もしくは、encoding 設定が UTF-8 等だと、plugin 内の処理でエラーとなります。このため、以下 pullrequest を参考に、プログラムを修正する必要があります。
あまりよい修正の仕方ではないのかもしれませんが、取り込めば動かすことができます。
Fixes Encoding issue by programmdesign · Pull Request #4 · martinblech/django-critical
django-critical を folk して上記の修正を取り込んだものを以下に UP しました。
kemsakurai/django-critical: Inlines critical path CSS and defers loading full CSS asynchronously.
この folk したものをインストールします。
django-critical のインストール
pip で django-critical
をインストールします。
pip install git+https://github.com/kemsakurai/django-critical
pip list | grep django-critical
---------------------------------------------
django-critical (0.1.1)
---------------------------------------------
設定
基本的に、README.md の設定に従い設定を行います。
settings.py
に設定を追加します。
-
INSTALLED_APPS critical を追加
INSTALLED_APPS = ( # other apps "critical", )
-
MIDDLEWARE_CLASSES に、
"critical.middleware.CriticalCssMiddleware"
を追加
MIDDLEWARE_CLASSES = ( .... # django-htmlmin "htmlmin.middleware.HtmlMinifyMiddleware", "critical.middleware.CriticalCssMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", ... )
-
CRITICAL_PENTHOUSE_PATH と、CRITICAL_PHANTOMJS_PATH の設定
以下のように、penthouse.js
の path とphantomjs
の path を設定します。
phantomjs
は、penthouse.js
をインストールすると、芋づるでインストールされます。
CRITICAL_PENTHOUSE_PATH = os.path.join( BASE_DIR, 'node_modules/penthouse/penthouse.js') CRITICAL_PHANTOMJS_PATH = os.path.join( BASE_DIR, 'node_modules/penthouse/node_modules/phantomjs/bin/phantomjs')
3.template ファイルの調整
以下、テンプレートタグの抜粋です。全量はmezzanine-theme-clean-blog/base.html at master · kemsakurai/mezzanine-theme-clean-blog をご確認ください。
-
base.htmlの抜粋
{% load critical %} {% critical %} {% compress css %} <!-- Bootstrap Core CSS --> <link href="{% static "css/bootstrap.min.css" %}" rel="stylesheet"> <link href="{% static "css/clean-blog.min.css" %}" rel="stylesheet"> <!-- Custom Fonts --> <link href="{% static "css/font-awesome.min.css" %}" rel="stylesheet"> <link href="{% static "css/fonts.css" %}" rel="stylesheet"> <!-- Code Hilite --> {% ifinstalled mezzanine_pagedown %} <link rel="stylesheet" href="{% static "css/codehilite.css" %}"> {% endifinstalled %} {% if LANGUAGE_BIDI %} <link rel="stylesheet" href="{% static "css/rtl.css" %}"> {% endif %} {% ifinstalled cartridge.shop %} <link rel="stylesheet" href="{% static "css/cartridge.css" %}"> {% if LANGUAGE_BIDI %} <link rel="stylesheet" href="{% static "css/cartridge.rtl.css" %}"> {% endif %} {% endifinstalled %} {% block extra_css %}{% endblock %} {% endcompress %} {% endcritical %} ................. {% autoescape off %} {% critical_async %} {% endautoescape %} </body>
-
criticalタグのロード
{% load critical %}
でタグの読み込みをします。 -
criticalCSS を生成したい箇所を囲む
{% critical %}
、{% endcritical %}
で、criticalCSSを生成したい箇所を囲みます。
上記は、タグ内に django-compressor の{% compress css %}
タグがあり、圧縮、結合して作成されたcssファイルのcriticalCSSを生成します。 -
元々のcss の遅延ロードを行う
body タグ直前に以下のタグを追加することで、criticalCSSの出力対象 css ファイルを遅延読み込みすることができます。
上記タグで、以下のHTMLが出力されます。{% autoescape off %} {% critical_async %} {% endautoescape %}
で、もともと CSS のリンクが出るはずの場所に、inline CSS が書き出させれます。<script> !function(e){"use strict";var n=function(n,t,o){function r(e){if(a.body)return e();setTimeout(function(){r(e)})}function i(){l.addEventListener&&l.removeEventListener("load",i),l.media=o||"all"}var d,a=e.document,l=a.createElement("link");if(t)d=t;else{var s=(a.body||a.getElementsByTagName("head")[0]).childNodes;d=s[s.length-1]}var f=a.styleSheets;l.rel="stylesheet",l.href=n,l.media="only x",r(function(){d.parentNode.insertBefore(l,t?d:d.nextSibling)});var c=function(e){for(var n=l.href,t=f.length;t--;)if(f[t].href===n)return e();setTimeout(function(){c(e)})};return l.addEventListener&&l.addEventListener("load",i),l.onloadcssdefined=c,c(i),l};"undefined"!=typeof exports?exports.loadCSS=n:e.loadCSS=n; var elem = document.getElementById("django-critical-async-css-marker"); loadCSS('https://www.monotalk.xyz/static/CACHE/css/690a0d57c104.css', elem); elem.parentNode.removeChild(elem); }("undefined"!=typeof global?global:this); </script>
4.動作確認
動作確認のした際の挙動について記載します。
-
初回表示時は異常に遅い
初回表示時、ページ描画とともに、penthouse
のコマンドが実行され、phantomjs
が起動します。
10秒ほどページ描画に時間がかかり、inline CSS の cache が作成され、2回目の表示以降 cahce が使われ早くなる動作となります。
ですので、実ユーザが初回起動にあたらないように、cache 作成のタイミングを工夫する必要があるかと思います。 -
実施前、実施後の Page Speed Insight の点数
実施前、88点で、実施後、92点になりました。
実施労力の割に点数の上がり幅は低いです。
まとめ
Django/Mezzanine の template に critical CSS を組み込むため、django-critical
を使ってみました。
以下、まとめます。
-
django-compressor との相性がいい。
compressor で 圧縮/結合した CSS を入力に用いることができ、また CSS の遅延読み込みが可能なため競合することなく使えます。 -
メンテされていないが、動く。
日本語環境で使えないバグもあり、依存する node ライブラリが古いです。頑張って動かすことはできましたが、仕事で使ったりするには少し不安です。 -
エンコードの問題を解決し、新しめの critical で動かす?
penthouse
の新しい version で動くようにして、エンコードの問題を解決すれば、結構イケてるものになりそうな気がします。
critical を試してみたので、それで動作するように改造してみようかと思います。
以上です。
コメント