Ajonaikaisten ympäristömuuttujien toteuttaminen create-reagoi-sovelluksen, Dockerin ja Nginxin avulla

React-sovellusta voi määrittää monella tapaa. Käytetään lähestymistapaa, joka kunnioittaa kahdentoista tekijän sovelluksen metodologiaa. Tämä tarkoittaa, että se suorittaa uudelleenkonfiguroinnin ajon aikana. Siksi rakennusta ei tarvita ympäristöä kohti.

? Mitä haluamme saavuttaa?

Haluamme pystyä käyttämään React-sovellustamme kerran rakennettuna Docker-säilönä. Se toimii kaikkialla olemalla konfiguroitavissa ajon aikana. Tuloksen tulisi olla kevyt ja suorituskykyinen säiliö, joka palvelee React-sovellustamme staattisena sisällönä, jonka saavutamme käyttämällä Ngnix Alpine -tuotetta. Sovelluksemme pitäisi sallia määritykset docker-compose-tiedostossa, kuten tämä:

version: "3.2" services: my-react-app: image: my-react-app ports: - "3000:80" environment: - "API_URL=//production.example.com"

Meidän pitäisi pystyä määrittämään React-sovelluksemme käyttämällä -elippua (ympäristömuuttujia) Docker runkomentoa käytettäessä.

Ensi silmäyksellä tämä lähestymistapa saattaa näyttää tuottavan liian vähän hyötyä ylimääräisestä työstä, jota se tarvitsee alkuasetuksiin. Mutta kun asennus on valmis, ympäristökohtaiset kokoonpanot ja käyttöönotto ovat huomattavasti helpompia käsitellä. Joten kaikille, jotka kohdistavat dynaamisiin ympäristöihin tai käyttävät orkesterijärjestelmiä, tämä lähestymistapa on ehdottomasti harkittavaa.

? Ongelma

Ensinnäkin on oltava selvää, että selainympäristössä ei ole ympäristömuuttujia. Kumpi ratkaisu, jota nykyään käytämme, on vain väärennetty abstraktio.

Mutta sitten saatat kysyä, entä .envtiedostot ja REACT_APPetuliitetyt ympäristömuuttujat, jotka tulevat suoraan dokumentaatiosta? Jopa lähdekoodin sisällä näitä käytetään process.envaivan kuten käytämme ympäristömuuttujia Node.js: n sisällä.

Todellisuudessa objektia processei ole selainympäristössä, se on solmukohtainen. CRA ei oletusarvoisesti tee palvelinpuolen hahmonnusta. Se ei voi pistää ympäristömuuttujia sisällön tarjoamisen aikana (kuten Next.js tekee). Tulkinnan aikana Webpack-prosessi korvaa kaikki esiintymät process.envmerkkijonolla, joka annettiin. Tämä tarkoittaa, että se voidaan määrittää vain rakennusajan aikana .

? Ratkaisu

Erityinen hetki, jolloin ympäristömuuttujia on vielä mahdollista syöttää, tapahtuu, kun käynnistämme kontin. Sitten voimme lukea ympäristömuuttujia säiliön sisältä. Voimme kirjoittaa ne tiedostoon, joka voidaan näyttää Nginxin kautta (joka palvelee myös React-sovellustamme). Ne tuodaan sovellukseemme käyttämällä otsikkoa index.html. Joten sillä hetkellä suoritamme bash-komentosarjan, joka luo JavaScript-tiedoston, jossa ympäristömuuttujat on määritetty globaalin windowobjektin ominaisuuksiksi . Injisoituna olevan maailmanlaajuisesti saatavilla sovelluksessamme selaimen tavalla.

? Vaiheittainen opas

Aloitetaan yksinkertaisella create-react-appprojektilla ja luodaan .envtiedosto ensimmäisellä ympäristömuuttujalla, jonka haluamme paljastaa.

# 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

.envKirjoitetaan sitten pieni bash-komentosarja, joka lukee tiedoston ja purkaa tiedostoon kirjoitettavat ympäristömuuttujat. Jos asetat ympäristömuuttujan säilöön, sen arvoa käytetään, muuten se laskee takaisin .env-tiedoston oletusarvoksi. Se luo JavaScript-tiedoston, joka asettaa ympäristömuuttujien arvot objektiksi, joka on määritetty windowobjektin ominaisuudeksi.

