#!/usr/bin/env python3 """ Frontend Optimization Script for MYP Platform Optimizes JavaScript and CSS files for better performance """ import os import gzip import shutil import hashlib from pathlib import Path def minify_file(content, file_type='js'): """Basic minification - removes comments and extra whitespace""" if file_type == 'js': # Remove single-line comments lines = content.split('\n') cleaned_lines = [] for line in lines: # Skip lines that are only comments stripped = line.strip() if stripped.startswith('//'): continue # Remove inline comments if '//' in line: line = line.split('//')[0].rstrip() cleaned_lines.append(line) content = '\n'.join(cleaned_lines) # Remove multi-line comments import re content = re.sub(r'/\*[\s\S]*?\*/', '', content) # Remove extra whitespace content = re.sub(r'\s+', ' ', content) content = re.sub(r'\s*([{}();,:])\s*', r'\1', content) elif file_type == 'css': # Remove CSS comments import re content = re.sub(r'/\*[\s\S]*?\*/', '', content) # Remove extra whitespace content = re.sub(r'\s+', ' ', content) content = re.sub(r'\s*([{}:;,])\s*', r'\1', content) return content.strip() def compress_file(file_path, force=False): """Compress file with gzip""" gz_path = file_path + '.gz' # Skip if already compressed and not forcing if os.path.exists(gz_path) and not force: return False with open(file_path, 'rb') as f_in: with gzip.open(gz_path, 'wb', compresslevel=9) as f_out: shutil.copyfileobj(f_in, f_out) return True def optimize_js_files(js_dir): """Optimize JavaScript files""" js_path = Path(js_dir) optimized_count = 0 for js_file in js_path.glob('*.js'): # Skip already minified files if js_file.name.endswith('.min.js'): continue min_file = js_file.with_suffix('.min.js') # Skip if minified version already exists if min_file.exists(): continue print(f"Optimizing {js_file.name}...") # Read and minify content = js_file.read_text(encoding='utf-8') minified = minify_file(content, 'js') # Write minified version min_file.write_text(minified, encoding='utf-8') # Compress both versions compress_file(str(js_file)) compress_file(str(min_file)) optimized_count += 1 return optimized_count def optimize_css_files(css_dir): """Optimize CSS files""" css_path = Path(css_dir) optimized_count = 0 for css_file in css_path.glob('*.css'): # Skip already minified files if css_file.name.endswith('.min.css'): continue min_file = css_file.with_suffix('.min.css') # Skip if minified version already exists if min_file.exists(): continue print(f"Optimizing {css_file.name}...") # Read and minify content = css_file.read_text(encoding='utf-8') minified = minify_file(content, 'css') # Write minified version min_file.write_text(minified, encoding='utf-8') # Compress both versions compress_file(str(css_file)) compress_file(str(min_file)) optimized_count += 1 return optimized_count def create_bundle_js(js_dir): """Create bundled JavaScript file with core utilities""" js_path = Path(js_dir) # Core files to bundle in order core_files = [ 'core-utilities.js', 'dark-mode.js', 'user-dropdown.js' ] bundle_content = [] for file_name in core_files: file_path = js_path / file_name if file_path.exists(): content = file_path.read_text(encoding='utf-8') bundle_content.append(f"/* === {file_name} === */\n{content}\n") if bundle_content: bundle_path = js_path / 'core-bundle.min.js' bundled = '\n'.join(bundle_content) minified = minify_file(bundled, 'js') bundle_path.write_text(minified, encoding='utf-8') compress_file(str(bundle_path)) print(f"Created core bundle: {bundle_path.name}") def main(): """Main optimization function""" base_dir = Path(__file__).parent.parent static_dir = base_dir / 'static' js_dir = static_dir / 'js' css_dir = static_dir / 'css' print("Starting frontend optimization...") # Optimize JavaScript js_count = optimize_js_files(js_dir) print(f"Optimized {js_count} JavaScript files") # Optimize CSS css_count = optimize_css_files(css_dir) print(f"Optimized {css_count} CSS files") # Create JavaScript bundle create_bundle_js(js_dir) # Compress performance-optimized.css if not already done perf_css = css_dir / 'performance-optimized.css' if perf_css.exists(): compress_file(str(perf_css), force=True) # Create minified version min_perf_css = css_dir / 'performance-optimized.min.css' if not min_perf_css.exists(): content = perf_css.read_text(encoding='utf-8') minified = minify_file(content, 'css') min_perf_css.write_text(minified, encoding='utf-8') compress_file(str(min_perf_css)) # Compress core-utilities files core_js = js_dir / 'core-utilities.js' core_css = css_dir / 'core-utilities.css' if core_js.exists(): compress_file(str(core_js), force=True) # Create minified version min_core_js = js_dir / 'core-utilities.min.js' if not min_core_js.exists(): content = core_js.read_text(encoding='utf-8') minified = minify_file(content, 'js') min_core_js.write_text(minified, encoding='utf-8') compress_file(str(min_core_js)) if core_css.exists(): compress_file(str(core_css), force=True) # Create minified version min_core_css = css_dir / 'core-utilities.min.css' if not min_core_css.exists(): content = core_css.read_text(encoding='utf-8') minified = minify_file(content, 'css') min_core_css.write_text(minified, encoding='utf-8') compress_file(str(min_core_css)) print("\nOptimization complete!") print("Remember to update templates to use minified versions in production.") if __name__ == "__main__": main()