Solide Frontends: Konfiguration

Das 12-Faktor-Anwendungsmanifest leistete einen wesentlichen Beitrag zur Entwicklung und zum Betrieb von Webanwendungen. Dies betraf jedoch hauptsächlich Backends und umging die Frontends. Die meisten Klauseln im Manifest gelten entweder nicht für Frontends oder sie werden von sich aus ausgeführt, aber bei Nummer 3 - Konfiguration - gibt es Fragen.





Das ursprüngliche Manifest lautete: "Behalten Sie die Konfiguration zur Laufzeit bei." In der Praxis bedeutet dies, dass die Konfiguration nicht im Quellcode oder im endgültigen Artefakt gespeichert werden kann. Es muss beim Start an die Anwendung übergeben werden. Diese Regel hat praktische Anwendungen, hier einige:





  1. Eine Anwendung in verschiedenen Umgebungen muss auf verschiedene Backends zugreifen. Bei der Produktion - zur Produktions-API, zum Staging - zum API-Staging und beim Ausführen von Integrationstests - zu einem speziellen Mock-Server.





  2. Für e2e-Tests muss die Wartezeit für die Reaktion des Benutzers verkürzt werden. Wenn beispielsweise nach 10 Minuten Inaktivität etwas auf der Site passiert, können Sie dieses Intervall für ein Testszenario auf eine Minute reduzieren.





SSR

Wenn die Front-End-Anwendung SSR enthält, wird die Aufgabe etwas einfacher. Die Konfiguration wird als Umgebungsvariable an die Anwendung auf dem Server übergeben. Beim Rendern wird sie als globale Variablen, <script>



die ganz am Anfang der Seite deklariert werden, an den Client gesendet . Auf dem Client reicht es aus, diese Variablen aus dem globalen Bereich zu übernehmen und zu verwenden.





Vor kurzem haben wir bei Aviasales eine Anwendung für das Server-Rendering von Teilen der Site erstellt und waren mit diesem Problem konfrontiert. Das Ergebnis ist mein Teamkollege zaopensorsil - isomorphic-env-webpack-plugin .





Die schöne Next.js erledigt dies sofort , Sie müssen nichts Besonderes tun.





CSR

, — . , , . , .





:





  1. config.js



    , . , . — -, -, — -. — PR .





  2. . DefinePlugin



    Webpack. — . — , . , , . .





.





-

- :





  1. nginx, nginx -. nginx .





  2. , — API.





— , nginx . /user-api/path



https://user.my-service.io/path



, /auth-api/path



https://auth.other-service.io/path



.





nginx Docker-





1.19 Docker- nginx . .template



/etc/nginx/templates



. , .





nginx SPA :





server {
  listen   8080;

  root /srv/www;
  index index.html;
  server_name _;

  location /user-api {
    proxy_pass ${USER_API_URL};
  }

  location /auth-api {
    proxy_pass ${AUTH_API_URL};
  }

  location / {
    try_files $uri /index.html;
  }
}
      
      



Dockerfile :





FROM node:14.15.0-alpine as build

WORKDIR /app
#   
# ...

FROM nginx:1.19-alpine

COPY ./default.conf.template /etc/nginx/templates/default.conf.template

COPY --from=build /app/public /srv/www
EXPOSE 8080
      
      



, nginx .





, , .





.





. Caddy , Traefik .





API, - .





-, . , .





JS-:





window.__ENV__ = {
  USER_API_URL: 'https://user.my-service.io/',
  AUTH_API_URL: 'https://auth.other-service.io/',
};

      
      



, . . <script>



HTML- .





nginx Docker-





, , — API, . , , env.dict



:





BACK_URL
GOOGLE_CLIENT_ID
      
      



Bash- generate_env.sh



JS-:





#!/bin/bash
filename='/etc/nginx/env.dict'

#  JS-
config_str="window._env_ = { "

#    JS-
while read line; do
variable_str="${line}: \"${!line}\""
config_str="${config_str}${variable_str}, "
done < $filename

#  JS-
config_str="${config_str} };"

#    
echo "Creating config-file with content: \"${config_str}\""
echo "${config_str}" >> /srv/www/config.env.js

#  <script>    HTML-
sed -i '/<\/body><\/html>/ i <script src="/confit.env.js"></script>' *.html
      
      



Bash, . , .





nginx , nginx. cmd.sh



, :





#!/bin/bash

bash /etc/nginx/generate_env.sh

nginx -g "daemon off;"
      
      



Dockerfile:





FROM node:14.15.0-alpine as build

WORKDIR /app
#   
# ...

FROM nginx:1.19-alpine

#    Alpine  Bash,  
RUN apk add bash

COPY ./default.conf /etc/nginx/conf.d/

COPY --from=build /app/public /srv/www

COPY ./cmd.sh /etc/nginx/cmd.sh
COPY ./generate_env.sh /etc/nginx/generate_env.sh
COPY ./env.dict /etc/nginx/env.dict
 
EXPOSE 8080

CMD ["bash", "/etc/nginx/cmd.sh"]
      
      



env.dict



.





.





, , SSR . isomorphic-env-webpack-plugin, : HTML.





In diesem Schema gibt es noch einen kleinen Randfall: Normalerweise wird den Namen von Dateien mit Ressourcen ein Inhalts-Hash hinzugefügt, sodass im Browser alle Dateien ohne Probleme für immer nach Namen zwischengespeichert werden können. In diesem Fall müssen Sie das Skript zum Generieren einer Datei mit Variablen etwas komplizieren, den Inhalt hashen und das Ergebnis dem Dateinamen hinzufügen.





Fazit

Durch korrektes Arbeiten mit den Parametern der Front-End-Anwendung können zuverlässige und benutzerfreundliche Systeme erstellt werden. Es reicht aus, die Konfiguration von der Anwendung zu entkoppeln und zur Laufzeit zu verschieben, um den Komfort der Teammitglieder radikal zu verbessern und mögliche Fehler zu reduzieren.





Wie übergeben Sie Konfigurationen an Clientanwendungen?








All Articles