denoland / fresh

The next-gen web framework.
https://fresh.deno.dev
MIT License
12.62k stars 653 forks source link

CDN for caching static assets / deprecation of `fresh/runtime` #2758

Open predaytor opened 1 week ago

predaytor commented 1 week ago

I want to cache static assets using Varnish Cache as a proxy layer (deployed to fly.io), but currently it seems that due to the nature of Fresh (2.0.0-alpha.25), assets to be marked at runtime using asset/assetSrcSet from fresh/runtime. Varnish doesn't seem to be able to cache such assets. What could be wrong?

Also, is there a plan to get rid of the fresh/runtime entirely to reduce the js bundle, as we already have a prebuild step for files in outdir at /_fresh, but no file hashes for now?

Dockerfile:

FROM denoland/deno:debian

WORKDIR /app

RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y supervisor varnish varnish-modules && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

COPY ./web .

RUN deno task build

COPY ./supervisord.conf /etc/supervisor/conf.d/supervisord.conf

ENV VARNISH_SIZE=128M
ENV VARNISH_HTTP_PORT=80
COPY ./varnish/default.vcl /etc/varnish/
COPY ./varnish/entrypoint.sh /usr/local/bin/varnish/entrypoint.sh
RUN chmod +x /usr/local/bin/varnish/entrypoint.sh

EXPOSE 80
CMD ["supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

supervisord.conf:

[supervisord]
logfile=/dev/stdout
logfile_maxbytes=0
loglevel=info
pidfile=/tmp/supervisord.pid
nodaemon=true
user=root

[unix_http_server]
file=/tmp/supervisor.sock

[program:varnish]
command=/usr/local/bin/varnish/entrypoint.sh
stdout_logfile=/dev/stdout
stderr_logfile=/dev/stderr
stdout_logfile_maxbytes = 0
stderr_logfile_maxbytes = 0

[program:app]
command=/bin/bash -c "deno run -A main.ts"
stdout_logfile=/dev/stdout
stderr_logfile=/dev/stderr
stdout_logfile_maxbytes = 0
stderr_logfile_maxbytes = 0

default.vcl:

vcl 4.1;

sub vcl_recv {
    // ...

    // Mark static files with the X-Static-File header, and remove any cookies
    if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|ogg|ogm|opus|otf|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") {
        set req.http.X-Static-File = "true";
        unset req.http.Cookie;
        return (hash);
    }

    return (hash);
}

// ...

sub vcl_backend_response {
    // ...

    // If the file is marked as static and no custom Cache-Control max-age specified, cache it for 1 year
    if (bereq.http.X-Static-File == "true" && !beresp.http.Cache-Control) {
        unset beresp.http.Set-Cookie;
        set beresp.http.Cache-Control = "public, max-age=31536000, immutable";
        set beresp.ttl = 1y;
    }

    return (deliver);
}

sub vcl_deliver {
    // Check if the object has been served from cache (HIT) or fetched from the backend (MISS)
    if (obj.hits > 0) {
        // For cached objects with a TTL of 0 seconds but still in grace mode, mark as STALE
        if (obj.ttl <= 0s && obj.grace > 0s) {
            set resp.http.X-Cache = "STALE";
        } else {
            // For regular cached objects, mark as HIT
            set resp.http.X-Cache = "HIT";
        }
    } else {
        // For uncached objects, mark as MISS
        set resp.http.X-Cache = "MISS";
    }

    // Set the X-Cache-Hits header to show the number of times the object has been served from cache
    set resp.http.X-Cache-Hits = obj.hits;
}
predaytor commented 1 week ago

And for some unknown reason, some HTML pages got caching working properly, while others have identical headers (also cache control) but always have Age: 0. Using the same Varnish configuration for all projects on Node.js - never seen such an error. 🤔