Skip to content

Commit 68dc8d4

Browse files
authored
Merge pull request #960 from Codeinwp/feat/improved_scaling
Feat/improved scaling
2 parents 5df00c9 + c865ec8 commit 68dc8d4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+6614
-961
lines changed

.distignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ phpcs.xml
1717
phpunit.xml
1818
phpunit-cc.xml
1919
phpmd.xml
20+
jest.config.js
21+
jest.setup.js
2022
package.json
2123
package-lock.json
2224
composer.json
@@ -31,6 +33,8 @@ tests
3133
dist
3234
artifact
3335
assets/src
36+
assets/js/modules/__tests__
37+
coverage
3438
.wporg
3539
.nvmrc
3640
.github
Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: ESLint
1+
name: JavaScript Tests
22

33
on:
44
pull_request:
@@ -9,21 +9,36 @@ on:
99
concurrency:
1010
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }}
1111
cancel-in-progress: true
12+
1213
jobs:
13-
run:
14-
if: github.event.pull_request.draft == false
14+
test:
15+
if: github.event_name == 'push' || github.event.pull_request.draft == false
1516
runs-on: ubuntu-latest
16-
name: ESLint
17+
name: ESLint & Jest Tests
1718
steps:
18-
- uses: actions/checkout@master
19+
- uses: actions/checkout@v3
1920
with:
2021
persist-credentials: false
22+
2123
- name: Setup Node
22-
uses: actions/setup-node@v1
24+
uses: actions/setup-node@v3
2325
with:
2426
node-version: 18
25-
- name: Lint js files
27+
cache: 'npm'
28+
29+
- name: Install dependencies
2630
run: |
27-
npm install -g npm
2831
npm ci
32+
33+
- name: Run ESLint
34+
run: |
2935
npm run lint
36+
37+
- name: Run unit tests
38+
run: |
39+
npm test
40+
41+
- name: Run tests with coverage
42+
run: |
43+
npm run test:coverage
44+

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ build
1111
cc-test-reporter
1212
assets/build
1313
test-results
14-
tests/assets/filestash
14+
tests/assets/filestash
15+
coverage

assets/js/modules/AGENTS.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Optimole JavaScript Modules - Agent Instructions
2+
3+
4+
## Code standards
5+
- **CRITICAL**: All functions must have JSDoc comments with `@param` and `@return` annotations
6+
- Use ES6 modules with `import`/`export` syntax
7+
- Follow camelCase naming for functions and variables
8+
- Use `const`/`let` instead of `var`
9+
- Always handle errors gracefully with try/catch blocks
10+
- Use descriptive variable names and avoid abbreviations
11+
12+
## Testing instructions
13+
- Use only unit tests
14+

