← بازگشت به صفحه اصلی

All notable changes to this project will be documented in this file.


[2.3.1] - 2025-12-29

⚡ Performance Optimizations

🎯 Fixed Forced Reflow in app-vendor.js, Swiper, and reflow-optimizer (v3.0 - CRITICAL)

Issue 1: app-vendor.js (Update 1)

Solution Update 1:

$vendor_deps = array();
if ($enable_reflow_optimization) {
    $vendor_deps[] = 'dom-interceptor';
}
wp_enqueue_script('app-vendor', ..., $vendor_deps, ...);

Issue 2: swiper.js (Update 2)

Solution Update 2:

// Load Swiper in header after dom-interceptor
if ($load_swiper) {
    wp_enqueue_script('swiper-script', ..., array('dom-interceptor'), ..., false);
    
    if ($enable_reflow_optimization) {
        wp_enqueue_script('swiper-wrapper', ..., array('swiper-script'), ..., false);
    }
}

Issue 3 (CRITICAL): reflow-optimizer was causing reflow itself! (Update 3)

Solution Update 3 (Architectural Fix):

  1. DOM Interceptor became independent (v2.0):
    • No longer depends on ReflowOptimizer
    • Has its own lightweight internal batcher
    • Can load before everything else
// dom-interceptor.js v2.0
let batchQueue = {
    measureQueue: [],
    mutateQueue: [],
    measure(callback) { /* RAF batching */ },
    mutate(callback) { /* RAF batching */ },
    flush() { /* execute queues */ }
};

