-4

Is there any way to stream text when my site gets CURL'd, similar to https://malted.dev/ ? I've tried using Vercel's functions, but I could not get it to return anything other than the HTML. If possible, I'd like to have it so CURL'ing my home page streams text, but opening it in a browser renders the page as usual, but if that's not possible it would just be an API.

1

1 Answer 1

0

Normally, web servers do not differentiate whether a request originates from a browser or a terminal-based client like curl or wget. However, you can check the request headers and respond accordingly. In most server environments, you can detect whether an HTTP request was made with curl by checking the User-Agent header.

By default, curl sends something like:

User-Agent: curl/<version> 

If curl does not send a unique header, you can set one manually:

curl -A "Custom-User-Agent" https://example.com 

On the server side, you would check for User-Agent or your custom header and return a different response based on that.

When streaming, chunks are sent over the wire as soon as they’re flushed. If you want a visible delay, like the effect shown on the website you mentioned, you need to introduce artificial timing using setInterval, setTimeout, or timed server-side flushing. Otherwise, true streaming works without delays; the pacing depends entirely on how you send and flush the chunks.

If you are going to use SolidJS directly, without SolidStart, you need to use Express or another server framework and render your application as a stream with the renderToStream method from the "solid-js/web" module. The rest works the same way as in SolidStart, as shown below.

Here, I’ll show you how to stream text using an artificial delay. There are multiple ways to do this; this is the most basic approach.

  1. Create new SolidStart app from a template using:
 pnpm create solid 

Follow the prompts:

◇ Project Name │ solid-streaming-text │ ◇ What type of project would you like to create? │ SolidStart │ ◇ Use Typescript? │ Yes │ ◇ Which template would you like to use? │ basic │ ◇ Project created 🎉 │ ◇ To get started, run: ──────╮ │ │ │ cd solidjs-streaming-text │ │ pnpm install │ │ pnpm dev │ │ │ ├─────────────────────────────╯ 
  1. Make sure server mode is set to stream in entry-server.tsx file:
// @refresh reload import { createHandler, StartServer } from "@solidjs/start/server"; export default createHandler(() => ( <StartServer document={({ assets, children, scripts }) => ( <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="/favicon.ico" /> {assets} </head> <body> <div id="app">{children}</div> {scripts} </body> </html> )} /> ), { mode: 'stream' }); 

The mode is set to stream by default, but we make it explicit for clarity.

  1. Replace your home component with:
import { Title } from "@solidjs/meta"; import Message from "~/components/Message"; export default function Home() { const text = ` This is a multi line text that should be streamed line by line. `.trim(); return ( <main> <Title>Stream Demo</Title> <h1>Stream Demo</h1> <Message text={text} /> </main> ); } 
  1. Create a Message component:
import { createAsync } from "@solidjs/router"; import { Suspense } from "solid-js"; export async function getMessage(text: string, delay: number): Promise<string> { "use server"; return new Promise(resolve => { setTimeout(() => resolve(text), delay); }); } export default function Message(props: { text: string }) { return props.text.split('\n').map((item, i) => { const message = createAsync(() => getMessage(item, i * 300)); return ( <Suspense> <div>{message()}</div> </Suspense> ); }) } 

The Message component splits any given text into lines and stream them one by one using a small delay in between.

This shows how to stream text line by line using an artificial delay.

Now, about accessing the headers. There are many ways to access request headers and pass them into server functions. Here’s how to do it using a middleware:

export default createMiddleware({ onRequest: (event) => { // Parse the request headers here! const { userAgent } = parseHeaders(event); if (userAgent) { // Store the value on the locals object event.locals.userAgent = userAgent; } }, }); 

We access the previously set values in a server function via getRequestEvent:

 import { getRequestEvent } from "solid-js/web"; export function getMessage() { "use server"; const event = getRequestEvent(); // Access local values event.locals.userAgent; } 

If you want to go beyond examples and really understand how SolidJS works under the hood, reactivity, routing, server functions, streaming, and full-stack patterns, my book SolidJS: The Complete Guide walks you through everything step by step. It’s designed to take you from beginner to fully confident Solid developer.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.