1

I prepared a basic example to demonstrate what I want to achieve. Consider the html below.

<html>
<head></head>
<body>
    <header> </header>
    <div class='container'></div>
    <footer></footer>
</body>
</html>

Quite basic. All dynamic data goes under container div. Rest is static. I used service workers and the app shell model (kind of) to speed up load time. I did something like this

top-shell.html - which ends just before the container. bottom-shell.html - starts from footer. And the container itself.

<!-- top-shell.html -->
<html>
<head></head>
<body>
    <header> </header>

<!-- bottm-shell.html -->
    <footer></footer>
</body>
</html>

The container has dynamic data. So I'll have to load through a request. I tried to Stream it along with the rest. Dev.to, Google Developer articles helped quite a lot. This is the code. This snippet isn't tested

function pageStream(request) {
    const stream = new ReadableStream({
        start(controller) {
            const fetchHeader = caches.match('/top-shell.html')
            const fetchContainer = fetch('/container.html')
                .then(response => response)

            function push(stream) {
                const reader = stream.getReader();
                return reader.read().then(function process(result) {
                    if (result.done) return
                    controller.enqueue(result.value);
                    return reader.read().then(process);
                });
            }

            fetchHeader.then(response => push(response.body))
                .then(() => fetchContainer)
                .then(response => push(response.body))
                .then(() => controller.close())
        }
    });

    return new Response(stream, {
        headers: {
            'Content-Type': 'text/html; charset=utf-8'
        }
    });
}

self.addEventListener('fetch', event => {
    // Checks ... (assets excluded, only html)
    event.respondWith(pageStream(event.request));
});

I excluded some parts and the bottom-shell to post less code. It works fine.

The thing is, I don't like to divide html tags like that body. I would like to have body and html tag ended in that file. And then have a specific point where the container will be inserted while streaming. Like this

<html>
<body>
    <header></header>
    <!-- {{ container here }} -->
    <!-- {{ footer here from cache }} -->
</body>
</html>

So this file will be loaded from cache. Then the container will start streaming and inserted in {{ container here }}. I can write a simple jinja2 like template system, that will do the job. I want all these to happen inside the service worker. I don't want users to see those curly braces of course.

I reached at a point where i can decode the already streamed chunk using TextDecoder but couldn't move forward because the whole file including the container is streaming, I can't replace the curly braces completely. If I do remove it, where the next chunk will be inserted.

Pardon my mistakes. Quite confused and don't have solid understanding of certain things to approach this alone.

Btw, can anyone add the ReadableStream tag. I wonder why it's not available :/

Anna
  • 319
  • 5
  • 18

0 Answers0