v8のlastIndexOfが(相対的に)遅い

  • 投稿日:
  • by
  • カテゴリ:

最近honoにコントリビュートをしていて、正規表現の結果からの文字列を探索する際にindexOf()の代わりにlastIndexOf()を使ったら最適化できないだろうかと考えたりしていたのですが、だめでした。これはその際に調べたことのメモです。

まず最初に、1000個のcaptureを返す正規表現の結果から500番目を探すパターンでベンチマークをとってみます。

どのバージョンでもindexOf()が文字通り桁違いに速く、lastIndexOf()はforやwhileにすら負けて最下位になっています。(ただindexOf()を使った場合にも変数へのアサインを挟んだだけでここまでの差にはならなかったりするので、どれも基本的には速く、ちょっとした条件の変化で結果が変わったりする程度のものでもあるとは思います。)単純に1つの空文字列を探索する場合にはindexOf()を使うのがよさそうです。

v8のコードを見てみたところ、indexOfの方はc++のコードで、lastIndexOfはマクロのコードで書かれていたので、その辺りで違いが出ているのかもしれません。

次に、以下のように「最大で2つの連続した空文字列が返ってくる match() の結果から、一番最後の空文字列の位置を取得する(captureは2000個)」というケースでのベンチマークをとってみます。

これはバージョンごとの違いが大きく、v16だと「indexOf()とforループがほぼ同じ性能」で、v17だと「indexOf()が最速で2倍近い性能」、そしてv18(pre)だと「forループが最速」となりました。

結論のようなものはなかなか難しいですが。

  • 正規表現の結果から最初の1つの文字列を探す場合にはArray.prototype.indexOf()が桁違いに速い
  • いまのところArray.prototype.lastIndexOf()は遅い
  • 少し条件が込み入ってくるとforループが最速になることもある

というところでしょうか。v18でもネイティブで実装されたlastIndexOf()よりもforループのの方が早くなるケースがあるというのは若干複雑な気持ちにはなりました。

TypeScriptのConditional Typesでinferを使って足し算を定義する

  • 投稿日:
  • by
  • カテゴリ:

String Literal TypesTemplate Literal Typesを使うとGenericsや関数の引数の文字列から型を作れるという話を聞いたので、勉強も兼ねて足し算を定義してみました。

以下のような感じになります。 `Expr<"1 + 1">` が `"10"` というString Literal Typeになります。2進数の足し算のみに対応していて、未対応の式ではUnrecognizedExpression型になります。3項以上でも計算できます。

型が補完されるエディタを使っていると、答を自分で打たなくても補完されたりして楽しいです。

これをtscで変換すると以下のようになるのですが、これを見て、TypeScriptの型はほんとに実行時には影響のないものなのだなと実感することもできます。

足し算の定義は業務の役には立たないものの、このあたりを勉強しつつTypeScriptを使っているウェブのフレームワーク(🔥)にAdded type to c.req.param key.というPRを作ってみて、引数から型を生成するようなパターンには可能性があるなと感じたりもしています。

ちなみにTypeScriptではdocument.querySelector(`a`)と指定したときに引数からHTMLAnchorElementが推論されたりして面白いのですが、`div a`や`a[href^="#"]`だとHTMLElementになってしまうというのがあるのですが、以下のように指定すると要素名っぽいものから推論されるようにできます。(面白いけど、やっぱりこれも使う機会はないとは思いますが。)

MTBockEidtorのカスタムブロックでData APIを使う方法

  • 投稿日:
  • by
  • カテゴリ:

これはどんな記事か?

Movable Type 7でプラグインとして利用できるMTBlockEditorでは、管理画面で作成する「カスタムブロック」やプラグインから追加する独自のブロックでブロックの種類を追加することができますが、それらのブロックの中でData APIを使うことも可能です。

この記事ではいくつかのパターンを紹介していきます。

管理画面で作成するカスタムブロック

