ブログにJavaScriptの全文検索ライブラリを導入したらブラウザクラッシャーになった。
JamstackなブログにJavaScriptの全文検索ライブラリを導入したらブラウザクラッシャーになりました。
採用したライブラリが悪いわけではなく、自分の事前調査・動作確認不足により発生した問題のため、反省として記事にしておきます。
実現したかったもの
Gridsome製の自分のブログで全文検索したかったので、クライアントサイドで動作する全文検索ライブラリのlunr.jsを導入しました。
lunr.jsを採用したのは、npm trendsで調べて人気だったのと、日本語に対応していたからです。
elasticlunr vs flexsearch vs fuse.js vs lunr | npm trends
できあがったもの
なかなか良さそうに見えます。ビルド用のPCからは普通に使えるのでそのまま公開しました。
その後、なんとなく手元のダブレット(iPad mini 2 Retina)から動作確認したところ、OSごとブラウザがクラッシュしました。
このままだとどこかしらの県警のお世話になりかねないため、とりあえずChromeのDeveloper ToolでHeap snapshotを見てみます。
lunrのIndexで189MB近く使われているようです。
iPad mini 2 RetinaのRAMは1GBなので、当然クラッシュします。
それ以前に、単なるテキストサイトで断りもなしにメモリを200MB近く食ってしまうのは問題があります。
何が悪かったか
lunrは全文検索の精度がとても良いのですが、その分メモリ効率が犠牲になっているように見えます。
- lots of unnecessary objects in invertedIndex (40% of memory) · Issue #316 · olivernn/lunr.js
- Space-Efficient Full-Text Search with Rust and WebAssembly
私のブログは記事数が200以上あり、lunerが記事をIndexingした結果をシリアライズすると2MB近くになるため、工夫無しでlunrを利用するのに向いていないようです。
なお、ブログではGridsomeでのビルド時にサーバサイドでindexをjsonにシリアライズし、beforeMount
でシリアライズされたindexを読み込む実装にしていました。
// gridsome.server.js
[...]
// indexをjsonにシリアライズ
const docs = data.allBlogPost.edges;
const index = lunr(function () {
this.use(lunr.multiLanguage("en", "jp"));
this.ref("id");
this.field("text");
this.field("title", { boost: 10 });
docs.forEach(({ node }) => {
this.add({ id: node.id, title: node.title, text: node.content.replace(/<\/?[^>]+>/gi, "") });
}, this);
});
fs.writeJsonSync(CACHE_PATH, index,
{
encoding: 'utf-8',
replacer: null,
spaces: " "
},
err => {
});
[...]
// Search.vue
[...]
const serialisedData = require("serialised.json");
beforeMount() {
this.lunrIndex = lunr.Index.load(serialisedData);
},
[...]
ドキュメントとソースコードを読んで使い方を工夫すればよいのかもしれませんが、そこまで頑張る気はなかったので、lunrの採用を諦めました。
ブラウザクラッシャーのリリースを防ぐために何をすべきだったか
- あらかじめDeveloper ToolでPerformanceを見ておくべきだった。
- PCのみの動作確認で終わらせずに、モバイル端末を使ったりLighthouseでパフォーマンスチェックすべきだった。
- 採用するライブラリの性能を調査・Issueをチェックしておくべきだった。
- 近い状況のIssue(ここまですごい使い方はしていませんが): Lunr index building is killed with OOM error · Issue #306 · olivernn/lunr.js
- flexsearchが提供している全文検索のbenchmark: Benchmark
これに懲りずに自分のブログの改良はしていきたいなと思いました。
Discussion