無料の最後の手段としてのページスピード最適化スクリプト
最も遅いページでさえも改善するこの最後の手段で、修正不可能なページを高速化しましょう

無料の最後の手段としてのページスピード最適化スクリプト
Core Web Vitalsのコンサルタントとして、時折「修正不可能なページ」に遭遇することがあります。それは、私が修正方法を知らないから修正不可能なわけではありません! そうではなく、修正するにはすでにリニューアルが予定されているサイトの大部分を書き直す必要があるためです。あるいは、WIX、HubSpot、WebFlowなどのよりクローズドなCMSシステムで見られるように、サイトのコードを改善するためのアクセス権や制御が十分にない場合もあります。そして最後に、単に予算がない場合です。頻繁に起こることではありませんが、クライアントが行うべき作業量と支払うべき金額を正確に予測できないことも時にはあるのです。
最終レビュー:Arjen Karel (2026年3月)
「最後の手段としてのページスピード最適化スクリプト」の紹介
このような窮地に陥ったとき、このスクリプトは、より良いものを構築できるようになるまでの間、少なくともページスピードを少しでも改善するための、必死の最終手段となります。これは、Mutation Observerを使用して巧みに機能します。このスクリプトは、ブラウザによってサイトのDocument Object Modelが作成されるのを監視し、即座に介入して遅いコードをより速いコードに置き換えます。
機能:
- すべてのレンダリングブロック・スクリプトを捕捉し、スクリプトのtypeをtype="module"に変更することで遅延させます。このテクニックは、すべてのモジュールスクリプトがデフォルトで遅延されるという事実を利用しています。インラインスクリプトであっても同様です。これにより、すべてのページスクリプトを遅延させる最も安全な方法となります。
- 画像の遅延読み込み: loading="lazy"とdecoding="async"がすべての画像に追加されます。これにより、非同期の画像レイアウト更新とともに、画像がほぼ表示領域に入るまでこれらの画像の読み込みを遅延させます。注意:LCP画像を遅延読み込みさせないでください。除外するにはprioImgs設定を使用します。LCP画像の遅延読み込みがパフォーマンスを低下させる理由を参照してください。
- iframeの遅延読み込み。画像の場合と同様に、iframeを遅延読み込みさせることで、より重要なあなた自身のコンテンツを優先させることができます!
設定
このスクリプトは単一の「configオブジェクト」を受け取り、その設定を使用して、重要な画像やスクリプトの遅延や遅延読み込みをスキップします。iframeの場合は逆になり、設定に一致するiframeのみを遅延読み込みします。すべての設定は正規表現として指定します。怖そうに聞こえるかもしれませんが、実際には非常にシンプルです。
- prioScripts: srcが設定に一致するスクリプトの遅延をスキップします。
例: 'jquery|menu' は、jqueryとメニューのスクリプトに一致します。 - prioImgs: 画像名、画像クラス、または画像IDが一致するすべての画像の遅延読み込みをスキップします。
例: 'hero' は、<img id="hero" ..> と <img src="hero.jpg"> の両方に一致します。 - lazyFrames: iframeのsrcが設定に一致するiframeのみを遅延読み込みします。
例: 'youtube|maps' は、すべてのYouTubeとGoogle Mapsのiframeを遅延読み込みします。
使用方法
制限事項
前述の通り、ページスピードを修正するための主要な解決策としてこのスクリプトを使用すべきではありません。他に行う術がなく、新しいサイトに積極的に取り組んでいる間にのみ、このような解決策は許容されます!
より技術的な言葉で言えば、このスクリプトはブラウザ(およびプリロードスキャナ)と競争するため、スクリプトが有効になる前に、どの遅い要素がすでにダウンロードのトリガーとなっているかは予測できません。
最後の手段としてのページスピード最適化スクリプト
本番環境で使用すべき縮小版はこちらです
!function(t){['prioScripts', 'prioImgs', 'lazyFrames'].forEach(e=>{t[e]=t[e]?RegExp(t[e],"i"):null});let e=new MutationObserver(e=>{e.forEach(({addedNodes:e})=>{e.forEach(e=>{if(1===e.nodeType)switch(e.tagName){case"SCRIPT":if(!t.prioScripts||!t.prioScripts.test(e.src)){let t=e.getAttribute("type");t&&"text/javascript"!==t||e.setAttribute("type","module")}break;case"IMG":console.log(e.outerHTML),t.prioImgs&&(t.prioImgs.test(e.outerHTML)||e.getAttribute("loading"))||(e.setAttribute("loading","lazy"),e.setAttribute("decoding","async"));break;case"IFRAME":t.lazyFrames.test(e.src)&&e.setAttribute("loading","lazy")}})})});/MSIE|Trident/.test(navigator.userAgent)||(e.observe(document.documentElement,{childList:!0,subtree:!0}),document.addEventListener("DOMContentLoaded",()=>{e.disconnect()}))}({prioScripts:"jquery",prioImgs:"hero",lazyFrames:"youtube|maps"}); こちらはスクリプトのより読みやすいバージョンです。これを本番環境で使用しないでください!縮小版を使用してください!
!function (cfg) {\r\n\r\n // Regexify config or nullify\r\n ['prioScripts', 'prioImgs', 'lazyFrames'].forEach((e) => {\r\n cfg[e] = cfg[e] ? new RegExp(cfg[e], "i") : null;\r\n });\r\n\r\n t0 = performance.now();\r\n\r\n /* Watch mutated nodes */\r\n const mutator = new MutationObserver((e) => {\r\n e.forEach(({ addedNodes: e }) => {\r\n e.forEach((e) => {\r\n switch (e.nodeType) {\r\n case 1:\r\n switch (e.tagName) {\r\n // defer scripts by adding type="module", excusive test on src\r\n case "SCRIPT":\r\n if (!cfg.prioScripts || !cfg.prioScripts.test(e.src)) {\r\n let type = e.getAttribute("type");\r\n if (!type || type === "text/javascript") {\r\n e.setAttribute("type", "module");\r\n }\r\n }\r\n break;\r\n\r\n // lazy load images, excusive test on outerHTML for classname, id etc etc\r\n case "IMG":\r\n console.log(e.outerHTML);\r\n if (!cfg.prioImgs || (!cfg.prioImgs.test(e.outerHTML) && !e.getAttribute("loading"))) {\r\n e.setAttribute("loading", "lazy");\r\n e.setAttribute("decoding", "async");\r\n }\r\n break;\r\n\r\n // lazy load iframes, inclusive test on src\r\n case "IFRAME":\r\n if (cfg.lazyFrames.test(e.src)) {\r\n e.setAttribute("loading", "lazy");\r\n }\r\n break;\r\n }\r\n break;\r\n }\r\n });\r\n });\r\n });\r\n\r\n\r\n // Check for IE\r\n if (!/MSIE|Trident/.test(navigator.userAgent)) {\r\n mutator.observe(document.documentElement, { childList: true, subtree: true });\r\n document.addEventListener("DOMContentLoaded", () => {\r\n mutator.disconnect();\r\n console.log("I quit after watching for " + (performance.now() - t0) + " ms");\r\n });\r\n }\r\n}({\r\n prioScripts: 'jquery',\r\n prioImgs: 'hero',\r\n lazyFrames: 'youtube|maps',\r\n});\r\n\r\n\r\n 