まず最初に「カスタムブロック」を使った例の紹介になりますが、最初に書いておくとこの方法は実際のところなかなか厳しいです。

  • srcがdata:であるiframeの内で実行されれるため、JavaScriptでData APIにアクセスする際のOriginヘッダーがnullになります。そのため mt-config.cgi で DataAPICORSAllowOrigin の環境変数に対して null を指定する必要があります(これは、外部のサイトからでも JavaScript でアクセス可能にするという設定になります)
  • カスタムスクリプトで実行するためプレビューが更新されるたびにスクリプトが実行される形になり、実行毎の状態を保存することができません。つまりプレビューが更新されるたびにData APIへのアクセスが発生します。CGIで実行している時にはレスポンスが悪くなったり、また認証を必要とする場合にはプレビューが更新されるたびに認証が発生する形になったりしてしまう問題があります。

というところが主な厳しいポイントです。

しかし、そういう部分もありつつではありますが、IPアドレス制限やBASIC認証を設定すれば利用できるケースもありますし、まずはPoCとして、実現が可能かどうかというところも大事だと思うので、以下で簡単な例を紹介します。

カスタムスクリプトの効率的な開発と運用の1つの方法

本題に入る前に、カスタムスクリプトの開発と運用の方法を1つ紹介します。

公式でもよく例として出されているカスタムスクリプトに直接style要素やscript要素を書くやり方は、一つの管理しやすい方法ではありますが、JavaScriptの処理が増えてくるとコーディングが大変であったり更新がしにくくなったりする面もあります。そういった時には、cssやjsのファイルを外部に置いて、linkやscript要素で読み込む方法を使うことができます。例えば以下のような感じです。

CSSはlink要素を使い、JavaScriptはscript要素のsrc属性を使って指定します。JavaScriptにパラメータを渡す場合にはdata属性を使います。script要素にdefer属性(またはtype=moduleにしてもよいかもしれません)を指定することでDOMContentLoadedで囲む必要もなくなりシンプルにすることができます。

webpackを使っていれば「webpack serve」でバンドルしたファイルをローカルの開発サーバーから参照したりすることもできるので、「ファイルの更新 -> ブロックエディタの編集画面のリロード」だけで(カスタムブロックの保存操作などをすることなく)開発をしていくことができるようになります。

今回の例でもこのやり方で開発を行っています。

公開されている記事のリンクを挿入する

ここからが本題です。Data APIを使って記事データを取得してリンクを挿入するブロックを作ります。

ブロックを追加するとキーワードの入力欄が表示されるので、そこにキーワードを入れて検索ボタンをクリックすると候補が出てきて、選択するとその記事のリンクが挿入されるというものです。

CSSとJavaScriptは以下のようにしました。

GitHubに保存しておくとjsdelivrなどを使ってCDN経由で参照できるので、カスタムブロックのカスタムスクリプト欄は以下のようになります。

以下のように動作します。

前述の通りカスタムブロックでは厳しいポイントも多いですが、状況によっては利用できそうな雰囲気も感じられるのではないかと思います。

プラグインから追加する独自のブロック

プラグインから独自のブロックを追加する場合にはカスタムブロックの時にあったような制限はなく、管理画面へJavaScriptを挿入するような自由度で作成することができます。(その反面、XSSなどのセキュリティ的な問題が発生しないように配慮する必要がありますが、雛形作成ツールから作成した場合にはセキュリティ的な問題が起きにくいようにもなっています。)

この記事ではData APIを使った独自のブロックの例として、DataAPIBlockExampleとを作成しました。基本的な動作としては前述のカスタムブロックでの例と同じですが、DataAPIProxy を使って現在のユーザーでサインインした状態で記事を取得するので、未公開の記事のリンクも挿入できるようになっています。その他にも以下のような違いがあります。

  • カスタムブロックのように何度も読み込まれたりしないので、よりリッチな表現を利用しやすい
    • また表現については、CMSのスタイルをそのまま利用できるので、統一感のあるUIで作りやすい
  • 「挿入時の検索語」のような(出力に含まない)メタ情報も、簡単に保存しておくことができる

以下のように動作します。

雛形作成ツールで作成されたものからはそれほど多くない差分でここまで動くようになるので、構築するサイトにあわせた独自のブロックをこういった形で作成をするというのも、現実的な選択肢であると思います。

この記事について

この記事は Movable Type Advent Calendar 2021 の25日目の記事です。皆様お疲れさまでした。それでは良いお年を!

Movable TypeでBlurHashのハッシュ値を出力できるようにするプラグインです。

