Skip to main content

Streaming File Download

A page that streams a large CSV file from the backend to the browser line by line, without loading the entire file into memory. Uses <script type="module"> for top-level for await...of.

from abstra.pages import register_function

@register_function
def stream_csv():
with open("large_report.csv") as f:
for line in f:
yield line.strip()

@register_function
def __render__():
return """
<script src="https://cdn.tailwindcss.com"></script>
<style>body { margin:0; font-family:'Inter',system-ui,sans-serif; background:#f8fafc; }</style>
<div class="min-h-screen p-8 max-w-4xl mx-auto">
<div class="flex items-center justify-between mb-6">
<h1 class="text-2xl font-bold text-slate-800">Report Viewer</h1>
<button id="btn"
class="bg-indigo-600 hover:bg-indigo-700 text-white text-sm font-medium px-5 py-2.5 rounded-lg transition-all">
Load Report
</button>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
<div class="px-6 py-3 border-b border-slate-100 flex items-center justify-between">
<span class="text-sm text-slate-400">Rows: <span id="count" class="font-mono text-slate-600">0</span></span>
</div>
<pre id="output" class="p-6 text-xs font-mono text-slate-600 max-h-[70vh] overflow-auto whitespace-pre"></pre>
</div>
</div>
<script type="module">
const btn = document.getElementById('btn');
const output = document.getElementById('output');
const count = document.getElementById('count');

btn.addEventListener('click', async () => {
btn.disabled = true; btn.textContent = 'Loading...';
output.textContent = '';
let rows = 0;
for await (const line of stream_csv()) {
output.textContent += line + '\\n';
count.textContent = ++rows;
}
btn.disabled = false; btn.textContent = 'Load Report';
});
</script>
"""

Key patterns: Generator reads file line by line (constant memory), <script type="module"> for top-level await, for await...of appends to DOM incrementally, live row counter.