Angular SSR Applikation in nginx mit gzip_static Kompression

Ich habe eine Angular SSR Anwendung, die mit express serverseitig gerendert wird und ├╝ber nginx ├╝ber einen reverse proxy mit proxy_pass ausgeliefert wird. Beim Build erzeuge ich f├╝r jede generierte JavaScript Datei gleichzeitig auch eine gzip Datei im gleichen Verzeichnis. Ich habe versucht f├╝r nginx die gzip_static Direktive zu aktivieren, allerdings ohne Erfolg. Die Dateien werden weiterhin ohne gzip Compression ausgeliefert:

server {
    ...
    gzip_static on;
    gzip_proxied any;
    gzip_vary on;
    gunzip on;
    gzip_types application/javascript
    ...
}

Wie kann ich gzip_static f├╝r meine Angular Anwendung verwenden?

Noch keine Stimmen abgegeben
1 Kommentar
  • Das wird wohl nicht gehen. In nginx mit proxy_pass bringt die Konfiguration f├╝r gzip_static nichts: That is, gzip_static is only expected to work when nginx is about to return regular files. It's not expected to do anything when all requests are...
    von TheSupervisor am 17 Feb. 2023
  • 26 Feb. 2023

    Die Konfiguration von Express und SSR-Angular, falls die JavaScript Dateien im Build schon gzip-t werden und sich im gleichen Verzeichnis wie die eigentliche JavaScript Datei befinden (Auszug aus server.ts ):

    export function app(): express.Express {
      const server = express();
      const distFolder = join(process.cwd(), 'dist/browser');
    
      // Hier folgt die standard-Konfiguration  von Angular + SSR, wie sie von Angular Cli automatisch erzeugt wird, ...
    
     server.get('*.js', (req, res, next) => {
        if (!existsSync(`${distFolder}${req.url}.gz`) || 
            req.headers['x-no-compression'] || 
            !req.header('Accept-Encoding').includes('gzip')) {
          return next();
        }
        req.url = `${req.url}.gz`;
        res.set({
          'Content-Type': 'text/javascript',
          'Content-Encoding': 'gzip',
          'Vary': 'Accept-Encoding',
          'Cache-Control': 'max-age=31536000'
        });
        next();
      });
    
      // ... und noch mehr Konfiguration
    
    }
    

    Eigentlich ist es relativ selbsterkl├Ąrend: Kommt ein GET Request f├╝r eine JavaScript *.js Datei, so werden erst einmal paar Bedingungen gepr├╝ft ob die Datei ausgeliefert werden kann und falls sie zutreffen, wird die Datei mit entsprechenden Headern zur├╝ckgegeben.

    • Mit existsSync(`${distFolder}${req.url}.gz` wird gepr├╝ft ob die gzip-te Datei existiert (existsSync aus dem "fs" modul).
    • ├ťber den Accept-Encoding Request-Header pr├╝fen wir, ob der Browser die gzip Compression ├╝berhaupt unterst├╝tzt (das machen aber alle modernen Browser).
    • Wir pr├╝fen noch ob der Header req.headers['x-no-compression'] gesetzt ist: x-no-compression ist zwar kein Standard-Header, der Header wird aber auch in dem express-static-gzip Projekt verwendet und es macht auch Sinn, f├╝r den Fall des Falles eine M├Âglichkeit zu haben, ├╝ber die man die Kompression ausschalten kann.

    Noch kurz zu den Response-Headern:

    • Ich denke "Content-Type" und "Content-Encoding" m├╝ssten klar sein
    • Vary mit Accept-Encoding: dieser Header weist Caching-Server und Proxys an, separate Kopien der komprimierten und unkomprimierten Versionen der JavaScript-Dateien zu speichern, basierend auf dem ÔÇ×Accept-EncodingÔÇť-Header des Clients. Dadurch wird sichergestellt, dass der Server in Abh├Ąngigkeit von den F├Ąhigkeit des Clients, den Inhalt zu dekomprimieren, die geeignete Version des Inhalts bereitstellt. Allerdings, soweit ich das verstehe, m├╝ssten wir bei Cache-Control den Flag public setzen. Sonst d├╝rfen die Dateien nicht auf Proxys/Caching-Servern gespeichert werden.
    • Hier bin ich mir nicht sicher (auch in Verbindung mit dem "Vary" Header) ob Cache-Control: max-age=31536000, immutable, public nicht besser w├Ąre: Da die generierten JS-Dateien im Namen einen Cache-Breaker (oder Cache-Buster) enthalten, sollte es kein Problem sein den Header eben auf "public" und "immutable" zu setzen.
    Noch keine Stimmen abgegeben
    Noch keine Kommentare