3

Note

Someone suggested that this is a duplicate of How to serve precompressed gzip/brotli files with .htaccess. That question seeks only to serve pre-compressed files. This question is different. Please see below.

My Goal

I want to serve pre-compressed brotli files when they exist. If no pre-compressed brotli file exists, fall back to on-the-fly gzip-compression.

Current Code

I'm working on a site that already has on-the-fly gzip enabled from its .htaccess file as follows:

<ifmodule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml...
</ifmodule>

Modified Code

I've setup a build script that compresses many static assets with brotli. In order to serve them, I've replaced the above mod_deflate block with the following:

<IfModule mod_headers.c>
    # Serve brotli compressed CSS and JS files if they exist
    # and the client accepts brotli.
    RewriteCond "%{HTTP:Accept-encoding}" "br"
    RewriteCond "%{REQUEST_FILENAME}\.br" "-s"
    RewriteRule "^(.*)\.(js|css)"              "$1\.$2\.br" [QSA]

    # Serve correct content types, and prevent double compression.
    RewriteRule "\.css\.br$" "-" [T=text/css,E=no-brotli:1]
    RewriteRule "\.js\.br$"  "-" [T=text/javascript,E=no-brotli:1]

    <FilesMatch "(\.js\.br|\.css\.br)$">
        # Serve correct encoding type.
        Header append Content-Encoding br

        # Force proxies to cache brotli &
        # non-brotli css/js files separately.
        Header append Vary Accept-Encoding
    </FilesMatch>
</IfModule>

The Problem

This serves brotli-encoded files when they exist as expected. However, the problem I face now is that, because the remaining assets are not brotli-encoded at build time, they are now served with no compression.

I've been unable to figure out how I might serve brotli with a gzip fallback that does not require me to pre-compress for gzip output.

Any help is appreciated, thank you!

jpodwys
  • 393
  • 2
  • 11
  • Does not appear to be a duplicate. The question you linked seeks to serve precompressed versions of all requested files. My question seeks to fallback to on-the-fly gzipped files when the requested file does not have a precompressed brotli equivalent. – jpodwys Sep 30 '19 at 18:19
  • @BarryPollard please re-read the question and remove the vote to close as duplicate. – jpodwys Sep 30 '19 at 18:27
  • Done. Misread the question. Any reason you don’t want to fallback to Brotli if precompressed doesn’t exist? – Barry Pollard Sep 30 '19 at 18:48
  • Thank you! brotli take much longer than gzip and I can't guarantee that the assets that are not pre-compressed are completely static, so I can't cache them after they're compressed once. It's an older system I'm taking incremental steps to improve. – jpodwys Sep 30 '19 at 19:29
  • Ok. In my experience it’s not noticeably longer by web server standards unless you are dealing with massive files or a very high volume web server. But each to their own. – Barry Pollard Sep 30 '19 at 19:35

1 Answers1

2

Your problem is you’ve replaced the dynamic gzip config with the static.

You need both bits of config in place but also to change your Brotli code to set the environment to no-gzip so it won’t fallback. The below should work;

<ifmodule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml...
</ifmodule>

<IfModule mod_headers.c>
    # Serve brotli compressed CSS and JS files if they exist
    # and the client accepts brotli.
    RewriteCond "%{HTTP:Accept-encoding}" "br"
    RewriteCond "%{REQUEST_FILENAME}\.br" "-s"
    RewriteRule "^(.*)\.(js|css)"              "$1\.$2\.br" [QSA]

    # Serve correct content types, and prevent double compression.
    RewriteRule "\.css\.br$" "-" [T=text/css,E=no-gzip:1]
    RewriteRule "\.js\.br$"  "-" [T=text/javascript,E=no-gzip:1]

    <FilesMatch "(\.js\.br|\.css\.br)$">
        # Serve correct encoding type.
        Header append Content-Encoding br

        # Force proxies to cache brotli &
        # non-brotli css/js files separately.
        Header append Vary Accept-Encoding
    </FilesMatch>
</IfModule>
Barry Pollard
  • 40,655
  • 7
  • 76
  • 92
  • Thank you! I had tried it with both code blocks present, but I wasn't aware of the `no-gzip` setting. This did the trick! – jpodwys Sep 30 '19 at 19:34