assets/js/modules/README.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Optimole JavaScript Modules
2+
3+
This directory contains the modular JavaScript components for the Optimole image optimizer.
4+
5+
## Module Structure
6+
7+
### Core Modules
8+
9+
#### `logger.js`
10+
- **Purpose**: Centralized logging functionality with debug mode support
11+
- **Exports**: `optmlLogger` object
12+
- **Key Features**:
13+
- Debug mode detection via URL params or localStorage
14+
- Structured logging with prefixes
15+
- Table logging support
16+
- Conditional logging based on debug state
17+
18+
#### `storage.js`
19+
- **Purpose**: Session storage management for tracking processed pages
20+
- **Exports**: `optmlStorage` object
21+
- **Key Features**:
22+
- Generate unique storage keys for URL/device combinations
23+
- Check if page/device combinations have been processed
24+
- Mark combinations as processed with timestamps
25+
- Error handling for storage operations
26+
27+
#### `device.js`
28+
- **Purpose**: Device type detection based on screen width
29+
- **Exports**: `optmlDevice` object
30+
- **Key Features**:
31+
- Mobile/desktop detection using 600px breakpoint
32+
- Device type constants (MOBILE: 1, DESKTOP: 2)
33+
- Helper methods for device type checking
34+
- PageSpeed Insights compatible detection logic
35+
36+
#### `api.js`
37+
- **Purpose**: REST API communication with fallback mechanisms
38+
- **Exports**: `optmlApi` object
39+
- **Key Features**:
40+
- Primary sendBeacon API for reliable data transmission
41+
- Fetch API fallback for when sendBeacon fails
42+
- Automatic storage marking on successful sends
43+
- Error handling and logging
44+
45+
#### `dom-utils.js`
46+
- **Purpose**: DOM manipulation and utility functions
47+
- **Exports**: `optmlDomUtils` object
48+
- **Key Features**:
49+
- Debounce utility for performance optimization
50+
- Unique CSS selector generation for elements
51+
- Background image detection and URL extraction
52+
- Page condition checking (viewport, visibility, load state)
53+
- Promise-based waiting utilities
54+
55+
### Specialized Modules
56+
57+
#### `background.js`
58+
- **Purpose**: Background image handling and lazy loading observation
59+
- **Exports**: `optmlBackground` object
60+
- **Key Features**:
61+
- Background image lazy loading detection
62+
- Mutation observer setup for class changes
63+
- URL extraction from background images
64+
- Selector processing and element observation
65+
66+
#### `lcp.js`
67+
- **Purpose**: Largest Contentful Paint (LCP) element detection
68+
- **Exports**: `optmlLcp` object
69+
- **Key Features**:
70+
- Performance Observer integration
71+
- LCP element identification and processing
72+
- Support for both image and background image LCP elements
73+
- Timeout handling for LCP detection
74+
75+
#### `image-detector.js`
76+
- **Purpose**: Image detection and dimension analysis
77+
- **Exports**: `optmlImageDetector` object
78+
- **Key Features**:
79+
- Missing dimension detection for images
80+
- Intersection Observer setup for above-fold detection
81+
- Optimole image observation (`data-opt-id` attributes)
82+
- Cleanup utilities for temporary attributes
83+
84+
#### `srcset-detector.js`
85+
- **Purpose**: Srcset analysis and missing variation detection for eligible images
86+
- **Exports**: `optmlSrcsetDetector` object
87+
- **Key Features**:
88+
- Smart image detection with improved skip logic:
89+
- Includes images without `data-opt-src` (non-lazyload images)
90+
- Includes images with `data-opt-src` AND `data-opt-lazy-loaded` (completed lazyload)
91+
- Skips images with only `data-opt-src` (pending lazyload)
92+
- **Aspect ratio detection for cropping requirements**:
93+
- Compares natural vs. displayed aspect ratios to determine if cropping is needed
94+
- Uses intelligent thresholds: 5% tolerance, 15% significant difference, 10% ratio change
95+
- Prevents unnecessary cropping when aspect ratios match
96+
- Returns separate crop status data as `imageId: cropStatus` mapping
97+
- Calculates required srcset variations using comprehensive size ranges:
98+
- Mobile range: 200w-500w (50w steps) for dense mobile coverage
99+
- Tablet range: 500w-800w (100w steps) for tablet devices
100+
- Desktop range: 800w-1200w (200w steps) for desktop screens
101+
- High-res range: 1200w-1600w (200w steps) with strategic 2x DPR
102+
- Configurable generation settings:
103+
- `widthStepSize`: Step size for width variations (default: 100px)
104+
- `minSize`: Minimum image size to consider (default: 200px)
105+
- `maxVariations`: Maximum srcset variations per image (default: 8)
106+
- `sizeTolerance`: Tolerance for existing sizes (default: 50px)
107+
- Analyzes existing srcset attributes to identify missing sizes
108+
- **Ultra-compact API payload**: Sends only essential fields with short names (w, h, d, s, b)
109+
- **Separate crop status**: Returns crop requirements as `imageId: cropStatus` mapping instead of per-srcset flags
110+
- **Full logging**: Complete analysis data available in console logs for debugging
111+
- Smart selection from dense size grid for optimal responsive coverage
112+
113+
#### `main.js`
114+
- **Purpose**: Main orchestrator coordinating all functionality
115+
- **Exports**: `optmlMain` object
116+
- **Key Features**:
117+
- Complete above-the-fold detection workflow
118+
- Module coordination and data aggregation
119+
- API data preparation and submission with separate crop status
120+
- Error handling and condition checking
121+
122+
## Data Structure
123+
124+
### API Payload Structure
125+
The main module sends data to the REST API with the following structure:
126+
127+
```javascript
128+
{
129+
d: deviceType, // Device type (1=mobile, 2=desktop)
130+
a: aboveTheFoldImages, // Array of above-fold image IDs
131+
b: backgroundSelectors, // Background image selectors
132+
u: url, // Page URL
133+
t: timestamp, // Request timestamp
134+
h: hmac, // Security hash
135+
l: lcpData, // LCP (Largest Contentful Paint) data
136+
m: missingDimensions, // Missing dimension data
137+
s: srcsetData, // Srcset variations data
138+
c: cropStatusData // Crop status mapping (imageId -> boolean)
139+
}
140+
```
141+
142+
### Srcset Data Structure
143+
Individual srcset entries contain:
144+
```javascript
145+
{
146+
w: width, // Image width
147+
h: height, // Image height
148+
d: dpr, // Device pixel ratio
149+
s: descriptor, // Srcset descriptor (e.g., "300w")
150+
b: breakpoint // CSS breakpoint
151+
}
152+
```
153+
154+
### Crop Status Data Structure
155+
Crop requirements are stored separately:
156+
```javascript
157+
{
158+
882936320: true, // Image ID -> requires cropping
159+
123456789: false // Image ID -> no cropping needed
160+
}
161+
```
162+

0 commit comments

Comments
 (0)