de Krunoslav Banovac
Conţinut
Cum se implementează variabile de mediu de rulare cu create-react-app, Docker și Nginx
Există multe modalități de a vă configura aplicația React. Să folosim o abordare care să respecte Metodologia aplicației cu 12 factori. Aceasta înseamnă că aplică reconfigurarea în timpul rulării. Prin urmare, nu ar fi necesară nicio construcție pe mediu.
? Ce vrem să realizăm?
Vrem să putem rula aplicația noastră React ca un container Docker care este construit o singură dată. Funcționează peste tot, fiind configurabil în timpul rulării. Rezultatul ar trebui să fie un container ușor și performant care servește aplicației noastre React ca conținut static, pe care îl realizăm utilizând Ngnix Alpine. Aplicația noastră ar trebui să permită configurarea în fișierul docker-compose, cum ar fi acesta:
version: "3.2"
services:
my-react-app:
image: my-react-app
ports:
- "3000:80"
environment:
- "API_URL=https://production.example.com"
Ar trebui să putem configura aplicația noastră React folosind -e
semnalizator (variabile de mediu) atunci când se utilizează Docker run
comanda.
La prima vedere, această abordare poate părea să aducă un beneficiu prea mic pentru munca suplimentară necesară pentru configurarea inițială. Dar odată ce configurarea este realizată, configurațiile și implementarea specifice mediului vor fi mult mai ușor de gestionat. Deci, pentru oricine vizează medii dinamice sau utilizează sisteme de orchestrație, această abordare este cu siguranță ceva de luat în considerare.
? Problema
În primul rând, trebuie să fie clar că nu există variabile de mediu în mediul browserului. Orice soluție pe care o folosim în zilele noastre nu este altceva decât o abstractizare falsă.
Dar, atunci s-ar putea să întrebați, ce zici de .env
fișiere și REACT_APP
variabile de mediu prefixate care vin direct din documentație? Chiar și în interiorul codului sursă, acestea sunt utilizate ca process.env
la fel cum folosim variabile de mediu în interiorul Node.js.
În realitate, obiectul process
nu există în mediul browserului, este specific nodului. În mod implicit, CRA nu face redarea de pe server. Nu poate injecta variabile de mediu în timpul difuzării conținutului (cum ar fi Next.js face). În timpul transpilării, Procesul Webpack înlocuiește toate aparițiile process.env
cu o valoare șir care a fost dată. Asta înseamnă poate fi configurat numai în timpul construirii.
? Soluţie
Momentul specific în care este încă posibil să injectăm variabile de mediu se întâmplă atunci când pornim containerul nostru. Apoi putem citi variabilele de mediu din interiorul containerului. Le putem scrie într-un fișier care poate fi difuzat prin Nginx (care servește și aplicația noastră React). Acestea sunt importate în aplicația noastră folosind <script>
etichetați în secțiunea cap a index.html
. Deci, în acel moment, rulăm un script bash care creează un fișier JavaScript cu variabile de mediu atribuite ca proprietăți ale globalului window
obiect. Injectat pentru a fi disponibil la nivel global în aplicația noastră în modul browser.
? Ghid pas cu pas
Să începem cu un simplu create-react-app
proiectează și creează .env
fișier cu prima noastră variabilă de mediu pe care dorim să o expunem.
# Generate React App
create-react-app cra-runtime-environment-variables
cd cra-runtime-environment-variables
# Create default environment variables that we want to use
touch .env
echo "API_URL=https//default.dev.api.com" >> .env
Apoi, să scriem un mic script bash care va citi.env
fișier și extrageți variabilele de mediu care vor fi scrise în fișier. Dacă setați o variabilă de mediu în interiorul containerului, valoarea acesteia va fi utilizată, în caz contrar, va reveni la valoarea implicită din fișierul .env. Acesta va crea un fișier JavaScript care pune valorile variabilei de mediu ca obiect care este atribuit ca proprietate a window
obiect.
#!/bin/bash
# Recreate config file
rm -rf ./env-config.js
touch ./env-config.js
# Add assignment
echo "window._env_ = {" >> ./env-config.js
# Read each line in .env file
# Each line represents key=value pairs
while read -r line || [[ -n "$line" ]];
do
# Split env variables by character `=`
if printf '%sn' "$line" | grep -q -e '='; then
varname=$(printf '%sn' "$line" | sed -e 's/=.*//')
varvalue=$(printf '%sn' "$line" | sed -e 's/^[^=]*=//')
fi
# Read value of current variable if exists as Environment variable
value=$(printf '%sn' "${!varname}")
# Otherwise use value from .env file
[[ -z $value ]] && value=${varvalue}
# Append configuration property to JS file
echo " $varname: "$value"," >> ./env-config.js
done < .env
echo "}" >> ./env-config.js
Trebuie să adăugăm următoarea linie la <head>
element din interior index.html
care apoi importă fișierul creat de scriptul nostru bash.
<script src="https://www.freecodecamp.org/news/how-to-implement-runtime-environment-variables-with-create-react-app-docker-and-nginx-7f9d42a91d70/%PUBLIC_URL%/env-config.js"></script>
Să afișăm variabila de mediu în cadrul aplicației:
<p>API_URL: {window._env_.API_URL}</p>
? Dezvoltare
În timpul dezvoltării, dacă nu dorim să folosim Docker, putem rula script bash prin npm script
alergător prin modificarea package.json
:
"scripts": {
"dev": "chmod +x ./env.sh && ./env.sh && cp env-config.js ./public/ && react-scripts start",
"test": "react-scripts test",
"eject": "react-scripts eject",
"build": "react-scripts build'"
},
Și dacă alergăm yarn dev
ar trebui să vedem ieșiri astfel:
Există două moduri de a reconfigura variabilele de mediu în cadrul dev. Fie modificați valoarea implicită din interior .env
fișier sau suprascrieți valorile implicite rulând yarn dev
comanda cu variabile de mediu preconizate:
API_URL=https://my.new.dev.api.com yarn dev
Și, în cele din urmă, editați .gitignore
astfel încât să excludem configurațiile de mediu din codul sursă:
# Temporary env files
/public/env-config.js
env-config.js
În ceea ce privește mediul de dezvoltare, atât! Suntem la jumătatea drumului. Nu am făcut o diferență uriașă în acest moment în comparație cu ceea ce CRA a oferit în mod implicit pentru mediul de dezvoltare. Adevăratul potențial al acestei abordări strălucește în producție.
? Producție
Acum vom crea o configurație minimă Nginx, astfel încât să putem construi o imagine optimizată care să servească aplicația pregătită pentru producție.
# Create directory for Ngnix configuration
mkdir -p conf/conf.d
touch conf/conf.d/default.conf conf/conf.d/gzip.conf
Fișierul principal de configurare ar trebui să arate oarecum astfel:
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
expires -1; # Set it to different value depending on your standard requirements
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
De asemenea, este util să activați compresia gzip, astfel încât activele noastre să fie mai ușoare în timpul tranziției în rețea:
gzip on;
gzip_http_version 1.0;
gzip_comp_level 5; # 1-9
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
# MIME-types
gzip_types
application/atom+xml
application/javascript
application/json
application/rss+xml
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/svg+xml
image/x-icon
text/css
text/plain
text/x-component;
Acum, când configurația noastră Nginx este gata, putem crea în cele din urmă fișiere Dockerfile și docker-compose:
touch Dockerfile docker-compose.yml
Inițial, folosim node:alpine
imagine pentru a crea o construcție de producție optimizată a aplicației noastre. Apoi, construim o imagine de execuție deasupra nginx:alpine
.
# => Build container
FROM node:alpine as builder
WORKDIR /app
COPY package.json .
COPY yarn.lock .
RUN yarn
COPY . .
RUN yarn build
# => Run container
FROM nginx:1.15.2-alpine
# Nginx config
RUN rm -rf /etc/nginx/conf.d
COPY conf /etc/nginx
# Static build
COPY --from=builder /app/build /usr/share/nginx/html/
# Default port exposure
EXPOSE 80
# Copy .env file and shell script to container
WORKDIR /usr/share/nginx/html
COPY ./env.sh .
COPY .env .
# Add bash
RUN apk add --no-cache bash
# Make our shell script executable
RUN chmod +x env.sh
# Start Nginx server
CMD ["/bin/bash", "-c", "/usr/share/nginx/html/env.sh && nginx -g "daemon off;""]
Acum containerul nostru este gata. Putem face toate lucrurile standard cu el. Putem construi un container, îl putem rula cu configurații inline și îl putem împinge către un depozit furnizat de servicii precum Dockerhub.
docker build . -t kunokdev/cra-runtime-environment-variables
docker run -p 3000:80 -e API_URL=https://staging.api.com -t kunokdev/cra-runtime-environment-variables
docker push -t kunokdev/cra-runtime-environment-variables
De mai sus docker run
comanda ar trebui să producă aplicația astfel:
În sfârșit, haideți să creăm fișierul nostru de compunere docker. De obicei, veți avea diferite fișiere docker-compose în funcție de mediu și le veți utiliza -f
pavilion pentru a selecta ce fișier să utilizați.
version: "3.2"
services:
cra-runtime-environment-variables:
image: kunokdev/cra-runtime-environment-variables
ports:
- "5000:80"
environment:
- "API_URL=production.example.com"
Și dacă o facem docker-compose up
ar trebui să vedem rezultate astfel:
Grozav! Acum ne-am atins obiectivul. Ne putem reconfigura aplicația cu ușurință atât în mediile de dezvoltare, cât și în cele de producție într-un mod foarte convenabil. Acum putem construi în sfârșit o singură dată și alergăm peste tot!
Dacă v-ați blocat sau aveți idei suplimentare, accesați cod sursă pe GitHub.
? Pasii urmatori
Implementarea curentă a scriptului shell va imprima toate variabilele incluse în fișierul .env. De cele mai multe ori nu vrem să le expunem pe toate. Puteți implementa filtre pentru variabilele pe care nu doriți să le expuneți folosind prefixe sau o tehnică similară.
? Soluții alternative
După cum sa menționat mai sus, configurația timpului de construcție va satisface majoritatea cazurilor de utilizare. Vă puteți baza pe abordarea implicită folosind fișierul .env per mediu și să creați un container pentru fiecare mediu și să injectați valori prin variabilele de mediu furnizate de CRA Webpack.
Ai putea, de asemenea, să arunci o privire la asta Problema depozitului CRA GitHub care acoperă această problemă. Până acum, ar trebui să existe mai multe postări și probleme care să acopere acest subiect. Fiecare oferă o soluție similară cu cea de mai sus. Depinde de dvs. să decideți cum veți implementa detalii specifice. S-ar putea să utilizați Node.js pentru a vă difuza aplicația, ceea ce înseamnă că puteți înlocui, de asemenea, scriptul shell cu scriptul Node.js. Rețineți că Nginx este mai convenabil pentru a difuza conținut static.
Dacă aveți întrebări sau doriți să oferiți feedback; nu ezitați să deschideți numărul pe GitHub. Opțional, urmați-mă pentru alte postări legate de tehnologiile web.
#Cum #implementează #variabile #mediu #execuție #createreactapp #Docker #și #Nginx
Cum se implementează variabile de mediu de execuție cu create-react-app, Docker și Nginx