- Extraído CSS inline de 15 templates POS + 13 templates Dashboard - CSS movido a archivos .css externos en pos/static/css/ y dashboard/ - Generados .min.css vía minify-assets.sh - Nginx auto-serve transparente para .min.css - Tests: 73/73 pasando - Script: scripts/extract-inline-css.py
111 lines
3.3 KiB
Python
111 lines
3.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Extract inline <style> blocks from HTML templates into external CSS files.
|
|
|
|
Replaces each <style>...</style> block with a <link rel="stylesheet"> tag.
|
|
This allows browsers to cache CSS across page navigations and dramatically
|
|
reduces HTML payload size.
|
|
|
|
Usage:
|
|
python3 extract-inline-css.py
|
|
"""
|
|
|
|
import glob
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
def extract_css_from_template(html_path, css_output_dir, css_url_prefix):
|
|
"""Extract <style> blocks from an HTML file into an external CSS file.
|
|
|
|
Returns the modified HTML content.
|
|
"""
|
|
with open(html_path, 'r', encoding='utf-8') as f:
|
|
html = f.read()
|
|
|
|
style_blocks = list(re.finditer(
|
|
r'<style[^>]*>(.*?)</style>',
|
|
html,
|
|
re.DOTALL | re.IGNORECASE
|
|
))
|
|
|
|
if not style_blocks:
|
|
return html # No inline CSS to extract
|
|
|
|
# Extract all CSS content
|
|
css_parts = []
|
|
for m in style_blocks:
|
|
css = m.group(1).strip()
|
|
if css:
|
|
css_parts.append(css)
|
|
|
|
if not css_parts:
|
|
return html
|
|
|
|
# Write external CSS file
|
|
name = Path(html_path).stem
|
|
css_filename = f"{name}.css"
|
|
css_path = Path(css_output_dir) / css_filename
|
|
css_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
combined_css = '\n\n'.join(css_parts)
|
|
with open(css_path, 'w', encoding='utf-8') as f:
|
|
f.write(f"/* Extracted from {Path(html_path).name} */\n\n")
|
|
f.write(combined_css)
|
|
f.write('\n')
|
|
|
|
# Replace first <style> block with <link>, remove the rest
|
|
link_tag = f'<link rel="stylesheet" href="{css_url_prefix}{css_filename}">'
|
|
new_html = html[:style_blocks[0].start()] + link_tag + html[style_blocks[0].end():]
|
|
|
|
# Remove remaining style blocks (they were concatenated into the CSS file)
|
|
for m in reversed(style_blocks[1:]):
|
|
new_html = new_html[:m.start()] + new_html[m.end():]
|
|
|
|
return new_html
|
|
|
|
|
|
def process_directory(html_dir, css_output_dir, css_url_prefix):
|
|
"""Process all HTML files in a directory."""
|
|
templates = sorted(glob.glob(f"{html_dir}/*.html"))
|
|
total_saved = 0
|
|
|
|
for html_path in templates:
|
|
new_html = extract_css_from_template(html_path, css_output_dir, css_url_prefix)
|
|
|
|
# Write back the modified HTML
|
|
with open(html_path, 'w', encoding='utf-8') as f:
|
|
f.write(new_html)
|
|
|
|
original_size = Path(html_path).stat().st_size
|
|
total_saved += original_size - len(new_html.encode('utf-8'))
|
|
name = Path(html_path).name
|
|
print(f" {name}: extracted CSS -> {css_url_prefix}{Path(html_path).stem}.css")
|
|
|
|
return total_saved
|
|
|
|
|
|
def main():
|
|
print("=== Extracting inline CSS from POS templates ===")
|
|
saved_pos = process_directory(
|
|
'/home/Autopartes/pos/templates',
|
|
'/home/Autopartes/pos/static/css',
|
|
'/pos/static/css/'
|
|
)
|
|
|
|
print("\n=== Extracting inline CSS from Dashboard templates ===")
|
|
saved_dash = process_directory(
|
|
'/home/Autopartes/dashboard',
|
|
'/home/Autopartes/dashboard',
|
|
'' # Dashboard CSS is in the same directory
|
|
)
|
|
|
|
total_saved_kb = (saved_pos + saved_dash) / 1024
|
|
print(f"\n=== Done ===")
|
|
print(f"Total HTML payload reduced by ~{total_saved_kb:.0f} KB")
|
|
print(f"POS templates: ~{saved_pos/1024:.0f} KB")
|
|
print(f"Dashboard templates: ~{saved_dash/1024:.0f} KB")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|