<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nicolas Coutin</title>
    <description>The latest articles on DEV Community by Nicolas Coutin (@ilshidur).</description>
    <link>https://dev.to/ilshidur</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F465092%2F936d21c4-a92b-4545-a40f-9a0e282f08ff.png</url>
      <title>DEV Community: Nicolas Coutin</title>
      <link>https://dev.to/ilshidur</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ilshidur"/>
    <language>en</language>
    <item>
      <title>Dynamic configuration for static Vue apps without SSR</title>
      <dc:creator>Nicolas Coutin</dc:creator>
      <pubDate>Thu, 27 Jun 2019 23:59:00 +0000</pubDate>
      <link>https://dev.to/ilshidur/dynamic-configuration-for-static-vue-apps-without-ssr-742</link>
      <guid>https://dev.to/ilshidur/dynamic-configuration-for-static-vue-apps-without-ssr-742</guid>
      <description>&lt;p&gt;This article explains how to allow our Vue.js app to accept configurations at &lt;strong&gt;run time&lt;/strong&gt; instead of &lt;strong&gt;build time&lt;/strong&gt; using &lt;a href="https://www.docker.com" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; &amp;amp; &lt;a href="https://www.nginx.com" rel="noopener noreferrer"&gt;NGINX&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want the solution, you can skip to the &lt;em&gt;Solution&lt;/em&gt; section.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why ?
&lt;/h2&gt;

&lt;p&gt;At &lt;a href="https://www.scalair.fr" rel="noopener noreferrer"&gt;Scalair&lt;/a&gt;, we use Docker to deploy our applications. Some of our applications are Vue.js &lt;strong&gt;static&lt;/strong&gt; front ends, served through NGINX. We use &lt;em&gt;Gitlab CI&lt;/em&gt; to test &amp;amp; deploy our code to &lt;em&gt;Amazon EKS&lt;/em&gt;. Each Gitlab pipeline builds our app, then pushes the Docker image to Amazon ECR.&lt;/p&gt;

&lt;p&gt;Our Vue apps had configurations like this, &lt;a href="https://cli.vuejs.org/guide/mode-and-env.html#using-env-variables-in-client-side-code" rel="noopener noreferrer"&gt;thanks to Vue.js client-side env vars&lt;/a&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const API_URL = process.env.VUE_APP_API_URL;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Due to the lack of &lt;a href="https://vuejs.org/v2/guide/ssr.html" rel="noopener noreferrer"&gt;Server-Side Rendering&lt;/a&gt; in our Vue app, we used to give environment variables to the Vue CLI at build time in order to provide configurations, e.g.: an API URL.&lt;/p&gt;

&lt;p&gt;We also had a Dockerfile that we used to build using &lt;code&gt;docker build --build-arg API_URL=https://api.example.com .&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Build stage
FROM mhart/alpine-node:10 as build-stage

WORKDIR /app

COPY package.json package-lock.json .npmrc ./
RUN npm ci

COPY . .

ARG API_URL
ENV VUE_APP_API_URL $API_URL

RUN ./node_modules/.bin/vue-cli-service build --mode production

# Production stage
FROM nginx:1.17.0-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80

CMD nginx -g "daemon off;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This multi-stage build will build the static files, then serve them with NGINX.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One concern we had was the consistency of our images : a Docker image would differ from one environment to an other because of the &lt;code&gt;--build-arg&lt;/code&gt; parameter. The &lt;code&gt;VUE_APP_&lt;/code&gt; env vars only work at **build time&lt;/strong&gt;.**&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Let the NGINX container do the job !&lt;/p&gt;

&lt;p&gt;We replaced &lt;code&gt;process.env.VUE_APP_API_URL&lt;/code&gt; with &lt;code&gt;'{{ API_URL }}'&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This will act as a "template" that will be replaced with an actual URL.
const API_URL = '{{ API_URL }}';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we removed the build args &amp;amp; replaced the &lt;code&gt;{{ templates }}&lt;/code&gt; before running NGINX.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Dockerfile :&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Build stage
FROM mhart/alpine-node:10 as build-stage

WORKDIR /app

COPY package.json package-lock.json .npmrc ./
RUN npm ci

COPY . .

RUN ./node_modules/.bin/vue-cli-service build --mode production

# Production stage
FROM nginx:1.17.0-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80

# Using `sed` to replace {{ API_URL }} with the actual API URL,
# which is given to the container at RUN TIME !
CMD sed -i -e "s/{{ API_URL }}/$API_URL/g" /usr/share/nginx/html/js/app.*.js &amp;amp;&amp;amp; \
    nginx -g "daemon off;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we run the container using these commands :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t my-vue-app .
docker run -e API_URL=https://api.example.com my-vue-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is more a temporary solution than an actual long-term solution.&lt;/p&gt;

&lt;p&gt;If you are facing the same issue we had, you should definitely look into &lt;a href="https://vuejs.org/v2/guide/ssr.html" rel="noopener noreferrer"&gt;Server-Side Rendering&lt;/a&gt;. SSR allows a lot of behaviors that you can’t do with a single static app rendered in the browser. This is a good way to dynamically change parts of your frontend and prevent crappy hacks like we did.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>docker</category>
      <category>nginx</category>
      <category>vue</category>
    </item>
  </channel>
</rss>