#!/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

Meidän on lisättävä seuraava rivi elementtiin, index.htmljoka sitten tuo bash-komentosarjamme luoman tiedoston.

Näytetään ympäristömuuttujamme sovelluksessa:

API_URL: {window._env_.API_URL}

? Kehitys

Jos emme halua käyttää Dockeria kehityksen aikana, voimme suorittaa bash-komentosarjan npm scriptjuoksijan kautta muuttamalla 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'" },

Ja jos suoritamme, yarn devmeidän pitäisi nähdä tällainen tulos:

Dev-ympäristössä on kaksi tapaa määrittää ympäristömuuttujat uudelleen. Joko muuta oletusarvoa .envtiedoston sisällä tai ohita oletukset suorittamalla yarn devkomento valmiiksi asetetuilla ympäristömuuttujilla:

API_URL=//my.new.dev.api.com yarn dev

Lopuksi muokkaa .gitignoreniin, että ympäristöasetukset jätetään pois lähdekoodista:

# Temporary env files /public/env-config.js env-config.js

Kehitysympäristön osalta se on! Olemme puolivälissä. Emme ole tehneet tässä vaiheessa suurta eroa verrattuna siihen, mitä luottoluokituslaitokset oletusarvoisesti tarjosivat kehitysympäristölle. Tämän lähestymistavan todellinen potentiaali loistaa tuotannossa.

? Tuotanto

Nyt aiomme luoda minimaalisen Nginx-kokoonpanon, jotta voimme rakentaa optimoidun kuvan, joka palvelee tuotantovalmiita sovelluksia.

# Create directory for Ngnix configuration mkdir -p conf/conf.d touch conf/conf.d/default.conf conf/conf.d/gzip.conf

Pääkokoonpanotiedoston tulisi näyttää tältä:

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; } }

On myös hyödyllistä ottaa gzip-pakkaus käyttöön, jotta omaisuutemme ovat kevyempiä verkon siirtymisen aikana:

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;

Nyt kun Nginx-kokoonpanomme on valmis, voimme vihdoin luoda Dockerfile- ja docker-compose-tiedostoja:

touch Dockerfile docker-compose.yml

Aluksi käytämme node:alpinekuvaa sovelluksen optimoidun tuotantorakenteen luomiseen. Sitten rakennamme ajonaikaisen kuvan päälle 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;\""]

Nyt kontti on valmis. Voimme tehdä kaikki tavalliset tavarat sen kanssa. Voimme rakentaa säilön, ajaa sen sisäisillä kokoonpanoilla ja siirtää sen tietopalveluun, kuten Dockerhub.

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

Yllä olevan docker runkomennon tulisi antaa sovellus sovelluksen tavoin:

Lopuksi, luodaan docker-compose-tiedosto. Sinulla on yleensä erilaisia ​​telakointikomponentteja ympäristöstä riippuen, ja valitset -flipun avulla käytettävän tiedoston.

version: "3.2" services: cra-runtime-environment-variables: image: kunokdev/cra-runtime-environment-variables ports: - "5000:80" environment: - "API_URL=production.example.com"

Ja jos teemme, docker-compose upmeidän pitäisi nähdä tällainen tulos:

Loistava! Olemme nyt saavuttaneet tavoitteemme. Voimme konfiguroida sovelluksemme helposti sekä kehitys- että tuotantoympäristöissä erittäin kätevällä tavalla. Voimme nyt vihdoin rakentaa vain kerran ja juosta kaikkialle!

Jos olet juuttunut tai sinulla on muita ideoita, käytä lähdekoodia GitHubissa.

? Seuraavat vaiheet

Shell-komentosarjan nykyinen toteutus tulostaa kaikki .env-tiedostoon sisältyvät muuttujat. Suurimman osan ajasta emme halua paljastaa niitä kaikkia. Voit toteuttaa suodattimia muuttujille, joita et halua paljastaa, käyttämällä etuliitteitä tai vastaavaa tekniikkaa.

? Vaihtoehtoiset ratkaisut

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.

Jos sinulla on kysyttävää tai haluat antaa palautetta voit avata ongelman GitHubissa. Seuraa minua vaihtoehtoisesti verkkotekniikoihin liittyvissä viesteissä.