무료 최후의 수단 페이지 속도 최적화 스크립트
가장 느린 페이지도 개선할 수 있는 이 최후의 수단 방법으로 수정 불가능한 페이지의 속도를 높이세요

무료 최후의 수단 페이지 속도 최적화 스크립트
때때로 Core Web Vitals 컨설턴트로서 저는 수정 불가능한 페이지를 접하게 됩니다. 제가 수정하는 방법을 몰라서 수정 불가능한 것이 아닙니다! 아니요, 그것은 이미 교체될 예정인 사이트의 많은 부분을 다시 작성해야 하기 때문에 수정 불가능한 것입니다. 또는 WIX, HubSpot, WebFlow 등과 같이 폐쇄적인 CMS 시스템에서 볼 수 있듯이 사이트의 코드를 개선하기 위한 접근 및 제어 권한이 충분하지 않은 경우도 있습니다. 또는 마지막으로, 예산이 전혀 없는 경우입니다. 자주 발생하는 일은 아니지만 때로는 클라이언트가 수행하고 비용을 지불해야 하는 작업량을 정확하게 예측하지 못할 수도 있습니다.
2026년 3월 Arjen Karel 최종 검토
"최후의 수단 페이지 속도 최적화 스크립트" 소개
이러한 궁지에 몰렸을 때, 이 스크립트는 더 나은 것을 구축할 수 있을 때까지 페이지 속도를 조금이라도 개선하기 위한 절박한 마지막 시도입니다. 이 스크립트는 Mutation Observer를 영리하게 사용합니다. 브라우저에서 사이트의 Document Object Model이 생성될 때 스크립트가 이를 주시하고, 느린 코드를 즉시 가로채 더 빠른 코드로 교체합니다.
기능:
- 모든 렌더링 차단 스크립트를 가로채고 스크립트의 유형을 type="module".로 변경하여 지연(defer)시킵니다. 이 트릭은 모든 모듈식 스크립트가 기본적으로 지연된다는 사실을 이용합니다. 인라인 스크립트도 마찬가지입니다. 이것은 모든 페이지 스크립트를 지연시키는 가장 안전한 방법입니다.
- 이미지 지연 로딩: 모든 이미지에 loading="lazy" 및 decoding="async"가 추가됩니다. 이렇게 하면 비동기식 이미지 레이아웃 업데이트와 함께 이미지가 가시적인 뷰포트에 거의 들어올 때까지 해당 이미지의 로딩을 지연시킵니다. 주의하세요: LCP 이미지는 지연 로드하지 않는 것이 좋습니다. prioImgs 구성을 사용하여 제외하십시오. LCP 이미지 지연 로딩이 성능을 저하시키는 이유를 참조하세요.
- iframe 지연 로드. 이미지와 마찬가지로 iframe을 지연 로딩하면 더 중요한 자체 콘텐츠의 우선순위를 높일 수 있습니다!
구성
이 스크립트는 단일 "구성 객체(config object)"를 가져와 해당 구성을 사용하여 중요한 이미지와 스크립트의 지연 또는 지연 로딩을 건너뜁니다. 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을 지연 로드합니다.
사용법
제한 사항
앞서 언급했듯이 이 스크립트를 페이지 속도를 수정하기 위한 주된 솔루션으로 사용해서는 안 됩니다. 모든 방법이 실패하고 새로운 사이트를 적극적으로 작업하는 동안에만 이와 같은 솔루션을 허용할 수 있습니다!
좀 더 기술적인 측면에서 이 스크립트는 브라우저(및 프리로드 스캐너)와 경쟁하므로 스크립트가 활성화되기 전에 어떤 느린 요소가 이미 다운로드되도록 트리거되었을지 알 수 없습니다.
최후의 수단 페이지 속도 최적화 스크립트
다음은 프로덕션에서 사용해야 하는 축소(minified) 버전입니다.
!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

