Postoji mnogo načina za konfiguriranje vaše React aplikacije. Upotrijebimo pristup koji poštuje metodologiju aplikacije dvanaest faktora. To znači da provodi rekonfiguraciju tijekom izvođenja. Stoga neće biti potrebna gradnja po okruženju.

? Što želimo postići?
Želimo biti u mogućnosti da našu aplikaciju React pokrenemo kao Docker spremnik koji je napravljen jednom. Izvodi se svugdje tako što ga je moguće konfigurirati tijekom izvođenja. Rezultat bi trebao biti lagan i učinkovit spremnik koji našoj aplikaciji React služi kao statički sadržaj, što postižemo uporabom Ngnix Alpine. Naša bi aplikacija trebala omogućiti konfiguraciju unutar datoteke za sastavljanje dockera, poput ove:
version: "3.2" services: my-react-app: image: my-react-app ports: - "3000:80" environment: - "API_URL=//production.example.com"
Morali bismo biti u mogućnosti konfigurirati našu React aplikaciju pomoću -e
zastavice (varijable okruženja) kada koristimo Docker run
naredbu.
? Problem
Prije svega, mora biti jasno da u okruženju preglednika ne postoje varijable okruženja. Bilo koje rješenje koje danas koristimo nije ništa drugo do lažna apstrakcija.
Ali, onda biste mogli pitati, što je s .env
datotekama i REACT_APP
prefiksnim varijablama okruženja koje dolaze izravno iz dokumentacije? Čak i unutar izvornog koda, koriste se kao process.env
što i mi koristimo varijable okoline unutar Node.js.
U stvarnosti objekt process
ne postoji unutar okruženja preglednika, on je specifičan za Node. CRA prema zadanim postavkama ne vrši prikazivanje na strani poslužitelja. Ne može ubrizgati varijable okruženja tijekom posluživanja sadržaja (kao što to čini Next.js). Tijekom prevođenja , Webpack postupak zamjenjuje sve pojave process.env
s zadanom vrijednošću niza. To znači da se može konfigurirati samo za vrijeme gradnje .
? Riješenje
Određeni trenutak kada je još uvijek moguće ubrizgati varijable okoline događa se kad pokrenemo naš spremnik. Tada možemo čitati varijable okruženja iz unutrašnjosti spremnika. Možemo ih zapisati u datoteku koja se može poslužiti putem Nginxa (koji također služi našoj aplikaciji React). U našu aplikaciju uvoze se pomoću oznake unutar odjeljka glave
index.html
. U tom trenutku pokrećemo bash skriptu koja stvara JavaScript datoteku s varijablama okruženja dodijeljenim kao svojstva globalnog window
objekta. Ubrizgano da bude globalno dostupno u našoj aplikaciji putem preglednika.

? Vodič korak po korak
Počnimo s jednostavnim create-react-app
projektom i stvorimo .env
datoteku s našom prvom varijablom okruženja koju želimo izložiti.
# 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
Onda napišimo malu bash skriptu koja će čitati .env
datoteku i izdvajati varijable okruženja koje će biti zapisane u datoteku. Ako unutar spremnika postavite varijablu okruženja, koristit će se njezina vrijednost, inače će se vratiti na zadanu vrijednost iz .env datoteke. Stvorit će JavaScript datoteku koja vrijednosti varijabli okruženja stavlja kao objekt koji je dodijeljen kao svojstvo window
objekta.
#!/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 '%s\n' "$line" | grep -q -e '='; then varname=$(printf '%s\n' "$line" | sed -e 's/=.*//') varvalue=$(printf '%s\n' "$line" | sed -e 's/^[^=]*=//') fi # Read value of current variable if exists as Environment variable value=$(printf '%s\n' "${!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-config.js
Moramo dodati sljedeći redak elementu unutar
index.html
kojeg se zatim uvozi datoteka koju je stvorila naša bash skripta.
Prikažimo našu varijablu okruženja unutar aplikacije:
API_URL: {window._env_.API_URL}
? Razvoj
Tijekom razvoja, ako ne želimo koristiti Docker, možemo pokrenuti bash skriptu putem npm script
pokretača izmjenom 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'" },
A ako pokrenemo yarn dev
trebali bismo vidjeti izlaz poput ovog:

