PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / 4.2.6
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization v4.2.6
4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 2.5.5 2.5.6 2.5.7 3.0.0 3.0.1 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.11.0 3.11.1 3.11.2 3.11.3 3.12.0 3.12.1 All 134 releases
optimole-wp / assets / js / modules / main.js

main.js in Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization 4.2.6, at assets/js/modules/main.js

245 lines 10.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Optimole Main Module
3 * Main orchestrator that coordinates all image detection functionality
4 */
5
6 import { optmlLogger } from './logger.js';
7 import { optmlStorage } from './storage.js';
8 import { optmlDevice } from './device.js';
9 import { optmlApi } from './api.js';
10 import { optmlDomUtils } from './dom-utils.js';
11 import { optmlBackground } from './background.js';
12 import { optmlLcp } from './lcp.js';
13 import { optmlImageDetector } from './image-detector.js';
14 import { optmlSrcsetDetector } from './srcset-detector.js';
15
16 /**
17 * Main detection functionality
18 */
19 export const optmlMain = {
20 /**
21 * Run the page profiling process to detect images, background selectors, and LCP element
22 * @returns {Promise<Object|null>} Detection results or null
23 */
24 runProfiling: async function() {
25 // Check for zero-dimension viewports and hidden pages
26 const pageConditions = optmlDomUtils.checkPageConditions();
27
28 if (!pageConditions.hasValidViewport) {
29 optmlLogger.info('Window must have non-zero dimensions for image detection.');
30 return null;
31 }
32
33 if (!pageConditions.isVisible) {
34 optmlLogger.info('Page opened in background tab so image detection is not performed.');
35 return null;
36 }
37
38 // Use object destructuring for repeated property access
39 const { pageProfileId, missingDevices, bgSelectors } = window.optimoleDataOptimizer || {};
40 const deviceType = optmlDevice.getDeviceType();
41 const url = pageProfileId;
42 const missingDevicesArray = missingDevices ? missingDevices.split(',') : [];
43
44 optmlLogger.info('Device Type:', deviceType);
45 optmlLogger.info('Missing Devices:', missingDevicesArray);
46 optmlLogger.info('Profile ID:', pageProfileId);
47 optmlLogger.info('Background Selectors:', bgSelectors || 'None provided');
48
49 // Check if this device type is needed
50 if (!missingDevicesArray.includes(deviceType.toString())) {
51 optmlLogger.info('Skipping device type, data already exists:', deviceType);
52 return null;
53 }
54
55 // Check if we've already processed this device/URL combination
56 if (optmlStorage.isProcessed(url, deviceType)) {
57 optmlLogger.info('Skipping detection, already processed this device/URL combination');
58 return null;
59 }
60
61 // Check if user is at the top of the page
62 const isAtTopOfPage = window.pageYOffset === 0 || document.documentElement.scrollTop === 0;
63 if (!isAtTopOfPage) {
64 optmlLogger.info('User is not at the top of the page, skipping image detection');
65 return null;
66 }
67
68 // Wait until the resources on the page have fully loaded
69 if (!pageConditions.isComplete && window.optmlDomUtils) {
70 optmlLogger.info('Waiting for page to fully load...');
71 await optmlDomUtils.waitForPageLoad();
72 optmlLogger.info('Page fully loaded, proceeding with detection');
73 }
74
75 // Wait for images in viewport to load
76 optmlLogger.info('Waiting for viewport images to load...');
77 await optmlDomUtils.waitForViewportImages(1500); // 1.5 second delay for images
78 optmlLogger.info('Viewport images loaded, proceeding with detection');
79
80 // Wait for browser idle time to run detection
81 await optmlDomUtils.waitForIdleTime();
82
83 // Detect LCP element
84 const lcpData = await optmlLcp.detectLcpElement();
85
86 // Track page visibility and window resize
87 let isPageVisible = document.visibilityState !== 'hidden';
88 let didWindowResize = false;
89
90 // Set up debounced resize handler
91 const resizeHandler = optmlDomUtils.debounce(() => {
92 didWindowResize = true;
93 optmlLogger.info('Window resized during detection, results may be affected');
94 }, 100);
95
96 // Set up visibility change handler
97 const visibilityChangeHandler = () => {
98 isPageVisible = document.visibilityState !== 'hidden';
99 optmlLogger.info('Page visibility changed:', isPageVisible ? 'visible' : 'hidden');
100 };
101
102 // Add event listeners with passive option for better performance
103 window.addEventListener('resize', resizeHandler, { passive: true });
104 document.addEventListener('visibilitychange', visibilityChangeHandler);
105
106 // Use IntersectionObserver instead of getBoundingClientRect for better performance
107 const aboveTheFoldImages = [];
108
109 // Create intersection observer
110 let selectorMap = new Map();
111 const observer = optmlImageDetector.createIntersectionObserver(aboveTheFoldImages, selectorMap);
112
113 // Observe Optimole images
114 const { allOptimoleImages } = optmlImageDetector.observeOptimoleImages(observer);
115
116 // Detect images with missing dimensions
117 const imageDimensionsData = optmlImageDetector.detectImageDimensions(allOptimoleImages);
118
119 optmlLogger.info('Images with missing dimensions found:', Object.keys(imageDimensionsData).length);
120
121 // Detect images requiring srcset variations (non-lazyload images)
122 const srcsetResult = await optmlSrcsetDetector.detectMissingSrcsets();
123 const srcsetData = srcsetResult.srcset;
124 const cropStatusData = srcsetResult.crop;
125
126 optmlLogger.info('Images requiring srcset variations found:', Object.keys(srcsetData).length);
127 optmlLogger.info('Images with crop status found:', Object.keys(cropStatusData).length);
128
129 // Process background image selectors if available
130 let bgImageUrls = new Map();
131 let pendingElements = 0;
132
133 if (bgSelectors && Array.isArray(bgSelectors) && bgSelectors.length > 0) {
134 const backgroundResult = optmlBackground.processBackgroundSelectors(bgSelectors, observer);
135 selectorMap = backgroundResult.selectorMap;
136 pendingElements = backgroundResult.pendingElements;
137
138 // Extract background image URLs
139 bgImageUrls = optmlBackground.extractBackgroundImageUrls(bgSelectors);
140
141 // Adjust wait time based on whether we have pending elements
142 const waitTime = pendingElements > 0 ? 600 : 300;
143 optmlLogger.info(`Waiting ${waitTime}ms for ${pendingElements} pending background elements`);
144 await new Promise(resolve => setTimeout(resolve, waitTime));
145 } else {
146 // Standard wait time if no background selectors
147 await new Promise(resolve => setTimeout(resolve, 300));
148 }
149
150 // Disconnect observer and clean up event listeners
151 observer.disconnect();
152 window.removeEventListener('resize', resizeHandler);
153 document.removeEventListener('visibilitychange', visibilityChangeHandler);
154
155 // Clean up temporary attributes
156 optmlImageDetector.cleanupBackgroundElements();
157
158 // Check conditions that might affect accuracy
159 if (didWindowResize) {
160 optmlLogger.warn('Window was resized during detection, results may not be accurate');
161 }
162
163 if (!isPageVisible) {
164 optmlLogger.warn('Page became hidden during detection, results may not be accurate');
165 }
166
167 // Log results
168 optmlLogger.info('Above the fold images with data-opt-id:', aboveTheFoldImages);
169 optmlLogger.info('Background selectors:', selectorMap);
170
171 // Prepare and send data if we found any images, background selectors, dimension data, or srcset data
172 if (aboveTheFoldImages.length > 0 || selectorMap.size > 0 || lcpData.imageId || lcpData.bgSelector || Object.keys(imageDimensionsData).length > 0 || Object.keys(srcsetData).length > 0) {
173 // Convert the Map to a plain object for the API
174 const processedBgSelectors = this._processBackgroundSelectors(selectorMap, bgImageUrls);
175
176 // Prepare the data object with LCP information using shorter key names
177 const data = {
178 d: deviceType,
179 a: aboveTheFoldImages,
180 b: processedBgSelectors,
181 u: url,
182 t: window.optimoleDataOptimizer ? window.optimoleDataOptimizer._t : null,
183 h: window.optimoleDataOptimizer ? window.optimoleDataOptimizer.hmac : null,
184 pu: window.optimoleDataOptimizer ? window.optimoleDataOptimizer.pageProfileUrl : null,
185 l: {
186 i: lcpData.imageId,
187 s: lcpData.bgSelector,
188 u: lcpData.bgUrls
189 },
190 m: imageDimensionsData, // m for missing dimensions
191 s: srcsetData, // s for srcset data
192 c: cropStatusData // c for crop status data
193 };
194
195 optmlLogger.info('Sending data with LCP information:', {
196 lcpImageId: lcpData.imageId,
197 lcpBgSelector: lcpData.bgSelector,
198 lcpBgUrls: lcpData.bgUrls
199 });
200 optmlLogger.info('Sending background selectors:', processedBgSelectors);
201 optmlLogger.info('Sending dimension data for images:', imageDimensionsData);
202 optmlLogger.info('Sending srcset data for images:', srcsetData);
203 optmlLogger.info('Sending crop status data for images:', cropStatusData);
204
205 optmlApi.sendToRestApi(data);
206 return data;
207 } else {
208 optmlLogger.info('No above-the-fold images, background elements, LCP elements, dimension data, or srcset data found');
209 return null;
210 }
211 },
212
213 /**
214 * Process background selectors for API submission
215 * @private
216 * @param {Map} selectorMap - Map of selectors to above-fold elements
217 * @param {Map} bgImageUrls - Map of background image URLs
218 * @returns {Object} Processed background selectors object
219 */
220 _processBackgroundSelectors: function(selectorMap, bgImageUrls) {
221 const processedBgSelectors = {};
222
223 // Process each selector that's present on the page
224 selectorMap.forEach((specificSelectors, baseSelector) => {
225 // Initialize the object for this base selector
226 processedBgSelectors[baseSelector] = {};
227
228 // For each specific selector, add its URLs if available
229 specificSelectors.forEach(specificSelector => {
230 // First, add the selector to indicate it's above the fold
231 processedBgSelectors[baseSelector][specificSelector] = null;
232
233 // Then, if we have URLs for this selector, add them
234 if (bgImageUrls.has(baseSelector) &&
235 bgImageUrls.get(baseSelector).has(specificSelector)) {
236 processedBgSelectors[baseSelector][specificSelector] =
237 bgImageUrls.get(baseSelector).get(specificSelector);
238 }
239 });
240 });
241
242 return processedBgSelectors;
243 }
244 };
245