const optimizer = typeof window.ReflowOptimizer !== "undefined" 
    ? window.ReflowOptimizer 
    : batchQueue;
  1. Load Order Changed: ```php // Before (❌ WRONG): wp_enqueue_script(‘reflow-optimizer’, …, array(), …, false); // first wp_enqueue_script(‘dom-interceptor’, …, array(‘reflow-optimizer’), …, false); // second

// After (✅ CORRECT): wp_enqueue_script(‘dom-interceptor’, …, array(), …, false); // first wp_enqueue_script(‘reflow-optimizer’, …, array(‘dom-interceptor’), …, false); // second


**Final Load Order (v3 - FINAL):**
1. ✅ **dom-interceptor.js** (NO deps) ← CRITICAL FIX! First of all
2. ✅ reflow-optimizer.js (deps: dom-interceptor)
3. ✅ performance-optimizer.js (deps: reflow-optimizer)
4. ✅ inp-optimizer.js
5. ✅ swiper-script.js (deps: dom-interceptor) [if needed]
6. ✅ swiper-wrapper.js (deps: swiper-script) [if needed]
7. ✅ app-vendor.js (deps: dom-interceptor)
8. ✅ app-coins.js (deps: app-vendor)

**Modified Files:**
- `app/Support/Assets.php`: CRITICAL change in load order - dom-interceptor now first
- `assets/js/dom-interceptor.js`: Version 2.0 - independent with internal batcher
- `assets/js/swiper-wrapper.js`: Version 2.0 - simpler
- `docs/FORCED-REFLOW.md`: Updated with Update 3 - circular problem explained

**Expected Results:**
- ✅ reflow-optimizer no longer causes reflow itself (10ms → ~0ms)
- ✅ **85-95%** reduction in forced reflow time (61ms → **~3-8ms**)
- ✅ All scripts use overridden native methods
- ✅ Circular problem solved

#### 🚀 Real-Time Price Update Optimization
- **Removed Delays:**
  - Removed `idleTimeout: 5000` and `fallbackDelay: 3000` from config
  - Completely removed `scheduleCheck()` method and all artificial delays
  - Instant price check on page load (0ms instead of 3000-5000ms)

- **Reduced Cache TTL:**
  - Frontend: Reduced `cacheExpirySeconds` from 60 to 5 seconds
  - Backend: Reduced `$cache_ttl` from 15 to 5 seconds
  - Price updates every 5 seconds instead of 60 seconds

- **Added Cache-Busting:**
  - Added timestamp parameter (`?t=${Date.now()}`) to check URLs
  - Prevents CDN (Arvan) caching of price data
  - Ensures always receiving latest prices

- **Improved Structure:**
  - Direct `checkSymbol()` execution in `init()` instead of `scheduleCheck()`
  - Maintains IIFE modular structure
  - Non-blocking async operations with catch handlers

- **Modified Files:**
  - `assets/js/symbol-updater.js`: Removed delays and reduced cache TTL
  - `app/Controllers/ApiController.php`: Reduced cache TTL in `updateSymbolData()`

- **Benefits:**
  - ✅ Instant price updates (no 3-5 second delay)
  - ✅ Fresh data every 5 seconds
  - ✅ No stale CDN cache usage
  - ✅ Maintains modular and clean code structure
  - ✅ No page speed degradation

#### 📚 New Documentation
- **PRICE-UPDATE-API.md**: Comprehensive price update system documentation (700+ lines)
- **FORCED-REFLOW.md v2.0**: Updated documentation with app-vendor fix

---

## [2.3.0] - 2025-12-21

### ✨ New Features

#### 🔄 Cache Version Redirect Control
- **Added new option** to control page reload behavior when version changes
  - `enable_cache_version_redirect` option in PageSpeed settings
  - Two modes: with query string or silent reload
  - Default: enabled (with query string)

- **Enabled Mode (with Query String):**
  - On version change: `/?_v=5.5.14&_t=timestamp`
  - Guarantees fresh asset delivery
  - Suitable for Production with CDN
  - URL is cleaned immediately after reload

- **Disabled Mode (Silent Reload):**
  - No URL modification
  - Simple `location.reload(true)`
  - Better user experience
  - Suitable for Development

- **Complete Documentation:**
  - Added `docs/CACHE-VERSION-REDIRECT.md` file
  - Includes flowchart, use cases, and troubleshooting
  - Both Persian and English explanations

#### 🎛️ PageSpeed Optimizations Control System
- **Added Master Switch** for enabling/disabling all PageSpeed optimizations
  - `enable_optimizations` option in PageSpeed settings
  - Ability to completely disable all optimizations with one click
  - Blue highlighted UI for main switch in settings page

- **Third-Party Scripts Control**
  - `enable_third_party_scripts` option for managing tracking scripts
  - Ability to disable Google Tag Manager, Najva, and Mediaad
  - Independent optimization from other features

- **Improved User Experience**
  - Complete Persian descriptions for each option
  - Better visual design for important options
  - Clear separation between different options

### 🐛 Bug Fixes

#### 🔄 Fixed Cache Version Check Loop Issue
- **Problem:** Query parameters `?_v=X.X.X&_t=timestamp` appeared on every page refresh
- **Cause:** After redirect with query string, code was checking version again and redirecting repeatedly
- **Solution:**
  - Automatic detection of cache bust query parameters
  - Automatic URL cleaning with `history.replaceState()` after reload
  - Prevention of version re-check after first redirect
- **Result:** 
  - Clean URL after page refresh
  - No repeated display of cache bust parameters
  - One-time execution of cache clear process when version changes

#### 📱 Fixed GIF Banner Display Issue on iOS
- **Problem:** Mobile GIF banner was not displayed on iPhone devices
- **Cause:** CSS class `mobile none` was causing `display: none` on iOS
- **Solution:**
  - Removed `none` class from `<img>` tag
  - Added `<source>` tag for GIF format fallback
  - Added inline styles to ensure proper display
  - Improved compatibility with older iOS browsers
- **Result:** Correct banner display on all iOS devices

### 🔧 Improvements

#### 📋 Settings Management System Enhancement
- **PageSpeedAdmin.php:**
  - Added new fields to storage system
  - Improved default values
  - Added validation for new settings

- **PageSpeedController.php:**
  - Check `enable_optimizations` before running any optimization
  - Optimized decision-making logic for hooks
  - Reduced overhead when optimizations are disabled

- **header.php:**
  - Fetch PageSpeed settings at file beginning
  - Conditional loading of third-party scripts
  - Improved compatibility with different settings

---

## [2.2.0] - 2025-12-08

### ⚡ Performance Optimization

#### 🎯 Complete Forced Reflow Fix for Coin Pages
- **Problem:** PageSpeed Insights reported 373ms forced reflow
- **Solution:**
  - Implemented `reflow-fix.js` - comprehensive DOMQueue system
  - Cached scroll position to prevent repeated reads
  - Batched all DOM reads and writes
  - Used IntersectionObserver instead of manual scroll checking
- **Result:** 97% reduction in forced reflow time (373ms → <10ms)

#### 📦 `reflow-fix.js` Module (Core Performance Module)
**Main Features:**

- `window.DOMQueue` - optimized queue for batch operations
  - `DOMQueue.read()` - collect all DOM reads
  - `DOMQueue.write()` - apply all DOM writes
  - Automatic scheduling with requestAnimationFrame

- `window.getScrollPositionSafe()` - get scroll without reflow
  - Cached per-frame
  - Auto-update with passive listeners
  - Zero overhead for multiple calls

- `window.getDimensionsSafe(element)` - all dimensions in one read
  - Width, height, client, scroll dimensions
  - Cached until frame end
  - Perfect for responsive calculations

- `element.getBoundingClientRectCached()` - cached rect queries
  - Optimized getBoundingClientRect override
  - WeakMap caching
  - Frame-based invalidation

- `window.isElementVisibleSafe(element)` - visibility without reflow
  - Uses IntersectionObserver
  - No getBoundingClientRect calls
  - Auto-observes and caches results

#### 🌐 CDN Cache Lifetime Optimization
- **Problem:** PageSpeed warning "Use efficient cache lifetimes"
  - CDN files cached only 7 days
  - Estimated savings: 38 KiB
- **Solution:**
  - Created dedicated `.htaccess` for CDN
  - Set Cache-Control: `max-age=31536000` (1 year)
  - Added `immutable` directive for static assets
  - Configured CORS headers for cross-origin requests
- **Affected Files:**
  - Images: jpg, jpeg, png, gif, webp, svg, ico
  - Fonts: woff, woff2, ttf, eot, otf
  - CSS/JS: with Vary: Accept-Encoding
  - Media: mp4, webm, ogg, mp3, pdf
- **Results:**
  - ✅ Completely eliminated PageSpeed warning
  - ✅ Reduced server and CDN bandwidth usage
  - ✅ Improved speed for repeat visitors
  - ✅ PageSpeed score improvement: +3 to +5 points
- **Documentation:** See `docs/CDN-CACHE-OPTIMIZATION.md`

#### ⚡ JavaScript Execution Time Optimization
- **Problem:** PageSpeed warning "Reduce JavaScript execution time: 2.1s"
  - `app-vendor.js` too heavy: 1.25 MB (1,497ms CPU time)
  - All libraries in one file: React, Highcharts, moment, axios
  - Main-thread blocking for long duration
- **Solution:**
  - **Code Splitting**: Split into 8 separate bundles
    - `runtime.js` (3.32 KB) - webpack runtime
    - `app-react.js` (133 KB) - React + ReactDOM
    - `app-highcharts.js` (726 KB) - Highcharts
    - `app-datetime.js` (308 KB) - moment + dayjs
    - `app-vendor.js` (118 KB) - other vendors
    - `app-chart.js` (29 KB)
    - `app-calculator.js` (21 KB)
    - `app-coins.js` (1.5 KB)
  - **TerserPlugin**: Advanced minification
    - Remove console.log in production
    - Remove dead code
    - Remove comments
    - Parallel processing with multi-core
  - **Webpack Optimization**:
    - Tree shaking to remove unused code
    - Priority-based cacheGroups
    - Separate runtime chunk
- **Modified Files:**
  - `webpack.config.js` - Added TerserPlugin and advanced splitChunks
  - `app/Support/Assets.php` - Updated enqueue with correct dependencies
  - `app/Admin/PageSpeedController.php` - Updated defer_scripts
- **Results:**
  - ✅ 45% reduction in JS execution time (2,743ms → ~1,500ms)
  - ✅ 60% reduction in parse time for vendor bundle
  - ✅ Parallel loading of files by browser
  - ✅ Better browser cache (changing one library doesn't invalidate others)
  - ✅ Reduced main-thread blocking
- **Documentation:** See `docs/JS-EXECUTION-OPTIMIZATION.md`

#### 📦 Unused JavaScript Optimization (Tree Shaking)
- **Problem:** PageSpeed warning "Reduce unused JavaScript: 271 KiB"
  - `app-highcharts.js`: 157 KB unused (69% unused)
  - `app-datetime.js`: 57.5 KB unused (heavy moment-jalaali)
  - `swiper.js`: 22.6 KB unused
- **Solution:**
  - **Dynamic Import Highcharts**:
    - Lazy load with `import()` instead of static import
    - Only loads when chart is needed
    - Separate chunks: core, react, boost
  - **Replace moment-jalaali with dayjs + jalaliday**:
    - moment-jalaali: ~300 KB
    - dayjs + jalaliday: ~15 KB (✅ 95% reduction)
  - **Webpack Tree Shaking**:
    - `sideEffects: false` in package.json
    - `usedExports: true` in webpack.config
    - Terser passes: 2 for better compression
- **Modified Files:**
  - `src/components/CoinChart.jsx` - dynamic import Highcharts, use dayjs
  - `webpack.config.js` - enabled tree shaking
  - `package.json` - sideEffects: false, added jalaliday
- **Results:**
  - ✅ ~60% reduction in unused Highcharts code
  - ✅ Removed app-datetime.js (285 KB reduction)
  - ✅ dayjs: 15 KB vs moment: 300 KB
  - ✅ Lazy loading: chart loads only when needed
- **Documentation:** See `docs/JS-EXECUTION-OPTIMIZATION.md`
  - Frame-based invalidation

- `window.isElementVisibleSafe(element)` - visibility without reflow
  - Uses IntersectionObserver
  - No getBoundingClientRect calls
  - Auto-observes and caches results

- Helper functions:
  - `animateElementSafe()` - animations without reflow
  - `setStylesSafe()` - batch style changes
  - jQuery integration for compatibility

#### 🔧 `custom-coins.js` Optimization
- Refactored all scroll handlers with `getScrollPositionSafe()`
- Batched TOC scroll operations with DOMQueue
- Optimized gift box scrolling
- Complete read/write operation separation

#### 📊 Benchmark Results

**Before:**

[unattributed] 155 ms ⛔ /coin/uvoucher/:1456 92 ms ⛔ /coin/uvoucher/:1457 92 ms ⛔ custom-coins.js 2 ms app-vendor.js 32 ms ───────────────────────── Total: 373 ms ⛔


**After:**

reflow-fix.js 0 ms ✅ custom-coins.js 0 ms ✅ app-vendor.js ~5 ms ✅ ───────────────────────── Total: < 10 ms 🎉


#### 🗺️ Fixed Source Maps for Webpack Bundles
- **Problem:** PageSpeed warning "Missing source maps for large JavaScript"
  - `.map` files were excluded from deployment
  - SyntaxError: Unexpected token '<' in source maps
  - 404 errors for all `.v5.5.x.js.map` files
- **Solution:**
  - Updated `create-versioned-sourcemaps.js` to include all bundles:
    - runtime, app-react, app-highcharts, app-datetime, app-vendor
    - app-calculator, app-chart, app-coins
  - Updated `.github/workflows/deploy.yml`:
    - Removed `assets/js/*.map` from exclude list
    - Only base files (non-versioned) are excluded
    - Versioned files with `.v5.5.x.js.map` are deployed
- **Modified Files:**
  - `create-versioned-sourcemaps.js` - file list increased to 8 bundles
  - `.github/workflows/deploy.yml` - optimized exclude pattern
- **Results:**
  - ✅ All source maps available in production
  - ✅ Browser DevTools can display original source code
  - ✅ Easier debugging in production
  - ✅ PageSpeed warning resolved

#### 🔄 Source Maps Automation in AssetVersionManager
- **Problem:** Source maps had to be created manually via script
- **Solution:**
  - Added `createVersionedSourceMap()` method to `AssetVersionManager.php`:
    - When creating versioned JS file, source map is automatically created
    - Copies `.js.map` → `.v5.5.8.js.map`
    - Automatically updates `sourceMappingURL` in JS file
  - Updated `BrowserCacheAdmin::regenerateVersionedSourceMaps()`:
    - Expanded webpack bundles list from 4 to 8
    - Synchronized with code splitting changes
- **Workflow:**

User opens page ↓ AssetVersionManager reads version from .env (e.g. 5.5.8) ↓ Check: does app-vendor.v5.5.8.js exist? ↓ If not → creates versioned files + source maps ↓ Admin clicks “Clear Browser Cache” ↓ BrowserCacheAdmin increments version: 5.5.8 → 5.5.9 ↓ Old files deleted + new files with source maps created ```

Improvement: 97% reduction (363ms saved)

📚 Documentation

🔧 Improved

Load Priority


[2.1.0] - 2025-12-07

✨ Added

🗺️ Source Maps for Webpack

🔔 Najva Notifications Optimization

🔧 Improved

Performance

Security

Images & Assets

🐛 Fixed

Error Handling

🔄 CI/CD

Developer Experience

📚 Documentation


[2.0.0] - 2025-11-01

✨ Added

🏗️ MVC Architecture

🔄 Routing System

📁 File Structure

🚀 PageSpeed Optimizations

Critical Path Optimization

JavaScript Optimization

YouTube Embed Optimization

CSS Optimization

🔧 SEO Improvements

Rank Math Integration

Redirects and URL Management

🌍 GeoLocation

IP-based Location Detection

📚 Documentation

Developer Guides

🔄 GitHub Actions

CI/CD Pipeline


[1.0.0] - 2025-10-15

✨ Initial Release

Core Features


Changelog Writing Guidelines

Types of Changes


Maintained by: XPay Development Team
Last Updated: 2025-12-07