mt-plugin-BlurHash

以下のように、画像にダウンロードを待つ間にプレイスホルダー的にぼやけた画像を表示ことができるようになります。ぼやけた画像は1画像あたり30文字程度に圧縮されているのでHTMLと一緒にドキュメントに埋め込んでレスポンスとして返して、JavaScriptでcanvas要素で表示させるというやり方になっています。(疑似的に3G回線程度の速度でアクセスした状態にして動画を収録しています)

使い方

プラグインをインストールするとmt:AssetBlurHashタグが使えるようになります。以下のようなテンプレートで、画像のアセットのあるコンテキストでmt:AssetBlurHashを使ってハッシュ値を書き出します。

ハッシュ値を画像にするのはウェブページの場合にはJavaScriptを使うことになりますが、「読み込むだけで表示してくれるJavaScript」のようなものは用意されていないので、自分で用意する必要があります。そこはちょっと面倒ではありますが、デコードするライブラリはnpmでインストールすることはできるので、プラグインのデモに含まれている以下の程度の簡単なJavaScript(TypeScript)で表示することができます。

サポートしている環境

  • Movable Type 7

利用可能なImageDriver

  • ImageMagick
  • GraphicsMagick
  • Imager

ユーザー体験的にどうなのか?

個人的な意見としては、ぼやっと表示されることで確かに雰囲気はでるものの、正直なところこれだけで大きくユーザー体験が改善されるかというとちょっと分からないなと思っています。(しかしデータをとったら、きちんと体験が改善されているという結果がでるという可能性も大いにあると思いますが)
とはいえ、そこまで確かなものでもないとしても、表現の選択肢の一つとして持っておくにはよいものかなと思っています。

こんな感じで動くMovable Typeのプラグインです。

プラグインについて

先日、MovableType.netのブロックエディタをソフトウェア版のMovable Typeでも利用できるようになるプラグインのα版が公開されました。

このプラグインでは、「指定されたURLからOpen Graph Protocolを中心としたメタ情報を取得して、ブログカードと呼ばれるような見た目のリンクを生成する」というブロックタイプをブロックエディタに追加します。

エディタで生成されたブログカードをそのまま使うこともできますが、さらにカスタマイズして、メタ情報を使ってMTMLで任意のHTMLを書き出すこともできます。

mt-plugin-mtbe-OGPEmbed

筆者について

筆者はこの記事を書いている時点で、Movable Typeとブロックエディタの開発メンバーです。

このウェブサイト(blog.taaas.jp)の記事は個人の意見であり公開しているのは個人的なプロジェクトで、この記事のプラグインについても個人的なものではありますが、今回のプラグインはα版が未公開の時期から準備されてはいて製品との関連も強いため、念のため明示しておきます。

簡単な使い方

インストールするとMTブロックエディタに「OGPEmbed」のボタンが追加されるので、そこからブロックを追加して、URLを指定するとブログカードが挿入されます。

公開側では、単純にmt:ContentFieldValueで書き出した場合にはHTMLのみが書き出されます。書き出されるデータにはCSSは含まれないので、サイト毎に指定する必要があります。標準のCSSは以下のようなものです。

MTMLによるブログカードの生成

単純にmt:ContentFieldValueで書き出す他に、MTMLで書き出すこともできます。標準の出力と同じブロクカードは以下のMTMLで得ることができます。

mt:Varでは以下の情報を利用することができます。

  • meta{icon} : link[rel="icon"]またはlink[rel="shortcut"]
  • meta{ogType} : meta[property="og:type"]
  • meta{ogTitle} : meta[property="og:title"]またはtitle
  • meta{ogDescription} : meta[property="og:description"]またはmeta[name="description"]
  • meta[ogImage} : meta[property="og:image"](複数ある場合には最初の要素)
  • meta{ogImageWidth} : meta[property="og:image:width"]
  • meta{ogImageHeight} : meta[property="og:image:height"]
  • meta{ogUrl} : meta[property="og:url"]またはlink[rel="canonical"]
  • meta{ogSiteName} : meta[property="og:site_name"]

この記事について

この記事は Movable Type Advent Calendar 2020 の25日目の記事です。皆様お疲れさまでした。それでは良いお年を!