まだ重たいCMSをお使いですか?
毎秒1000リクエスト を捌く超高速CMS「adiary

2019/07/05(金)JavaScriptから .png 画像を加工してCSSに適用する

png画像をJavaScript上で加工して、CSSに適用する方法。

背景

adiaryでは、UIアイコン(このサイトだとページ送りやタグ一覧に出ている▼等)を色指定に基づいて動的にロードしています。

仕組みとしては、予め128種類の色の異なる画像アイコンを用意して、指定色にもっとも近い色をロードするという感じになっていますが、いくつか問題があります。

  • 画像ファイルを増やすには限界があり近似色になってしまう。
  • 1KBにも満たないような小さなファイルをわざわざ別ファイルとしてロードさせるのは嫌。*1

色が固定で良いなら、base64で埋め込むだけの話なのですが……。

.ui-icon {
	background-image:	url('data:image/png;base64,XXXX----XXX=');
}

adiaryはテーマの色をユーザーが自由に変更できるという素敵な機能が付いておりまして、そういうわけにも行きません……。

*1 : Webの表示速度を上げるためにも、ロードファイル数は極力少ないほうが良いわけです。

正攻法

続きを読む

2019/07/02(火)ES2015(ES6)をminifyしたいけど、Node.jsに興味はない場合

ES2015(ES6)のJavaScriptを minify(compress) したかったときに苦戦したメモ。

JavaScript Compressor

古くから有名でお手軽なYUI Compressorをインストールして、圧縮してみたのですが、謎のエラーが出て困ってしまいました。

Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.yahoo.platform.yui.compressor.Bootstrap.main(Bootstrap.java:21)
Caused by: java.util.MissingResourceException: Can't find bundle for base name org.mozilla.javascript.resources.Messages, locale ja_JP
(以下略)

どうやら調べてみると、YUI CompressorはES6(let/const)に対応していないようです。

2019年にJavaScriptを書くのに「ES2015ではないスクリプトを書く」のは考えられないので、ES2015対応のJavaScript Compressorを探してみました。

Node.js に用はない

色々調べてみてもNode.js関連情報しか出てきません。

「Node.js」に興味はなく、純粋にJavaScriptを圧縮したいだけなのに……。

路頭に迷っていたのですが、Uglify-jsというNode.js関連ツールを使うことで、Node.jsとは関係なく単にJavaScriptを圧縮できることがわかりました。

Wabpackというツールもあるのですが、軽く調べた感じではNode.js専用ツールっぽい感じで、単なるJavaScriptの圧縮ツールとしては使いにくそうでした。

Uglify-es

残念ながらUglify-jsは「Uglifyjs 3 (Ver3)」でもES6には対応していません。超注意点です。

Uglify-jsからフォークされた「Uglify-es」というツールを使います。まずこのツールを入れるために、Node.js用のパッケージマネージャー npm をインストールする必要があります。

今回インストールしたサーバはDebainですが、普通にapt-getすると古いツールが入るため、「Debian9 (stretch) に Node.js をインストールする」を参考にVer10系の Node.js を導入しました。

curl -sL https://deb.nodesource.com/setup_10.x | bash -
apt-get install -y nodejs

これで npm が使用できるようになったので、Uglify-esを導入します。

npm install uglify-es

Makefile

Uglify-js@2、Uglify-js@3、Uglify-esでみんなコマンドラインオプションが違うので、情報を探す際はご注意ください。

参考までに作成したMakefileを晒しておきます。

#
# Makefile for adiary.min.js
#
COMPRESSOR = uglifyjs
OPTIONS    = -c -m --comments '/^!/' --source-map includeSources,filename

OUTPUT	   = ../adiary.min.js
MAP_FILE   = ../adiary.min.map

FILES = \
	01_global-variables.js	\
	10_jquery-ext.js	\
	20_init.js		\
	30_css.js		\
	90_PrefixStorage.js	\
	91_jquery-storage.js

all:  $(OUTPUT)

$(OUTPUT): $(FILES) Makefile
	$(COMPRESSOR) $(OPTIONS) $(FILES) -o $(OUTPUT)
	mv $(OUTPUT).map $(MAP_FILE)
-c
ソースファイルを圧縮します
-m
Mangleします。これをつけたほうが圧縮率が高くなります。
--source-map includeSources,filename
mapファイルを作成します。
--comments '/^!/'
「!」マークで始まるコメント(ライセンスコメント)を残します。

terserになりました

uglify-esは更新が停止し、uglify-esをフォークした terser に乗り換えました。

インストール方法。

# apt-get install npm
# npm install terser -g

使い方は uglifyjs と一緒です。

2019/06/30(日)adiary Version3.30 リリース情報

ダウンロードはこちらから

Ver3.30の主な変更点

アップデートしたadiaryでreStructuredTextを使用する場合、adiary.conf.cgi に設定を追加する必要があります。RST(reST)に直接対応した初のCMSだといいな。

続きを読む

2019/05/31(金)adiary Version3.24 リリース情報

ダウンロードはこちらから

Ver3.24の変更点

