Fronteras sólidas: configuración

El manifiesto de aplicación de 12 factores hizo una contribución significativa al desarrollo y operación de aplicaciones web, pero esto afectó principalmente a los backends y pasó por alto los front-end. La mayoría de las cláusulas del manifiesto no son aplicables a las interfaces o se realizan por sí mismas, pero con el número 3 ( configuración ) hay preguntas.





El manifiesto original decía: "Mantenga la configuración en tiempo de ejecución". En la práctica, esto significa que la configuración no se puede almacenar dentro del código fuente o el artefacto final. Debe pasar a la aplicación en el momento del inicio. Esta regla tiene aplicaciones prácticas, aquí hay un par:





  1. Una aplicación en diferentes entornos debe acceder a diferentes backends. De producción a API de producción, de prueba a prueba de API y al ejecutar pruebas de integración a un servidor simulado especial.





  2. Para las pruebas e2e, es necesario reducir el tiempo de espera para la reacción del usuario. Por ejemplo, si algo sucede en el sitio después de 10 minutos de inactividad, entonces para un escenario de prueba puede reducir este intervalo a un minuto.





SSR

Si la aplicación de front-end contiene SSR, la tarea se vuelve un poco más sencilla. La configuración se pasa como variables de entorno a la aplicación en el servidor; cuando se procesa, entra en la respuesta al cliente como variables globales declaradas al <script>



principio de la página. En el cliente, es suficiente recoger estas variables del alcance global y usarlas.





Recientemente, en Aviasales, creamos una aplicación para renderizar partes del sitio en el servidor y nos enfrentamos a este problema. El resultado es mi compañero de equipo zaopensorsil - isomorphic -env-webpack-plugin .





El hermoso Next.js hace esto de inmediato , no es necesario que haga nada especial.





RSE

, — . , , . , .





:





  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.





Hay un caso de borde más pequeño en este esquema: generalmente se agrega un hash de contenido a los nombres de los archivos con recursos, de modo que en el navegador todos los archivos se pueden almacenar en caché para siempre por nombre sin ningún problema. En este caso, debe complicar un poco el script para generar un archivo con variables, aplicar un hash al contenido y agregar el resultado al nombre del archivo.





Conclusión

El trabajo correcto con los parámetros de la aplicación front-end ayuda a crear sistemas confiables y fáciles de usar. Basta con desacoplar la configuración de la aplicación y pasarla al tiempo de ejecución para mejorar radicalmente la comodidad de los miembros del equipo y reducir los posibles errores.





¿Cómo se pasan las configuraciones a las aplicaciones cliente?








All Articles