Kako smo implementirali lazy učitavanje video-zapisa koristeći Cloudflare Workers
Elementor omogućava korišćenje pozadinskih video-zapisa (YouTube, Vimeo i self-hosted MP4) u sekcijama i kontejnerima, ali postoji jedan veliki problem koji se godinama ignoriše: pozadinski video-zapisi se ne lazy loaduju zaista.
Čak i kada je u Elementor podešavanjima uključena opcija za lazy load ili kada postoji placeholder slika, video se i dalje inicijalizuje odmah pri učitavanju stranice. To znači da se:
- YouTube / Vimeo API učitavaju odmah
- iframe se kreira odmah
- video konekcije se otvaraju pre nego što korisnik vidi sekciju
Rezultat su:
- loš TTFB
- veći JS execution time
- nepotrebni mrežni zahtevi
- slabiji Lighthouse i Core Web Vitals skorovi
Ovo je naročito problematično na stranicama sa više sekcija i hero background videima.
Zašto klasična rešenja ne rade
Tokom godina smo testirali gotovo sve poznate pristupe:
- JavaScript koji uklanja iframe i kasnije ga vraća
- MutationObserver hackove
- DOM manipulacije nakon
DOMContentLoaded - Plugin-based lazy load rešenja
- Elementor addone
Sva ova rešenja imaju bar jedan od sledećih problema:
- lomljenje Elementor lifecycle-a
- race condition sa Elementor frontend skriptama
- flicker efekat
- problemi pri update-u Elementora
- ne rade konzistentno za Vimeo / YouTube / MP4
Ključni problem je jednostavan:
Elementor sam kontroliše kada se video aktivira, i ako se to ne preseče na pravom mestu, nema pravog lazy load-a.
Gde je stvarni problem u Elementor-u
U Elementor core JavaScript-u postoji handler BackgroundVideo koji u metodi run() odmah poziva activate() čim su ispunjeni osnovni uslovi:
- dozvoljeno na trenutnom device-u
- background type = video
- postoji video link
Tu se dešava prerano učitavanje videa.
Drugim rečima:
Elementor nema koncept viewport-based lazy loadinga za background video.
Naše rešenje: Cloudflare Worker koji patch-uje Elementor JS
Umesto da:
- menjamo Elementor fajlove
- pravimo WordPress plugin
- ili manipulišemo DOM-om
odlučili smo da problem rešimo na ivici mreže, koristeći Cloudflare Worker.
Ideja je jednostavna, ali moćna:
- presrećemo tačno jedan Elementor JS fajl
- menjamo samo jednu metodu (
run()) - uvodimo
IntersectionObserver - aktiviramo video tek kada element uđe u viewport
Sve ostalo ostaje netaknuto.
Šta tačno patch radí
Naš Worker:
- Presreće fajl
/wp-content/plugins/elementor/assets/js/shared-frontend-handlers.*.bundle.min.js - Pronalazi originalnu
run()metodu zaBackgroundVideo - Zamenjuje je verzijom koja:
- ne poziva
activate()odmah - kreira
IntersectionObserver - čeka da se Elementor sekcija pojavi u viewport-u
- tek tada poziva originalni
activate()
- ne poziva
- Poštuje sva Elementor pravila:
- mobile / desktop settings
- play once
- privacy mode
- YouTube, Vimeo i self-hosted MP4
Šta dobijaš ovim pristupom
Pravi lazy load (ne simulacija)
Video se ne inicijalizuje uopšte dok korisnik ne dođe blizu sekcije.
Radi sa Elementor core-om
Ne oslanja se na addon-e niti na DOM hackove.
Bez lomljenja editora
Elementor editor i frontend ostaju stabilni.
Update-safe
Ako se Elementor update-uje, Worker se može:
- prilagoditi
- ili trenutno isključiti
Bez rollback-a i bez downtime-a.
Globalno rešenje
Jedan Worker važi za ceo sajt ili više sajtova.
Koji video-zapisi su obuhvaćeni
Ovo rešenje važi za Elementor core background videos, konkretno:
- YouTube background video
- Vimeo background video
- Self-hosted MP4 background video
- Section i Container background
- Desktop i mobile (prema Elementor pravilima)
Ne utiče na:
- video widgete
- popup video-zapise
- third-party addon-e
Zašto je Cloudflare Worker idealan za ovo
Cloudflare Worker omogućava:
- menjanje JavaScript-a bez dodira WordPress-a
- edge-level optimizaciju
- trenutno rollback-ovanje
- precizno targetiranje samo jednog fajla
U ovom slučaju, Worker je čistiji i sigurniji nego bilo koji WordPress plugin.
Ovo nije trik.
Ovo je strukturno ispravno rešenje.
Ako koristiš Elementor i pozadinske video-zapise, ovo je trenutno najčistiji način da ih lazy load-uješ kako treba.
Worker Kod
export default {
async fetch(request) {
const url = new URL(request.url);
// Target ONLY Elementor background video handler bundle (all versions)
const isElementorBgHandler =
/^\/wp-content\/plugins\/elementor\/assets\/js\/shared-frontend-handlers\..+\.bundle\.min\.js$/.test(
url.pathname
);
if (!isElementorBgHandler) {
return fetch(request);
}
const upstream = await fetch(request);
if (!upstream.ok) {
return upstream;
}
let js = await upstream.text();
// EXACT original minified method
const originalRun =
'run(){const e=this.getElementSettings();(e.background_play_on_mobile||"mobile"!==elementorFrontend.getCurrentDeviceMode())&&("video"===e.background_background&&e.background_video_link?this.activate():this.deactivate())}';
// Patched version with true lazy loading
const patchedRun =
'run(){const e=this.getElementSettings();' +
'if(!(e.background_play_on_mobile||"mobile"!==elementorFrontend.getCurrentDeviceMode()))return;' +
'("video"===e.background_background&&e.background_video_link)?this.__lazyBgVideoInit():this.deactivate()}' +
'__lazyBgVideoInit(){' +
'if(this.__bgVideoLazyDone||this.__bgVideoObserver)return;' +
'const e=this.$element&&this.$element[0]?this.$element[0]:null;' +
'if(!e){this.activate();this.__bgVideoLazyDone=!0;return;}' +
'const t=()=>{' +
'if(this.__bgVideoLazyDone)return;' +
'this.__bgVideoLazyDone=!0;' +
'try{this.__bgVideoObserver&&this.__bgVideoObserver.disconnect()}catch(e){}' +
'this.__bgVideoObserver=null;' +
'this.activate();' +
'};' +
'this.__bgVideoObserver=new IntersectionObserver((e)=>{' +
'for(const i of e){if(i.isIntersecting||i.intersectionRatio>0){t();break}}' +
'},{root:null,rootMargin:"300px 0px",threshold:0.01});' +
'this.__bgVideoObserver.observe(e)}';
if (js.includes(originalRun)) {
js = js.replace(originalRun, patchedRun);
}
return new Response(js, {
status: 200,
headers: {
"content-type": "application/javascript; charset=utf-8",
"cache-control": "public, max-age=3600",
"x-elementor-bg-video-lazyload": "true"
}
});
}
};



