#!/usr/bin/env python3
import os
import asyncio
from pathlib import Path
from playwright.async_api import async_playwright
# Simple configuration
CONFIG = {
"input_file": os.path.join(os.path.dirname(__file__), "templates", "listpage.js"), # React component file
"output_pdf": "book-page.pdf", # Output PDF filename
"temp_html": "temp-render.html", # Temporary HTML file
"wait_time": 1500, # Time to wait for rendering (ms)
"device_scale": 2, # Resolution multiplier
"debug": True # Keep temp files for debugging
}
async def create_html_file():
"""Create a temporary HTML file that loads the React component from a file."""
try:
# Check if input file exists
input_path = Path(CONFIG["input_file"])
if not input_path.exists():
print(f"Error: Input file '{input_path}' not found")
return False
# Read the component file
with open(input_path, 'r', encoding='utf-8') as f:
component_code = f.read()
# Create HTML that will load our component
html_content = """
Book Page Template
"""
with open(CONFIG["temp_html"], 'w', encoding='utf-8') as f:
f.write(html_content)
print(f"Created HTML file: {CONFIG['temp_html']}")
print(f"Using React component from: {CONFIG['input_file']}")
return True
except Exception as e:
print(f"Error creating HTML file: {e}")
print(f"Exception details: {str(e)}")
import traceback
traceback.print_exc()
return False
async def render_to_pdf():
"""Render the React component to PDF using Playwright."""
try:
# Create the HTML file first
html_created = await create_html_file()
if not html_created:
print("Failed to create HTML file")
return
print("Launching browser...")
async with async_playwright() as p:
# Launch the browser with more debugging options
browser = await p.chromium.launch(
headless=True, # True for production, False for debugging
)
# Create a new page for letter size paper
page = await browser.new_page(
viewport={"width": 816, "height": 1056}, # 8.5in x 11in at 96dpi
device_scale_factor=CONFIG["device_scale"]
)
# Get absolute path to HTML file
html_path = Path(CONFIG["temp_html"]).absolute()
html_uri = f"file://{html_path}"
print(f"Navigating to: {html_uri}")
# Add event listeners for console messages and errors
page.on("console", lambda msg: print(f"Browser console: {msg.text}"))
page.on("pageerror", lambda err: print(f"Browser page error: {err}"))
# Navigate with longer timeout and wait for network idle
await page.goto(html_uri, wait_until="networkidle", timeout=30000)
# Wait for React to render
await page.wait_for_timeout(CONFIG["wait_time"])
# Add a check to ensure the component rendered
element_count = await page.evaluate("""() => {
const root = document.getElementById('root');
return root.childElementCount;
}""")
if element_count == 0:
print("Warning: No elements found in root. Component may not have rendered.")
else:
print(f"Found {element_count} elements in root. Component rendered successfully.")
# Save debug screenshot
if CONFIG["debug"]:
await page.screenshot(path="debug-screenshot.png")
print("Debug screenshot saved")
# Generate PDF
print("Generating PDF...")
await page.pdf(
path=CONFIG["output_pdf"],
format="Letter",
print_background=True,
margin={"top": "0", "right": "0", "bottom": "0", "left": "0"}
)
print(f"PDF generated successfully: {CONFIG['output_pdf']}")
# Close the browser
await browser.close()
# Cleanup temp files if not in debug mode
if not CONFIG["debug"] and Path(CONFIG["temp_html"]).exists():
Path(CONFIG["temp_html"]).unlink()
print("Temporary HTML file removed")
except Exception as e:
print(f"Error generating PDF: {e}")
if __name__ == "__main__":
# Run the async function
try:
asyncio.run(render_to_pdf())
except Exception as e:
print(f"Fatal error: {e}")
import traceback
traceback.print_exc()