発生していた問題
解決方法
Mathjaxのレンダラーを変更する。コンソールで実行しても良いが、今回は最小限の拡張機能を作成。
できあがったもの
以下を一つのフォルダに入れて、「パッケージ化されていない拡張機能」として読み込めば解消された。
manifest.json:
{
"manifest_version": 3,
"name": "Colab MathJax Fixer",
"version": "1.0",
"description": "Fix MathJax rendering in Google Colab",
"content_scripts": [
{
"matches": ["https://colab.research.google.com/*"],
"js": ["content.js"],
"run_at": "document_end",
"world": "MAIN"
}
],
"permissions": [
"activeTab"
]
}
content.js:
(function() {
'use strict';
console.log('[Colab MathJax Fixer] Extension loaded in MAIN world');
function fixMathJaxRendering() {
console.log('[Colab MathJax Fixer] Running MathJax fix...');
console.log('[Colab MathJax Fixer] MathJax:', typeof MathJax);
if (typeof MathJax !== 'undefined' && MathJax.Hub) {
try {
MathJax.Hub.Queue(["setRenderer", MathJax.Hub, "CommonHTML"]);
MathJax.Hub.Queue(["Rerender", MathJax.Hub]);
console.log('[Colab MathJax Fixer] Fix applied successfully');
return true;
} catch (error) {
console.log('[Colab MathJax Fixer] Fix failed:', error.message);
}
} else {
console.log('[Colab MathJax Fixer] MathJax not available');
}
return false;
}
// 指定した秒数後に実行
const delays = [0.1, 0.5, 1];
let hasSucceeded = false;
const timeouts = [];
delays.forEach((delay, index) => {
const timeoutId = setTimeout(() => {
if (hasSucceeded) {
console.log(`[Colab MathJax Fixer] Already succeeded, skipping attempt ${index + 1}`);
return;
}
console.log(`[Colab MathJax Fixer] Attempt ${index + 1}/${delays.length} (after ${delay}s)`);
if (fixMathJaxRendering()) {
hasSucceeded = true;
console.log('[Colab MathJax Fixer] Success! Clearing remaining timeouts.');
// 残りのタイマーをすべてクリア
timeouts.forEach(id => clearTimeout(id));
}
}, delay * 1000);
timeouts.push(timeoutId);
});
})();
jsの実装でモヤモヤしているところ:
-
if (typeof MathJax !== 'undefined' && MathJax.Hub)
という分岐は本当に必要だろうか?try-catchで出てくるエラー文をそのまま流すのに吸収させても良いのではないだろうか?エラーメッセージすら出ずに失敗する時や、エラーメッセージだとわかりにくいことがあるかに依りそう。 - delayの部分、for文みたいに途中でbreakしてしまうことはできるだろうか?普通どのように実装するのだろうか?
経緯
Tofuになるのが嫌だったので、解消したくなった。調べてもあまり出てこず、Gemini 2.5 Pro と喋ったところ、解決策の一つとして、ブラウザのコンソールで以下を走らせることを提案された。走らせると上手く行ったので拡張機能として自動化したくなった。
MathJax.Hub.Queue(["setRenderer", MathJax.Hub, "CommonHTML"]);
MathJax.Hub.Queue(["Rerender", MathJax.Hub]);
Gemini 2.5 Pro、Claude Code Sonnet 4に拡張機能を実装してと頼んだが、はじめは上手く行かなかった。ページ内コンテンツへのアクセスに失敗しているように見えた。 その旨だけ友人にぽろっと喋ると、「content_scriptsを使うとページ内で走るjsを突っ込める」と返答があった。Claude Code にそのまま伝えると解決して驚いた。リアル中国語の部屋である。
実際間違っていたのはアクセス権限関連であったで、詰まっていた部分について以下のように理解した:
-
manifest.json
の方でページ内コンテンツ(JavaScript)へのアクセス権限を管理しているから、 - "content_scripts" の
"world"
をデフォルトの"ISOLATED"
から"MAIN"
にしてやることで、 - 拡張機能から中のMathjaxへアクセスできるようになる。
感想
- 思い立ってから30分もせず、ちょっとした嫌なことを解消できるのは嬉しい!ありがとう大規模LLM。ありがとう友人。
- 自分で全部コードのも思いつけるようになりたいなぁ。JavaScriptでコンテンツをどう操作するとか、Chrome拡張機能の仕様とかにもう少し詳しくなりたい。
- 私はただ松尾研の強化学習の課題をやりたかっただけなのに!まさにYak Shaving!