Postoje dva načina za rekonfiguriranje varijabli okoline unutar programa dev. Ili promijenite zadanu vrijednost u .env
datoteci ili poništite zadane postavke izvođenjem yarn dev
naredbe s unaprijed pripremljenim varijablama okoline:
API_URL=//my.new.dev.api.com yarn dev

I na kraju, uredite .gitignore
tako da iz izvornog koda izuzmemo konfiguracije okoline:
# Temporary env files /public/env-config.js env-config.js
Što se tiče razvojnog okruženja, to je to! Na pola smo puta. U ovom trenutku nismo napravili veliku razliku u odnosu na ono što je CRA standardno ponudio za razvojno okruženje. Pravi potencijal ovog pristupa blista u proizvodnji.
? Proizvodnja
Sada ćemo stvoriti minimalnu Nginx konfiguraciju kako bismo mogli stvoriti optimiziranu sliku koja služi proizvodno spremnoj aplikaciji.
# Create directory for Ngnix configuration mkdir -p conf/conf.d touch conf/conf.d/default.conf conf/conf.d/gzip.conf
Glavna konfiguracijska datoteka trebala bi izgledati otprilike ovako:
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; } }
Također je korisno omogućiti gzip kompresiju kako bi naša imovina bila lakša tijekom mrežne tranzicije:
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;
Sada kada je naša Nginx konfiguracija spremna, konačno možemo stvoriti Dockerfile i docker-compose datoteke:
touch Dockerfile docker-compose.yml
U početku koristimo node:alpine
sliku za stvaranje optimizirane proizvodne verzije naše aplikacije. Zatim na vrhu gradimo sliku vremena izvođenja 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;\""]
Sad je naš spremnik spreman. S njim možemo raditi sve standardne stvari. Možemo izgraditi spremnik, pokrenuti ga s ugrađenim konfiguracijama i gurnuti u spremište koje pružaju usluge poput Dockerhub-a.
docker build . -t kunokdev/cra-runtime-environment-variables docker run -p 3000:80 -e API_URL=//staging.api.com -t kunokdev/cra-runtime-environment-variables docker push -t kunokdev/cra-runtime-environment-variables
Gornja docker run
naredba trebala bi izlaziti tako:

Na kraju, kreirajmo našu datoteku za sastavljanje dockera. Obično ćete imati različite datoteke za sastavljanje dockera, ovisno o okruženju, a -f
zastavicom ćete odabrati koju ćete datoteku koristiti.
version: "3.2" services: cra-runtime-environment-variables: image: kunokdev/cra-runtime-environment-variables ports: - "5000:80" environment: - "API_URL=production.example.com"
A ako to učinimo docker-compose up
, trebali bismo vidjeti izlaz tako:

Sjajno! Sada smo postigli svoj cilj. Svoju aplikaciju možemo vrlo lako konfigurirati u razvojnom i proizvodnom okruženju na vrlo prikladan način. Sada konačno možemo graditi samo jednom i trčati svugdje!
Ako ste zapeli ili imate dodatnih ideja, pristupite izvornom kodu na GitHubu.
? Sljedeći koraci
Trenutna implementacija skripte ljuske ispisat će sve varijable uključene u .env datoteku. Većinu vremena ne želimo sve razotkriti. Možete primijeniti filtre za varijable koje ne želite izlagati pomoću prefiksa ili slične tehnike.
? Alternativna rješenja
As noted above, the build time configuration will satisfy most use cases. You can rely on the default approach using .env file per environment and build a container for each environment and inject values via CRA Webpack provided environment variables.
You could also have a look at this CRA GitHub repository issue which covers this problem. By now, there should be more posts and issues which cover this topic. Each offers a similar solution as above. It’s up to you to decide how are you going to implement specific details. You might use Node.js to serve your application which means that you can also replace shells script with Node.js script. Note that Nginx is more convenient to serve static content.
If you have any questions or want to offer feedback; feel free to open issue on GitHub. Optionally follow me for further posts related to web technologies.