うならぼ

どうも。

Mastodon関連で作ったもの

6/13 9/14現在、まだ飽きてはいない。分散云々や独立性云々はそこまで関心ないけど、なかなか楽しいLTLがそこにあったので。

UserScript

なおWebUIで動作するものは https://*/web/* というURLで起動するようになっています。https://mstdn.jp/ といったURLでアクセスした場合は(見た目上のURLが変化していても)起動しません。https://mstdn.jp/web/timelines/public/local といったURLをブックマークしておくとよいでしょう。

あまり汎用的じゃないもの:

Bookmarklet

UserStyle

  • キラキラッター風(kktCSS)のお手伝い
    設定ページと外向きのページを勝手に実装したあとマージされ、その後も色々お手伝いしてます。未だにiPhone5s+iOS9使いなので、そこで起きるバグの修正とか…。
  • ごらく部風
    思いっきり作りかけな上に、開発のきっかけになったインスタンスが休業してるという。
  • 個人的なカスタマイズ集
    文字サイズを一回り小さくしたり、メディアをcontain表示したり、ユーザーページのアバターのアニメーションを調整したり、マウスオーバーでタイムスタンプを絶対時間で表記したり、等々があります。おまけで1.3向けバグ修正寄せ集めも残してあります。

その他

Pawooのaccount_media_timelineをメイン拠点やkktに取り込んだりしてましたが、今は本家のメディアギャラリーがあるのでほとんど残ってないですね。

本家には翻訳の修正とかCSSの修正とかを多少投げる程度で穏便に暮らしていたはずなんですが、気が付いたら緑チェックマーク付けられるようになってました。ありゃま。

Hatena::Let、もしくはES5世代のminifyツール(JavaScript::Squish)でTemplate Literalsを使う

ES2015のTemplate Literals、便利ですねー。プレースホルダの展開といい、改行を含められることといい、"‘をエスケープせずに済むことといい、UserScriptやブックマークレットではとても便利です。

そんな便利な Template Literals ですが、Hatena::Let でそのまま使うと、@javascript_url や .packed.js の出力がまずいことになる場合があります。

どうまずいのか、回避策はないのか、という話をします。

問題点

Hatena::Let では JavaScript::Squish というライブラリでminifyを行っているのですが、これがES2015に対応していません。単にES2015の構文が無視されるだけではありますが、これが Template Literals では問題になります。つまり、文字列リテラルではなくただの式としてminifyされてしまいます。

大きく分けると、「空白が削除されてしまう」「各種開始記号が解釈されてしまう」という二つの問題があります。

1. リテラル内でも空白が削除されてしまう

JavaScript の式において、空白文字はいくつ連続しても意味は変わりません。また、記号で区切られる個所では前後に空白を入れても入れなくてもよいです。例えば次の二つのコードは同義なので、後者にminifyすることが可能です。

return          window   .  alert
  ( 100 -100
    + " === 0"
  );

return window.alert(100-100+" === 0");

というのはJavaScriptに限った話で、例えばCSSを同様にminifyされると意味が変わってしまいます。

body .foo ::before {
  margin: 100px -100px;
}

body.foo::before{margin: 100px-100px;}

あとは Template literals のプレースホルダの直後とか。

${rootid} span { ... }

${rootid}span{...}

JavaScript::Squishでは !%&()*+,-/:;<=>?[]\{|}~ の前後の空白が取り除かれます。

2. リテラル内でも各種開始記号が解釈されてしまう

JavaScriptには正規表現リテラルがあり、スラッシュで始まり、スラッシュ+αで終わります。この中の空白もむやみに取り除くことはできないので、JavaScript::Squish もこれを認識します。ついでに、本来は文字列リテラル正規表現リテラルの中では改行をしてはいけませんが、JavaScript::Squish は緩いので容認します。

let a = `<img src="..." />`;
let b = `<img src="..." />`;
let c = `<img src="..." />`;

これを JavaScript::Squish にかけると次のようになります。

let a=`<img src="..."/>`;
let b = `<img src="..." />`;let c=`<img src="..."/

一行目の />`; から二行目の "..." / までが正規表現リテラルとして認識され、その間はminifyが行われません。三行目の / でやはり正規表現リテラルが始まりますが、このリテラルは終了しないままにソースコードが終了しています。すると、JavaScript::Squish は開始記号より後の文字列を出力しません。

もうめちゃくちゃですね。

回避策

// これを...

alert(`<div class="${LET_ID}" onclick="alert('test')">
</div>`);

// こう。

alert(`'<div class="${LET_ID}" onclick="alert(\'test\')">
</div>'`.slice(1, -1));

すぐ内側にシングルクォートを入れて、ただの文字列リテラルとしても解釈できるようにします。Template literals 内でもエスケープ文字は有効なので、中でシングルクォートを使いたければエスケープします。最後に余分なシングルクォートを取り除いてできあがり。

なお改行が使えているのは JavaScript::Squish が甘いだけで厳密にはダメです。このブログのシンタックスハイライトでも改行を越えては認識していませんね。あとは匿名関数のコメントに書いておいて Function.prototype.toString() してごにょごにょするぐらいですが、minifyで消されるので…一行ずつ書いた文字列リテラルを連結するぐらいでしょうか。

参考

そしてきっかけとなった id:noromamba 氏と id:a-kuma3 氏による作品。誰しも(?)考えるであろう、ページタイトルとURLをまとめてコピーするやつ。