バグ修正が主です。

  • RSSからのリンクhash(#rss-tm)を除去する際、リロードしないようにしました。
  • はてなブックマークの常時SSL化に伴い、はてなブックマークへのリンクを https に変更。
  • RFC7231に準拠し、リダイレクトを相対パスで出力するよう変更。
  • アルバムにアップロード時の拡張子制約を緩和し、半角英数以外を含むものを許可しました。(Thanks to harata
  • 【conf】<$v.album_allow_ver_ext>の設定を削除
  • 【アルバム】ファイル名に使えない文字の制限を緩和しました。
  • 【Fix】トップページの2ページ目で「前のページ」のリンクが正しくない。(Thanks to sabazo
  • 【Fix】mixiの画像サーバ等、一部のサイトにSSL接続できない。*1
  • 【Fix】body が 0byte の結果を応答するとき、「Content-Length: 0」を送れていなかった。
  • 【Fix/httpd】mime.types をロードする際、コメントも処理していた。
  • 【Fix/httpd】"file?query" 形式のとき、ファイルをロードできない。
  • 【Fix/httpd】拡張子判定時、大文字小文字を区別してしまう。
  • 【Fix/アルバム】ゴミ箱関連のファイル名の挙動がおかしい。
  • 【Fix/アルバム】ファイル名に特殊文字を含む場合の挙動がおかしい時がある。
  • 【Fix/Markdown】「|:---|:---|」のようなテーブルを認識できない。
  • 【Fix/Markdown】通常文字列に「|---|---|」などが続いた場合、テーブルと判定してしまう。

*1 : Net::SSLeayモジュールで、SNIが有効になっていないため。

既知の不具合

  • PostgreSQL/MySQL運用時、外部画像の取り込みが動作しない。

2019/03/12(火)adiary Version3.23 リリース情報

ダウンロードはこちらから

  • Ver3.20以降の変更による累積的なバグ修正、httpd/EXEの修正が多めです。

Ver3.23の変更点

  • Pocketのシェア数が取得できなくなっていたので取得機能を削除しました。*1
  • デフォルトアイコンとデフォルトロゴを変更しました。
  • 静的HTML出力が無効のとき、管理者以外にはエラーメッセージを表示しないように変更。
  • 管理メニューの流れを少し改善しました。
  • 記事編集画面でファイルアップロードの進捗を表示するよう変更。
  • アルバムと記事編集画面のファイル選択ボタンのデザインを変更。
  • 【アルバム】アップロード中の進捗を表示するように変更。
  • 【アルバム】ファイルリネーム時に、画像以外はサムネイルを再生成するよう変更。
  • 【アルバム】ファイルリネーム時に del キーが使用できない。
  • 【httpd/EXE】Socket を STDIN に接続するのを止め、若干高速化しました。
  • 【httpd/EXE】index.htmlを有効化しました。
  • 【httpd/EXE】大きいファイルをダウンロードする場合、すべてメモリに展開しないようにしました。
  • 【adiary.conf.cgi.sample】大きいファイルはテンポラリに書き出すよう変更。
  • 【adiary.conf.cgi.sample】<$Form_options.multipart_use_temp>を<$Form_options.use_temp_flag>に変更。*2
  • 【plugin】非公開コメントにヘルプを出せる機能を追加。
  • 【Fix/plugin】Twitter通知プラグイン。2018/06/13以降、新規認証に失敗していた。
  • 【Fix/Ver3.20-】デザイン編集時に、ヘッダが常に標準のまま(非カスタム状態で)出力されてしまう。
  • 【Fix】稀に最初のファイルアップロードに失敗することがある。
  • 【Fix】静的出力時、ヘッダにゴミが出力される。
  • 【Fix】致命的エラーメッセージ(初期ディレクトリ作成失敗)がきちんと表示されない。
  • 【Fix】大きなファイルを送信されたとき、<$Form_options.multipart_use_temp_dir>を設定していても、すべてメモリに展開していた。*3
  • 【Fix】テンポラリとして /tmp などパーティションが異なるディレクトリを指定すると、アップロードに失敗する。
  • 【Fix】コメント欄でTABが入力できないことがある。
  • 【Security/httpd/EXE】HTTP_HOSTヘッダにタグを挿入可能だった。*4
  • 【Security】HTTP_HOSTヘッダに虚偽の設定をした上でコメントを投稿するとRSSのホスト名部分を外部から書き換えられてしまう。*5

*1 : query.yahooapis.com が突然サービス終了したため

*2 : ディレクトリ名を設定するのかフラグを設定するのか非常にわかりにくく、自分でハマってしまったので……。

*3 : multipart_use_temp_dirを設定していない場合、無条件にメモリに展開します。

*4 : RSS以外に展開されることはないので、実害はあまりない。

*5 : Hostヘッダインジェクションと呼ばれる攻撃です。一般的なレンタルサーバでは VirtualHost と呼ばれる設定を使用しているため問題ありません。

Hostヘッダインジェクションについて

今回のバージョンアップで、RSSのホスト部分を第3者が書き換え可能になるセキィリティホールが修正されています。

  • 一般的なレンタルサーバでは問題ありません。
  • 独自サーバ等でも、(最初以外の)VirtualHost部分にadiaryの設定がある場合は問題ありません。
  • adiary.env.cgiで <Server_url> が設定されている場合問題ありません。

いわゆるHostヘッダインジェクションと呼ばれる問題で、Hostヘッダからサーバのホスト名を設定する仕様が原因になっています。幸い、Host名として不正なものはサーバソフトウェアが弾くのでJavaScriptを埋め込まれるといった問題は起こりませんが*6、RSSのURLが書き換えられる問題はおきます。

対策としては、最初のインストール時に HTTP_HOST から信頼できる URL を生成し記録しておくなどの方法が有効です。*7

*6 : adiary.httpd.plのVer1.04以前にはこの問題が存在しますが、HTTP_HOSTをそのまま埋め込むのはRSSのみなのでスクリプトを実行することはできません。RSSのXMLをパースエラーにする程度です。

*7 : adiaryでは管理者ログイン時に HTTP_HOST 情報を記録するようにしました。