FASE 7e: CSS Inline Extraction + Minificación

- 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
This commit is contained in:
2026-04-27 08:50:19 +00:00
parent 5eab18bfa2
commit f893391916
69 changed files with 38622 additions and 19242 deletions

View File

@@ -0,0 +1,110 @@
#!/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()