<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Travis CI - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Travis CI - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 28 Jul 2026 03:52:32 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/travis-ci/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Host an Angular Application on GitHub Pages with Travis CI ]]>
                </title>
                <description>
                    <![CDATA[ By Rodrigo Kamada In this article, we'll create an application using the latest version of Angular. Then we'll host it on the GitHub Pages static website service using the continuous integration tool Travis CI to deploy the application. Prerequisites... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/host-an-angular-application-on-github-pages-with-travis-ci/</link>
                <guid isPermaLink="false">66d460c57df3a1f32ee7f88d</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ github pages ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Travis CI ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 19 Apr 2022 10:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/04/angular-travisci-cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Rodrigo Kamada</p>
<p>In this article, we'll create an application using the latest version of Angular. Then we'll host it on the GitHub Pages static website service using the continuous integration tool Travis CI to deploy the application.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you start, you need to install and configure the tools below to create the Angular application.</p>
<ul>
<li><a target="_blank" href="https://git-scm.com/">Git</a>: Git is a distributed version control system that we'll use to sync the repository.</li>
<li><a target="_blank" href="https://nodejs.org/">Node.js and npm</a>: Node.js is a JavaScript code runtime software based on Google's V8 engine. npm is a package manager for Node.js (Node Package Manager). We'll use these to build and run the Angular application and install the libraries.</li>
<li><a target="_blank" href="https://angular.io/cli">Angular CLI</a>: Angular CLI is a command line utility tool for Angular which we'll use to create the base structure of the Angular application.</li>
<li>An IDE (like <a target="_blank" href="https://code.visualstudio.com/">Visual Studio Code</a> or <a target="_blank" href="https://www.jetbrains.com/webstorm/">WebStorm</a>): an IDE (Integrated Development Environment) is a tool with a graphical interface that helps us develop applications. Here, we'll use one to develop the Angular application.</li>
</ul>
<h2 id="heading-getting-started">Getting started</h2>
<h3 id="heading-create-and-configure-your-account-on-github">Create and configure your account on GitHub</h3>
<p><a target="_blank" href="https://github.com/">GitHub</a> is a source code and file storage service with version control using the Git tool. And <a target="_blank" href="https://pages.github.com/">GitHub Pages</a> is a static file hosting service using a public repository.</p>
<p>First, you'll need to create an account on GitHub if you don't have one already. Visit <a target="_blank" href="https://github.com/">https://github.com/</a> and click on the button <em>Sign up</em>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/github-step1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Fill in the fields for Username, Email address, and Password, click on the button Verify to solve the challenge, and then click on the button Create account.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/github-step2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Next, we'll generate the token that will be used in Travis CI. Click on the menu with the avatar and click on the menu Settings.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/github-step3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on the menu Developer settings.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/github-step4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on the menu Personal access tokens.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/github-step5.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on the button Generate new token.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/github-step6.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Fill in the field Note, select the option repo and click on the button Create token.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/github-step7.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Copy the generated token. In my case, the token <code>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</code> was generated because this token will be configured in Travis CI.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/github-step8.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let's create the repository. Click on the menu with the avatar and click on the menu Your repositories.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/github-step9.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on the button New.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/github-step10.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Fill in the field Repository name and click on the button Create repository.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/github-step11.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Ready! Account created, token generated, and repository <a target="_blank" href="https://github.com/rodrigokamada/angular-travisci"><code>https://github.com/rodrigokamada/angular-travisci</code></a> created.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/github-step12.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-create-and-configure-your-account-on-travis-ci">Create and configure your account on Travis CI</h3>
<p><a target="_blank" href="https://www.travis-ci.com/">Travis CI</a> is a deployment service integrated with GitHub.</p>
<p>First, you'll need to create a Travis CI account if you don't already have one. Visit <a target="_blank" href="https://travis-ci.com/">https://travis-ci.com/</a> and click on the button Sign up.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/travisci-step1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on the button SIGN IN WITH GITHUB to sign in with your GitHub account.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/travisci-step2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If Travis CI requests permission to list the GitHub repositories, accept the request. Click on the repository link angular-travisci.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/travisci-step3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let's set up the GitHub access token. Click on the menu More options and click on the menu Settings.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/travisci-step4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Fill in the field NAME with the value GITHUB_TOKEN, VALUE with the value of your token generated on GitHub, and click on the button Add.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/travisci-step5.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Ready! Account created and repository configured.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/travisci-step6.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-create-your-angular-application">Create your Angular application</h3>
<p><a target="_blank" href="https://angular.io/">Angular</a> is a development platform for building Web, mobile, and desktop applications using HTML, CSS and TypeScript (JavaScript). Currently, Angular is at version 13 and Google is the main maintainer of the project.</p>
<p>Let's create the application with the Angular base structure using the <code>@angular/cli</code> with the route file and the SCSS style format.</p>
<pre><code class="lang-powershell">? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? SCSS   [ <span class="hljs-type">https</span>://<span class="hljs-type">sass</span>-<span class="hljs-type">lang.com</span>/<span class="hljs-type">documentation</span>/<span class="hljs-type">syntax</span><span class="hljs-comment">#scss                ]</span>
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">README.md</span> (<span class="hljs-number">1061</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">.editorconfig</span> (<span class="hljs-number">274</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">.gitignore</span> (<span class="hljs-number">604</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">angular.json</span> (<span class="hljs-number">3267</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">package.json</span> (<span class="hljs-number">1078</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">tsconfig.json</span> (<span class="hljs-number">783</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">.browserslistrc</span> (<span class="hljs-number">703</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">karma.conf.js</span> (<span class="hljs-number">1433</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">tsconfig.app.json</span> (<span class="hljs-number">287</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">tsconfig.spec.json</span> (<span class="hljs-number">333</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">favicon.ico</span> (<span class="hljs-number">948</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">index.html</span> (<span class="hljs-number">301</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">main.ts</span> (<span class="hljs-number">372</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">polyfills.ts</span> (<span class="hljs-number">2820</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">styles.scss</span> (<span class="hljs-number">80</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">test.ts</span> (<span class="hljs-number">743</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">assets</span>/<span class="hljs-type">.gitkeep</span> (<span class="hljs-number">0</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">environments</span>/<span class="hljs-type">environment.prod.ts</span> (<span class="hljs-number">51</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">environments</span>/<span class="hljs-type">environment.ts</span> (<span class="hljs-number">658</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">app</span>/<span class="hljs-type">app</span>-<span class="hljs-type">routing.module.ts</span> (<span class="hljs-number">245</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">app</span>/<span class="hljs-type">app.module.ts</span> (<span class="hljs-number">393</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">app</span>/<span class="hljs-type">app.component.scss</span> (<span class="hljs-number">0</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">app</span>/<span class="hljs-type">app.component.html</span> (<span class="hljs-number">23809</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">app</span>/<span class="hljs-type">app.component.spec.ts</span> (<span class="hljs-number">1087</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
<span class="hljs-type">CREATE</span> <span class="hljs-type">angular</span>-<span class="hljs-type">travisci</span>/<span class="hljs-type">src</span>/<span class="hljs-type">app</span>/<span class="hljs-type">app.component.ts</span> (<span class="hljs-number">221</span> <span class="hljs-built_in">byte</span><span class="hljs-type">s</span>)
✔ <span class="hljs-type">Packages</span> <span class="hljs-type">installed</span> <span class="hljs-type">successfully.</span>
    <span class="hljs-type">Successfully</span> <span class="hljs-type">initialized</span> <span class="hljs-type">git.</span>
</code></pre>
<p>Create the <code>.travis.yml</code> file.</p>
<pre><code class="lang-powershell">touch .travis.yml
</code></pre>
<p>Configure the <code>.travis.yml</code> file with the content below:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">notifications:</span>
  <span class="hljs-attr">email:</span>
    <span class="hljs-attr">recipients:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">rodrigo@kamada.com.br</span>

<span class="hljs-attr">language:</span> <span class="hljs-string">node_js</span>

<span class="hljs-attr">node_js:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-number">16</span>

<span class="hljs-attr">before_script:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span>

<span class="hljs-attr">script:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">test:headless</span>

<span class="hljs-attr">before_deploy:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build:prod</span>

<span class="hljs-attr">deploy:</span>
  <span class="hljs-attr">provider:</span> <span class="hljs-string">pages</span>
  <span class="hljs-attr">skip_cleanup:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">github_token:</span> <span class="hljs-string">$GITHUB_TOKEN</span>
  <span class="hljs-attr">local_dir:</span> <span class="hljs-string">dist/angular-travisci</span>
  <span class="hljs-attr">on:</span>
    <span class="hljs-attr">branch:</span> <span class="hljs-string">main</span>
</code></pre>
<p>Change the <code>package.json</code> file and add the scripts below. Replace the <code>rodrigokamada</code> value with your GitHub username.</p>
<pre><code class="lang-json">  <span class="hljs-string">"build:prod"</span>: <span class="hljs-string">"ng build --prod --base-href https://rodrigokamada.github.io/angular-travisci/"</span>,
  <span class="hljs-string">"test:headless"</span>: <span class="hljs-string">"ng test --watch=false --browsers=ChromeHeadless"</span>
</code></pre>
<p>Change the <code>src/app/app.component.spec.ts</code> file and remove the tests <code>should have as title 'angular-travisci'</code> and <code>should render title</code>.</p>
<p>Run the test with the command below:</p>
<pre><code class="lang-powershell">npm run test:headless

&gt; angular<span class="hljs-literal">-travisci</span>@<span class="hljs-number">1.0</span>.<span class="hljs-number">0</span> test:headless
&gt; ng test -<span class="hljs-literal">-watch</span>=false -<span class="hljs-literal">-browsers</span>=ChromeHeadless

⠋ Generating browser application bundles (phase: setup)...Compiling @angular/core/testing : es2015 as esm2015
Compiling @angular/compiler/testing : es2015 as esm2015
Compiling @angular/platform<span class="hljs-literal">-browser</span>/testing : es2015 as esm2015
Compiling @angular/common/testing : es2015 as esm2015
Compiling @angular/platform<span class="hljs-literal">-browser</span><span class="hljs-literal">-dynamic</span>/testing : es2015 as esm2015
Compiling @angular/router/testing : es2015 as esm2015
⠸ Generating browser application bundles (phase: building)...<span class="hljs-number">05</span> <span class="hljs-number">09</span> <span class="hljs-number">2021</span> <span class="hljs-number">19</span>:<span class="hljs-number">40</span>:<span class="hljs-number">04.329</span>:INFO [<span class="hljs-type">karma</span>-<span class="hljs-type">server</span>]: Karma v6.<span class="hljs-number">3.4</span> server started at http://localhost:<span class="hljs-number">9876</span>/
<span class="hljs-number">05</span> <span class="hljs-number">09</span> <span class="hljs-number">2021</span> <span class="hljs-number">19</span>:<span class="hljs-number">40</span>:<span class="hljs-number">04.331</span>:INFO [<span class="hljs-type">launcher</span>]: Launching browsers ChromeHeadless with concurrency unlimited
<span class="hljs-number">05</span> <span class="hljs-number">09</span> <span class="hljs-number">2021</span> <span class="hljs-number">19</span>:<span class="hljs-number">40</span>:<span class="hljs-number">04.369</span>:INFO [<span class="hljs-type">launcher</span>]: Starting browser ChromeHeadless
✔ Browser application bundle generation complete.
<span class="hljs-number">05</span> <span class="hljs-number">09</span> <span class="hljs-number">2021</span> <span class="hljs-number">19</span>:<span class="hljs-number">40</span>:<span class="hljs-number">09.704</span>:INFO [<span class="hljs-type">Chrome</span> <span class="hljs-type">Headless</span> <span class="hljs-number">92.0</span><span class="hljs-type">.4515.159</span> (<span class="hljs-type">Linux</span> <span class="hljs-type">x86_64</span>)]: Connected on socket NUtJhjavb1JvssqOAAAB with id <span class="hljs-number">25989029</span>
Chrome Headless <span class="hljs-number">92.0</span>.<span class="hljs-number">4515.159</span> (Linux x86_64): Executed <span class="hljs-number">1</span> of <span class="hljs-number">1</span> SUCCESS (<span class="hljs-number">0.068</span> secs / <span class="hljs-number">0.042</span> secs)
TOTAL: <span class="hljs-number">1</span> SUCCESS
</code></pre>
<p>Run the application with the command below. Access the URL <code>http://localhost:4200/</code> and check if the application is working.</p>
<pre><code class="lang-powershell">npm <span class="hljs-built_in">start</span>

&gt; angular<span class="hljs-literal">-travisci</span>@<span class="hljs-number">1.0</span>.<span class="hljs-number">0</span> <span class="hljs-built_in">start</span>
&gt; ng serve

✔ Browser application bundle generation complete.

Initial Chunk Files | Names         |      Size
vendor.js           | vendor        |   <span class="hljs-number">2.39</span> MB
polyfills.js        | polyfills     | <span class="hljs-number">128.51</span> kB
main.js             | main          |   <span class="hljs-number">8.89</span> kB
runtime.js          | runtime       |   <span class="hljs-number">6.63</span> kB
styles.css          | styles        |   <span class="hljs-number">1.18</span> kB

                    | Initial Total |   <span class="hljs-number">2.53</span> MB

Build at: <span class="hljs-number">2021</span><span class="hljs-literal">-09</span><span class="hljs-literal">-05T22</span>:<span class="hljs-number">35</span>:<span class="hljs-number">38.010</span>Z - Hash: a4cfc9149589386eca5b - Time: <span class="hljs-number">39997</span>ms

** Angular Live Development Server is listening on localhost:<span class="hljs-number">4200</span>, open your browser on http://localhost:<span class="hljs-number">4200</span>/ **


✔ Compiled successfully.
</code></pre>
<p>Build the application with the command below:</p>
<pre><code class="lang-powershell">npm run build:prod

&gt; angular<span class="hljs-literal">-travisci</span>@<span class="hljs-number">1.0</span>.<span class="hljs-number">0</span> build:prod
&gt; ng build -<span class="hljs-literal">-configuration</span> production -<span class="hljs-literal">-base</span><span class="hljs-literal">-href</span> https://rodrigokamada.github.io/angular<span class="hljs-literal">-travisci</span>/

✔ Browser application bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.

Initial Chunk Files           | Names         |      Size
main.c678fa8750e7c769.js      | main          | <span class="hljs-number">177.63</span> kB
polyfills.<span class="hljs-number">6</span>d7801353e02e327.js | polyfills     |  <span class="hljs-number">36.21</span> kB
runtime.b136bda8a38c4f2e.js   | runtime       |   <span class="hljs-number">1.06</span> kB
styles.ef46db3751d8e999.css   | styles        |   <span class="hljs-number">0</span> bytes

                              | Initial Total | <span class="hljs-number">214.90</span> kB

Build at: <span class="hljs-number">2021</span><span class="hljs-literal">-09</span><span class="hljs-literal">-05T22</span>:<span class="hljs-number">42</span>:<span class="hljs-number">19.525</span>Z - Hash: <span class="hljs-number">83</span>bfffc079b083727ca4 - Time: <span class="hljs-number">26030</span>ms
</code></pre>
<p>Syncronize the application on the GitHub repository that you created.</p>
<p>Ready! After synchronizing the application on the GitHub repository, Travis CI builds the application and synchronizes on the branch <code>gh-pages</code>. </p>
<p>Access the URL <a target="_blank" href="https://rodrigokamada.github.io/angular-travisci/"><code>https://rodrigokamada.github.io/angular-travisci/</code></a> and check if the application is working. Replace the <code>rodrigokamada</code> value with your GitHub username.</p>
<p>And that's it! The application repository is available at <a target="_blank" href="https://github.com/rodrigokamada/angular-travisci">https://github.com/rodrigokamada/angular-travisci</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Summarizing what was covered in this article:</p>
<ul>
<li>We created an account on GitHub.</li>
<li>We created an access token on GitHub.</li>
<li>We created a repository on GitHub.</li>
<li>We created an account on Travis CI.</li>
<li>We configured the GitHub access token on Travis CI.</li>
<li>We create an Angular application.</li>
</ul>
<p>You can use this article to create your personal website and have an online portfolio.</p>
<p>Thank you for reading and I hope you enjoyed the article!</p>
<p>To stay updated whenever I post new articles, follow me on <a target="_blank" href="https://twitter.com/rodrigokamada">Twitter</a>.</p>
<p>This tutorial was posted on my <a target="_blank" href="https://rodrigo.kamada.com.br/share/blog/hospedando-uma-aplicacao-angular-no-github-pages-usando-o-travis-ci">blog</a> in Portuguese.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Develop and Deploy Micro-Frontends with Single-SPA ]]>
                </title>
                <description>
                    <![CDATA[ By Tyler Hawkins Micro-frontends are the future of front end web development. Inspired by microservices, which allow you to break up your backend into smaller pieces, micro-frontends allow you to build, test, and deploy pieces of your frontend app in... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/developing-and-deploying-micro-frontends-with-single-spa/</link>
                <guid isPermaLink="false">66d4617438f2dc3808b79113</guid>
                
                    <category>
                        <![CDATA[ architecture ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Front-end Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Heroku ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Travis CI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 03 Aug 2020 11:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/07/single-spa-3.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Tyler Hawkins</p>
<p>Micro-frontends are the future of front end web development.</p>
<p>Inspired by microservices, which allow you to break up your backend into smaller pieces, micro-frontends allow you to build, test, and deploy pieces of your frontend app independently of each other. </p>
<p>Depending on the micro-frontend framework you choose, you can even have multiple micro-frontend apps — written in React, Angular, Vue, or anything else — coexisting peacefully together in the same larger app.</p>
<p>In this article, we’re going to develop an app composed of micro-frontends using <a target="_blank" href="https://single-spa.js.org/">single-spa</a> and deploy it to <a target="_blank" href="https://www.heroku.com/">Heroku</a>. </p>
<p>We’ll set up continuous integration using <a target="_blank" href="https://travis-ci.org/">Travis CI</a>. Each CI pipeline will bundle the JavaScript for a micro-frontend app and then upload the resulting build artifacts to <a target="_blank" href="https://aws.amazon.com/s3/">AWS S3</a>. </p>
<p>Finally, we’ll make an update to one of the micro-frontend apps and see how it can be deployed to production independently of the other micro-frontend apps.</p>
<h1 id="heading-overview-of-the-demo-app">Overview of the Demo App</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/mfe1.png" alt="Demo app — end result" width="600" height="400" loading="lazy">
<em>Demo app — end result</em></p>
<p>Before we discuss the step-by-step instructions, let’s get a quick overview of what makes up the demo app. This app is composed of four sub-apps:</p>
<ol>
<li>A <a target="_blank" href="https://github.com/thawkin3/single-spa-demo-root-config">container app</a> that serves as the main page container and coordinates the mounting and unmounting of the micro-frontend apps</li>
<li>A <a target="_blank" href="https://github.com/thawkin3/single-spa-demo-nav">micro-frontend navbar app</a> that’s always present on the page</li>
<li>A <a target="_blank" href="https://github.com/thawkin3/single-spa-demo-page-1">micro-frontend “page 1” app</a> that only shows when active</li>
<li>A <a target="_blank" href="https://github.com/thawkin3/single-spa-demo-page-2">micro-frontend “page 2” app</a> that also only shows when active</li>
</ol>
<p>These four apps all live in separate repos, available on GitHub, which I’ve linked to above.</p>
<p>The end result is fairly simple in terms of the user interface, but, to be clear, the user interface isn’t the point here. </p>
<p>If you’re following along on your own machine, by the end of this article you too will have all the underlying infrastructure necessary to get started with your own micro-frontend app.</p>
<p>Alright, grab your scuba gear, because it’s time to dive in!</p>
<h1 id="heading-creating-the-container-app">Creating the Container App</h1>
<p>To generate the apps for this demo, we’re going to use a command-line interface (CLI) tool called <a target="_blank" href="https://single-spa.js.org/docs/create-single-spa/">create-single-spa</a>. The version of create-single-spa at the time of writing is 1.10.0, and the version of single-spa installed via the CLI is 4.4.2.</p>
<p>We’ll follow these steps to create the container app (also sometimes called the root config):</p>
<pre><code class="lang-bash">mkdir single-spa-demo

<span class="hljs-built_in">cd</span> single-spa-demo

mkdir single-spa-demo-root-config

<span class="hljs-built_in">cd</span> single-spa-demo-root-config

npx create-single-spa
</code></pre>
<p>We’ll then follow the CLI prompts:</p>
<ol>
<li>Select “single spa root config”</li>
<li>Select “yarn” or “npm” (I chose “yarn”)</li>
<li>Enter an organization name (I used “thawkin3,” but it can be whatever you want)</li>
</ol>
<p>Great! Now, if you check out the <code>single-spa-demo-root-config</code> directory, you should see a skeleton root config app. We'll customize this in a bit, but first let's also use the CLI tool to create our other three micro-frontend apps.</p>
<h1 id="heading-creating-the-micro-frontend-apps">Creating the Micro-Frontend Apps</h1>
<p>To generate our first micro-frontend app, the navbar, we’ll follow these steps:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ..

mkdir single-spa-demo-nav

<span class="hljs-built_in">cd</span> single-spa-demo-nav

npx create-single-spa
</code></pre>
<p>We’ll then follow the CLI prompts:</p>
<ol>
<li>Select “single-spa application / parcel”</li>
<li>Select “react”</li>
<li>Select “yarn” or “npm” (I chose “yarn”)</li>
<li>Enter an organization name, the same one you used when creating the root config app (“thawkin3” in my case)</li>
<li>Enter a project name (I used “single-spa-demo-nav”)</li>
</ol>
<p>Now that we’ve created the navbar app, we can follow these same steps to create our two page apps. But, we’ll replace each place we see “single-spa-demo-nav” with “single-spa-demo-page-1” the first time through and then with “single-spa-demo-page-2” the second time through.</p>
<p>At this point we’ve generated all four apps that we need: one container app and three micro-frontend apps. Now it’s time to hook our apps together.</p>
<h1 id="heading-registering-the-micro-frontend-apps-with-the-container-app">Registering the Micro-Frontend Apps with the Container App</h1>
<p>As stated before, one of the container app’s primary responsibilities is to coordinate when each app is “active” or not. In other words, it handles when each app should be shown or hidden. </p>
<p>To help the container app understand when each app should be shown, we provide it with what are called “activity functions.” Each app has an activity function that simply returns a boolean, true or false, for whether or not the app is currently active.</p>
<p>Inside the <code>single-spa-demo-root-config</code> directory, in the <code>activity-functions.js</code> file, we'll write the following activity functions for our three micro-frontend apps.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">prefix</span>(<span class="hljs-params">location, ...prefixes</span>) </span>{
  <span class="hljs-keyword">return</span> prefixes.some(
    <span class="hljs-function"><span class="hljs-params">prefix</span> =&gt;</span> location.href.indexOf(<span class="hljs-string">`<span class="hljs-subst">${location.origin}</span>/<span class="hljs-subst">${prefix}</span>`</span>) !== <span class="hljs-number">-1</span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">nav</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// The nav is always active</span>
  <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">page1</span>(<span class="hljs-params">location</span>) </span>{
  <span class="hljs-keyword">return</span> prefix(location, <span class="hljs-string">'page1'</span>);
}

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">page2</span>(<span class="hljs-params">location</span>) </span>{
  <span class="hljs-keyword">return</span> prefix(location, <span class="hljs-string">'page2'</span>);
}
</code></pre>
<p>Next, we need to register our three micro-frontend apps with single-spa. To do that, we use the <code>registerApplication</code> function. This function accepts a minimum of three arguments: the app name, a method to load the app, and an activity function to determine when the app is active.</p>
<p>Inside the <code>single-spa-demo-root-config</code> directory, in the <code>root-config.js</code> file, we'll add the following code to register our apps:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { registerApplication, start } <span class="hljs-keyword">from</span> <span class="hljs-string">"single-spa"</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> isActive <span class="hljs-keyword">from</span> <span class="hljs-string">"./activity-functions"</span>;

registerApplication(
  <span class="hljs-string">"@thawkin3/single-spa-demo-nav"</span>,
  <span class="hljs-function">() =&gt;</span> System.import(<span class="hljs-string">"@thawkin3/single-spa-demo-nav"</span>),
  isActive.nav
);

registerApplication(
  <span class="hljs-string">"@thawkin3/single-spa-demo-page-1"</span>,
  <span class="hljs-function">() =&gt;</span> System.import(<span class="hljs-string">"@thawkin3/single-spa-demo-page-1"</span>),
  isActive.page1
);

registerApplication(
  <span class="hljs-string">"@thawkin3/single-spa-demo-page-2"</span>,
  <span class="hljs-function">() =&gt;</span> System.import(<span class="hljs-string">"@thawkin3/single-spa-demo-page-2"</span>),
  isActive.page2
);

start();
</code></pre>
<p>Now that we’ve set up the activity functions and registered our apps, the last step before we can get this running locally is to update the local import map inside the <code>index.ejs</code> file in the same directory. </p>
<p>We'll add the following code inside the <code>head</code> tag to specify where each app can be found when running locally:</p>
<pre><code class="lang-javascript">&lt;% <span class="hljs-keyword">if</span> (isLocal) { %&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"systemjs-importmap"</span>&gt;</span><span class="javascript">
    {
      <span class="hljs-string">"imports"</span>: {
        <span class="hljs-string">"@thawkin3/root-config"</span>: <span class="hljs-string">"http://localhost:9000/root-config.js"</span>,
        <span class="hljs-string">"@thawkin3/single-spa-demo-nav"</span>: <span class="hljs-string">"http://localhost:9001/thawkin3-single-spa-demo-nav.js"</span>,
        <span class="hljs-string">"@thawkin3/single-spa-demo-page-1"</span>: <span class="hljs-string">"http://localhost:9002/thawkin3-single-spa-demo-page-1.js"</span>,
        <span class="hljs-string">"@thawkin3/single-spa-demo-page-2"</span>: <span class="hljs-string">"http://localhost:9003/thawkin3-single-spa-demo-page-2.js"</span>
      }
    }
  </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
&lt;% } %&gt;
</code></pre>
<p>Each app contains its own startup script, which means that each app will be running locally on its own development server during local development. As you can see, our navbar app is on port 9001, our page 1 app is on port 9002, and our page 2 app is on port 9003.</p>
<p>With those three steps taken care of, let’s try out our app.</p>
<h1 id="heading-test-run-for-running-locally">Test Run for Running Locally</h1>
<p>To get our app running locally, we can follow these steps:</p>
<ol>
<li>Open four terminal tabs, one for each app</li>
<li>For the root config, in the <code>single-spa-demo-root-config</code> directory: <code>yarn start</code> (runs on port 9000 by default)</li>
<li>For the nav app, in the <code>single-spa-demo-nav</code> directory: <code>yarn start --port 9001</code></li>
<li>For the page 1 app, in the <code>single-spa-demo-page-1</code> directory: <code>yarn start --port 9002</code></li>
<li>For the page 2 app, in the <code>single-spa-demo-page-2</code> directory: <code>yarn start --port 9003</code></li>
</ol>
<p>Now, we’ll navigate in the browser to <a target="_blank" href="http://localhost:9000/">http://localhost:9000</a> to view our app.</p>
<p>We should see… some text! Super exciting.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/mfe2.png" alt="Demo app — main page" width="600" height="400" loading="lazy">
<em>Demo app — main page</em></p>
<p>On our main page, the navbar is showing because the navbar app is always active.</p>
<p>Now, let’s navigate to <a target="_blank" href="http://localhost:9000/page1.">http://localhost:9000/page1.</a> As shown in our activity functions above, we’ve specified that the page 1 app should be active (shown) when the URL path begins with “page1.” So, this activates the page 1 app, and we should see the text for both the navbar and the page 1 app now.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/mfe3.png" alt="Demo app — page 1 route" width="600" height="400" loading="lazy">
<em>Demo app — page 1 route</em></p>
<p>One more time, let’s now navigate to <a target="_blank" href="http://localhost:9000/page2.">http://localhost:9000/page2.</a> As expected, this activates the page 2 app, so we should see the text for the navbar and the page 2 app now.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/mfe4.png" alt="Demo app — page 2 route" width="600" height="400" loading="lazy">
<em>Demo app — page 2 route</em></p>
<h1 id="heading-making-minor-tweaks-to-the-apps">Making Minor Tweaks to the Apps</h1>
<p>So far our app isn’t very exciting to look at, but we do have a working micro-frontend setup running locally. If you aren’t cheering in your seat right now, you should be!</p>
<p>Let’s make some minor improvements to our apps so they look and behave a little nicer.</p>
<h3 id="heading-specifying-the-mount-containers">Specifying the Mount Containers</h3>
<p>First, if you refresh your page over and over when viewing the app, you may notice that sometimes the apps load out of order, with the page app appearing above the navbar app. </p>
<p>This is because we haven’t actually specified <em>where</em> each app should be mounted. The apps are simply loaded by <a target="_blank" href="https://github.com/systemjs/systemjs">SystemJS</a>, and then whichever app finishes loading fastest gets appended to the page first.</p>
<p>We can fix this by specifying a mount container for each app when we register them.</p>
<p>In our <code>index.ejs</code> file that we worked in previously, let's add some HTML to serve as the main content containers for the page:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"nav-container"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"page-1-container"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"page-2-container"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
</code></pre>
<p>Then, in our <code>root-config.js</code> file where we've registered our apps, let's provide a fourth argument to each function call that includes the DOM element where we'd like to mount each app:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { registerApplication, start } <span class="hljs-keyword">from</span> <span class="hljs-string">"single-spa"</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> isActive <span class="hljs-keyword">from</span> <span class="hljs-string">"./activity-functions"</span>;

registerApplication(
  <span class="hljs-string">"@thawkin3/single-spa-demo-nav"</span>,
  <span class="hljs-function">() =&gt;</span> System.import(<span class="hljs-string">"@thawkin3/single-spa-demo-nav"</span>),
  isActive.nav,
  { <span class="hljs-attr">domElement</span>: <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'nav-container'</span>) }
);

registerApplication(
  <span class="hljs-string">"@thawkin3/single-spa-demo-page-1"</span>,
  <span class="hljs-function">() =&gt;</span> System.import(<span class="hljs-string">"@thawkin3/single-spa-demo-page-1"</span>),
  isActive.page1,
  { <span class="hljs-attr">domElement</span>: <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'page-1-container'</span>) }
);

registerApplication(
  <span class="hljs-string">"@thawkin3/single-spa-demo-page-2"</span>,
  <span class="hljs-function">() =&gt;</span> System.import(<span class="hljs-string">"@thawkin3/single-spa-demo-page-2"</span>),
  isActive.page2,
  { <span class="hljs-attr">domElement</span>: <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'page-2-container'</span>) }
);

start();
</code></pre>
<p>Now, the apps will always be mounted to a specific and predictable location. Nice!</p>
<h3 id="heading-styling-the-app">Styling the App</h3>
<p>Next, let’s style up our app a bit. Plain black text on a white background isn’t very interesting to look at.</p>
<p>In the <code>single-spa-demo-root-config</code> directory, in the <code>index.ejs</code> file again, we can add some basic styles for the whole app by pasting the following CSS at the bottom of the <code>head</code> tag:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
  <span class="hljs-selector-tag">body</span>, <span class="hljs-selector-tag">html</span> { <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>; <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>; <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>; <span class="hljs-attribute">font-family</span>: Arial, Helvetica, sans-serif; <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>; }
  <span class="hljs-selector-tag">body</span> { <span class="hljs-attribute">display</span>: flex; <span class="hljs-attribute">flex-direction</span>: column; }
  * { <span class="hljs-attribute">box-sizing</span>: border-box; }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>Next, we can style our navbar app by finding the <code>single-spa-demo-nav</code> directory, creating a <code>root.component.css</code> file, and adding the following CSS:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.nav</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: row;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#000</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}

<span class="hljs-selector-class">.link</span> {
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">text-decoration</span>: none;
}

<span class="hljs-selector-class">.link</span><span class="hljs-selector-pseudo">:hover</span>,
<span class="hljs-selector-class">.link</span><span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#1098f7</span>;
}
</code></pre>
<p>We can then update the <code>root.component.js</code> file in the same directory to import the CSS file and apply those classes and styles to our HTML. We'll also change the navbar content to actually contain two links so we can navigate around the app by clicking the links instead of entering a new URL in the browser's address bar.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./root.component.css"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Root</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/page1"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"link"</span>&gt;</span>
        Page 1
      <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/page2"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"link"</span>&gt;</span>
        Page 2
      <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span></span>
  );
}
</code></pre>
<p>We’ll follow a similar process for the page 1 and page 2 apps as well. We’ll create a <code>root.component.css</code> file for each app in their respective project directories and update the <code>root.component.js</code> files for both apps too.</p>
<p>For the page 1 app, the changes look like this:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container1</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#1098f7</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
}
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./root.component.css"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Root</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container1"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Page 1 App<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>And for the page 2 app, the changes look like this:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container2</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#9e4770</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
}
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./root.component.css"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Root</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container2"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Page 2 App<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<h3 id="heading-adding-react-router">Adding React Router</h3>
<p>The last small change we’ll make is to add <a target="_blank" href="https://reacttraining.com/react-router/">React Router</a> to our app. Right now the two links we’ve placed in the navbar are just normal anchor tags, so navigating from page to page causes a page refresh. Our app will feel much smoother if the navigation is handled client-side with React Router.</p>
<p>To use React Router, we’ll first need to install it. From the terminal, in the <code>single-spa-demo-nav</code> directory, we'll install React Router using yarn by entering <code>yarn add react-router-dom</code>. (Or if you're using npm, you can enter <code>npm install react-router-dom</code>.)</p>
<p>Then, in the <code>single-spa-demo-nav</code> directory in the <code>root.component.js</code> file, we'll replace our anchor tags with React Router's <code>Link</code> components like so:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { BrowserRouter, Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./root.component.css"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Root</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/page1"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"link"</span>&gt;</span>
          Page 1
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/page2"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"link"</span>&gt;</span>
          Page 2
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span></span>
  );
}
</code></pre>
<p>Cool. That looks and works much better!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/mfe5.png" alt="Demo app — styled and using React Router" width="600" height="400" loading="lazy">
<em>Demo app — styled and using React Router</em></p>
<h1 id="heading-getting-ready-for-production">Getting Ready for Production</h1>
<p>At this point we have everything we need to continue working on the app while running it locally. But how do we get it hosted somewhere publicly available? </p>
<p>There are several possible approaches we can take using our tools of choice, but the main tasks are:</p>
<ol>
<li>to have somewhere we can upload our build artifacts, like a CDN, and</li>
<li>to automate this process of uploading artifacts each time we merge new code into the master branch.</li>
</ol>
<p>For this article, we’re going to use AWS S3 to store our assets, and we’re going to use Travis CI to run a build job and an upload job as part of a continuous integration pipeline.</p>
<p>Let’s get the S3 bucket set up first.</p>
<h3 id="heading-setting-up-the-aws-s3-bucket">Setting up the AWS S3 Bucket</h3>
<p>It should go without saying, but you’ll need an AWS account if you’re following along here. </p>
<p>If we are the root user on our AWS account, we can create a new IAM user that has programmatic access only. This means we’ll be given an access key ID and a secret access key from AWS when we create the new user. We’ll want to store these in a safe place since we’ll need them later. </p>
<p>Finally, this user should be given permissions to work with S3 only, so that the level of access is limited if our keys were to fall into the wrong hands.</p>
<p>AWS has some great resources for <a target="_blank" href="https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html">best practices with access keys</a> and <a target="_blank" href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html">managing access keys for IAM users</a> that would be well worth checking out if you’re unfamiliar with how to do this.</p>
<p>Next we need to create an S3 bucket. S3 stands for Simple Storage Service and is essentially a place to upload and store files hosted on Amazon’s servers. A bucket is simply a directory. </p>
<p>I’ve named my bucket “single-spa-demo,” but you can name yours whatever you’d like. You can follow the AWS guides for <a target="_blank" href="https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html">how to create a new bucket</a> for more info.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/mfe6.png" alt="AWS S3 bucket" width="600" height="400" loading="lazy">
<em>AWS S3 bucket</em></p>
<p>Once we have our bucket created, it’s also important to make sure the bucket is public and that <a target="_blank" href="https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html#how-do-i-enable-cors">CORS (cross-origin resource sharing) is enabled for our bucket</a> so that we can access and use our uploaded assets in our app. </p>
<p>In the permissions for our bucket, we can add the following CORS configuration rules:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">CORSConfiguration</span>&gt;</span>
 <span class="hljs-tag">&lt;<span class="hljs-name">CORSRule</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">AllowedOrigin</span>&gt;</span>*<span class="hljs-tag">&lt;/<span class="hljs-name">AllowedOrigin</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">AllowedMethod</span>&gt;</span>GET<span class="hljs-tag">&lt;/<span class="hljs-name">AllowedMethod</span>&gt;</span>
 <span class="hljs-tag">&lt;/<span class="hljs-name">CORSRule</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">CORSConfiguration</span>&gt;</span>
</code></pre>
<p>In the AWS console, it ends up looking like this after we hit Save:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/mfe7.png" alt="Image" width="600" height="400" loading="lazy">
<em>CORS configuration</em></p>
<h3 id="heading-creating-a-travis-ci-job-to-upload-artifacts-to-aws-s3">Creating a Travis CI Job to Upload Artifacts to AWS S3</h3>
<p>Now that we have somewhere to upload files, let’s set up an automated process that will take care of uploading new JavaScript bundles each time we merge new code into the master branch for any of our repos.</p>
<p>To do this, we’re going to use <a target="_blank" href="https://travis-ci.org/">Travis CI</a>. As mentioned earlier, each app lives in its own repo on GitHub, so we have four GitHub repos to work with. We can <a target="_blank" href="https://docs.travis-ci.com/user/tutorial/#to-get-started-with-travis-ci-using-github">integrate Travis CI with each of our repos</a> and set up continuous integration pipelines for each one.</p>
<p>To configure Travis CI for any given project, we create a <code>.travis.yml</code> file in the project's root directory. Let's create that file in the <code>single-spa-demo-root-config</code> directory and insert the following code:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">language:</span> <span class="hljs-string">node_js</span>
<span class="hljs-attr">node_js:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">node</span>
<span class="hljs-attr">script:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">yarn</span> <span class="hljs-string">build</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">echo</span> <span class="hljs-string">"Commit sha - $TRAVIS_COMMIT"</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">dist/@thawkin3/root-config/$TRAVIS_COMMIT</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">mv</span> <span class="hljs-string">dist/*.*</span> <span class="hljs-string">dist/@thawkin3/root-config/$TRAVIS_COMMIT/</span>
<span class="hljs-attr">deploy:</span>
  <span class="hljs-attr">provider:</span> <span class="hljs-string">s3</span>
  <span class="hljs-attr">access_key_id:</span> <span class="hljs-string">"$AWS_ACCESS_KEY_ID"</span>
  <span class="hljs-attr">secret_access_key:</span> <span class="hljs-string">"$AWS_SECRET_ACCESS_KEY"</span>
  <span class="hljs-attr">bucket:</span> <span class="hljs-string">"single-spa-demo"</span>
  <span class="hljs-attr">region:</span> <span class="hljs-string">"us-west-2"</span>
  <span class="hljs-attr">cache-control:</span> <span class="hljs-string">"max-age=31536000"</span>
  <span class="hljs-attr">acl:</span> <span class="hljs-string">"public_read"</span>
  <span class="hljs-attr">local_dir:</span> <span class="hljs-string">dist</span>
  <span class="hljs-attr">skip_cleanup:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">on:</span>
    <span class="hljs-attr">branch:</span> <span class="hljs-string">master</span>
</code></pre>
<p>This implementation is what I came up with after reviewing the <a target="_blank" href="https://docs.travis-ci.com/user/deployment-v2/providers/s3/">Travis CI docs for AWS S3 uploads</a> and a <a target="_blank" href="https://github.com/single-spa/import-map-deployer/blob/master/examples/ci-for-javascript-repo/travis-digital-ocean-spaces/.travis.yml">single-spa Travis CI example config</a>.</p>
<p>Because we don’t want our AWS secrets exposed in our GitHub repo, we can store those as environment variables. You can place environment variables and their secret values within the Travis CI web console for anything that you want to keep private, so that’s where the <code>.travis.yml</code> file gets those values from.</p>
<p>Now, when we commit and push new code to the master branch, the Travis CI job will run, which will build the JavaScript bundle for the app and then upload those assets to S3. To verify, we can check out the AWS console to see our newly uploaded files:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/mfe8.png" alt="Uploaded files as a result of a Travis CI job" width="600" height="400" loading="lazy">
<em>Uploaded files as a result of a Travis CI job</em></p>
<p>Neat! So far so good. Now we need to implement the same Travis CI configuration for our other three micro-frontend apps, but swapping out the directory names in the <code>.travis.yml</code> file as needed. After following the same steps and merging our code, we now have four directories created in our S3 bucket, one for each repo.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/mfe9.png" alt="Four directories within our S3 bucket" width="600" height="400" loading="lazy">
<em>Four directories within our S3 bucket</em></p>
<h1 id="heading-creating-an-import-map-for-production">Creating an Import Map for Production</h1>
<p>Let’s recap what we’ve done so far. We have four apps, all living in separate GitHub repos. Each repo is set up with Travis CI to run a job when code is merged into the master branch, and that job handles uploading the build artifacts into an S3 bucket. </p>
<p>With all that in one place, there’s still one thing missing: How do these new build artifacts get referenced in our container app? In other words, even though we’re pushing up new JavaScript bundles for our micro-frontends with each new update, the new code isn’t actually used in our container app yet!</p>
<p>If we think back to how we got our app running locally, we used an import map. This import map is simply JSON that tells the container app where each JavaScript bundle can be found. </p>
<p>But, our import map from earlier was specifically used for running the app locally. Now we need to create an import map that will be used in the production environment.</p>
<p>If we look in the <code>single-spa-demo-root-config</code> directory, in the <code>index.ejs</code> file, we see this line:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"systemjs-importmap"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://storage.googleapis.com/react.microfrontends.app/importmap.json"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Opening up that URL in the browser reveals an import map that looks like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"imports"</span>: {
    <span class="hljs-attr">"react"</span>: <span class="hljs-string">"https://cdn.jsdelivr.net/npm/react@16.13.1/umd/react.production.min.js"</span>,
    <span class="hljs-attr">"react-dom"</span>: <span class="hljs-string">"https://cdn.jsdelivr.net/npm/react-dom@16.13.1/umd/react-dom.production.min.js"</span>,
    <span class="hljs-attr">"single-spa"</span>: <span class="hljs-string">"https://cdn.jsdelivr.net/npm/single-spa@5.5.3/lib/system/single-spa.min.js"</span>,
    <span class="hljs-attr">"@react-mf/root-config"</span>: <span class="hljs-string">"https://react.microfrontends.app/root-config/e129469347bb89b7ff74bcbebb53cc0bb4f5e27f/react-mf-root-config.js"</span>,
    <span class="hljs-attr">"@react-mf/navbar"</span>: <span class="hljs-string">"https://react.microfrontends.app/navbar/631442f229de2401a1e7c7835dc7a56f7db606ea/react-mf-navbar.js"</span>,
    <span class="hljs-attr">"@react-mf/styleguide"</span>: <span class="hljs-string">"https://react.microfrontends.app/styleguide/f965d7d74e99f032c27ba464e55051ae519b05dd/react-mf-styleguide.js"</span>,
    <span class="hljs-attr">"@react-mf/people"</span>: <span class="hljs-string">"https://react.microfrontends.app/people/dd205282fbd60b09bb3a937180291f56e300d9db/react-mf-people.js"</span>,
    <span class="hljs-attr">"@react-mf/api"</span>: <span class="hljs-string">"https://react.microfrontends.app/api/2966a1ca7799753466b7f4834ed6b4f2283123c5/react-mf-api.js"</span>,
    <span class="hljs-attr">"@react-mf/planets"</span>: <span class="hljs-string">"https://react.microfrontends.app/planets/5f7fc62b71baeb7a0724d4d214565faedffd8f61/react-mf-planets.js"</span>,
    <span class="hljs-attr">"@react-mf/things"</span>: <span class="hljs-string">"https://react.microfrontends.app/things/7f209a1ed9ac9690835c57a3a8eb59c17114bb1d/react-mf-things.js"</span>,
    <span class="hljs-attr">"rxjs"</span>: <span class="hljs-string">"https://cdn.jsdelivr.net/npm/@esm-bundle/rxjs@6.5.5/system/rxjs.min.js"</span>,
    <span class="hljs-attr">"rxjs/operators"</span>: <span class="hljs-string">"https://cdn.jsdelivr.net/npm/@esm-bundle/rxjs@6.5.5/system/rxjs-operators.min.js"</span>
  }
}
</code></pre>
<p>That import map was the default one provided as an example when we used the CLI to generate our container app. What we need to do now is replace this example import map with an import map that actually references the bundles we’re using.</p>
<p>So, using the original import map as a template, we can create a new file called <code>importmap.json</code>, place it <em>outside of our repos</em> and add JSON that looks like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"imports"</span>: {
    <span class="hljs-attr">"react"</span>: <span class="hljs-string">"https://cdn.jsdelivr.net/npm/react@16.13.0/umd/react.production.min.js"</span>,
    <span class="hljs-attr">"react-dom"</span>: <span class="hljs-string">"https://cdn.jsdelivr.net/npm/react-dom@16.13.0/umd/react-dom.production.min.js"</span>,
    <span class="hljs-attr">"single-spa"</span>: <span class="hljs-string">"https://cdn.jsdelivr.net/npm/single-spa@5.5.1/lib/system/single-spa.min.js"</span>,
    <span class="hljs-attr">"@thawkin3/root-config"</span>: <span class="hljs-string">"https://single-spa-demo.s3-us-west-2.amazonaws.com/%40thawkin3/root-config/179ba4f2ce4d517bf461bee986d1026c34967141/root-config.js"</span>,
    <span class="hljs-attr">"@thawkin3/single-spa-demo-nav"</span>: <span class="hljs-string">"https://single-spa-demo.s3-us-west-2.amazonaws.com/%40thawkin3/single-spa-demo-nav/f0e9d35392ea0da8385f6cd490d6c06577809f16/thawkin3-single-spa-demo-nav.js"</span>,
    <span class="hljs-attr">"@thawkin3/single-spa-demo-page-1"</span>: <span class="hljs-string">"https://single-spa-demo.s3-us-west-2.amazonaws.com/%40thawkin3/single-spa-demo-page-1/4fd417ee3faf575fcc29d17d874e52c15e6f0780/thawkin3-single-spa-demo-page-1.js"</span>,
    <span class="hljs-attr">"@thawkin3/single-spa-demo-page-2"</span>: <span class="hljs-string">"https://single-spa-demo.s3-us-west-2.amazonaws.com/%40thawkin3/single-spa-demo-page-2/8c58a825c1552aab823bcbd5bdd13faf2bd4f9dc/thawkin3-single-spa-demo-page-2.js"</span>
  }
}
</code></pre>
<p>You’ll note that the first three imports are for shared dependencies: react, react-dom, and single-spa. That way we don’t have four copies of React in our app causing bloat and longer download times. Next, we have imports for each of our four apps. The URL is simply the URL for each uploaded file in S3 (called an “object” in AWS terminology).</p>
<p>Now that we have this file created, we can manually upload it to our bucket in S3 through the AWS console. </p>
<p><strong>Note</strong>: This is a pretty important and interesting caveat when using single-spa: The import map doesn’t actually live anywhere in source control or in any of the git repos. That way, the import map can be updated on the fly without requiring checked-in changes in a repo. We’ll come back to this concept in a little bit.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/mfe10.png" alt="Import map manually uploaded to the S3 bucket" width="600" height="400" loading="lazy">
<em>Import map manually uploaded to the S3 bucket</em></p>
<p>Finally, we can now reference this new file in our <code>index.ejs</code> file instead of referencing the original import map.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"systemjs-importmap"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"//single-spa-demo.s3-us-west-2.amazonaws.com/%40thawkin3/importmap.json"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h1 id="heading-creating-a-production-server">Creating a Production Server</h1>
<p>We are getting closer to having something up and running in production! We’re going to host this demo on Heroku, so in order to do that, we’ll need to create a simple Node.js and <a target="_blank" href="https://expressjs.com/">Express</a> server to serve our file.</p>
<p>First, in the <code>single-spa-demo-root-config</code> directory, we'll install express by running <code>yarn add express</code> (or <code>npm install express</code>). Next, we'll add a file called <code>server.js</code> that contains a small amount of code for starting up an express server and serving our main <code>index.html</code> file.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">"path"</span>);
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">5000</span>;

express()
  .use(express.static(path.join(__dirname, <span class="hljs-string">"dist"</span>)))
  .get(<span class="hljs-string">"*"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.sendFile(<span class="hljs-string">"index.html"</span>, { <span class="hljs-attr">root</span>: <span class="hljs-string">"dist"</span> });
  })
  .listen(PORT, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Listening on <span class="hljs-subst">${PORT}</span>`</span>));
</code></pre>
<p>Finally, we’ll update the NPM scripts in our <code>package.json</code> file to differentiate between running the server in development mode and running the server in production mode.</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
  <span class="hljs-attr">"build"</span>: <span class="hljs-string">"webpack --mode=production"</span>,
  <span class="hljs-attr">"lint"</span>: <span class="hljs-string">"eslint src"</span>,
  <span class="hljs-attr">"prettier"</span>: <span class="hljs-string">"prettier --write './**'"</span>,
  <span class="hljs-attr">"start:dev"</span>: <span class="hljs-string">"webpack-dev-server --mode=development --port 9000 --env.isLocal=true"</span>,
  <span class="hljs-attr">"start"</span>: <span class="hljs-string">"node server.js"</span>,
  <span class="hljs-attr">"test"</span>: <span class="hljs-string">"jest"</span>
}
</code></pre>
<h1 id="heading-deploying-to-heroku">Deploying to Heroku</h1>
<p>Now that we have a production server ready, let’s get this thing deployed to Heroku! In order to do so, you’ll need to have a <a target="_blank" href="https://signup.heroku.com/">Heroku account created</a>, the <a target="_blank" href="https://devcenter.heroku.com/articles/heroku-cli">Heroku CLI</a> installed, and be logged in. Deploying to Heroku is as easy as 1–2–3:</p>
<ol>
<li>In the <code>single-spa-demo-root-config</code> directory: <code>heroku create thawkin3-single-spa-demo</code> (changing that last argument to a unique name to be used for your Heroku app)</li>
<li><code>git push heroku master</code></li>
<li><code>heroku open</code></li>
</ol>
<p>And with that, we are up and running in production. Upon running the <code>heroku open</code> command, you should see your app open in your browser. Try navigating between pages using the nav links to see the different micro-frontend apps mount and unmount.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/mfe11.png" alt="Demo app — up and running in production" width="600" height="400" loading="lazy">
<em>Demo app — up and running in production</em></p>
<h1 id="heading-making-updates">Making Updates</h1>
<p>At this point, you may be asking yourself, “All that work for this? Why?” And you’d be right. Sort of. This is a lot of work, and we don’t have much to show for it, at least not visually. But, we’ve laid the groundwork for whatever app improvements we’d like. </p>
<p>The setup cost for any microservice or micro-frontend is often a lot higher than the setup cost for a monolith; it’s not until later that you start to reap the rewards.</p>
<p>So let’s start thinking about future modifications. Let’s say that it’s now five or ten years later, and your app has grown. A lot. And, in that time, a hot new framework has been released, and you’re dying to re-write your entire app using that new framework. </p>
<p>When working with a monolith, this would likely be a years-long effort and may be nearly impossible to accomplish. But, with micro-frontends, you could swap out technologies one piece of the app at a time, allowing you to slowly and smoothly transition to a new tech stack. Magic!</p>
<p>Or, you may have one piece of your app that changes frequently and another piece of your app that is rarely touched. While making updates to the volatile app, wouldn’t it be nice if you could just leave the legacy code alone? </p>
<p>With a monolith, it’s possible that changes you make in one place of your app may affect other sections of your app. What if you modified some stylesheets that multiple sections of the monolith were using? Or what if you updated a dependency that was used in many different places? </p>
<p>With a micro-frontend approach, you can leave those worries behind, refactoring and updating one app where needed while leaving legacy apps alone.</p>
<p>But, how do you make these kinds of updates? Or updates of any sort, really? </p>
<p>Right now we have our production import map in our <code>index.ejs</code> file, but it's just pointing to the file we manually uploaded to our S3 bucket. If we wanted to release some new changes right now, we'd need to push new code for one of the micro-frontends, get a new build artifact, and then manually update the import map with a reference to the new JavaScript bundle.</p>
<p>Is there a way we could automate this? Yes!</p>
<h1 id="heading-updating-one-of-the-apps">Updating One of the Apps</h1>
<p>Let’s say we want to update our page 1 app to have different text showing. In order to automate the deployment of this change, we can update our CI pipeline to not only build an artifact and upload it to our S3 bucket, but to also update the import map to reference the new URL for the latest JavaScript bundle.</p>
<p>Let’s start by updating our <code>.travis.yml</code> file like so:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">language:</span> <span class="hljs-string">node_js</span>
<span class="hljs-attr">node_js:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">node</span>
<span class="hljs-attr">env:</span>
  <span class="hljs-attr">global:</span>
    <span class="hljs-comment"># include $HOME/.local/bin for `aws`</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">PATH=$HOME/.local/bin:$PATH</span>
<span class="hljs-attr">before_install:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">pyenv</span> <span class="hljs-string">global</span> <span class="hljs-number">3.7</span><span class="hljs-number">.1</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">pip</span> <span class="hljs-string">install</span> <span class="hljs-string">-U</span> <span class="hljs-string">pip</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">pip</span> <span class="hljs-string">install</span> <span class="hljs-string">awscli</span>
<span class="hljs-attr">script:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">yarn</span> <span class="hljs-string">build</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">echo</span> <span class="hljs-string">"Commit sha - $TRAVIS_COMMIT"</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">dist/@thawkin3/root-config/$TRAVIS_COMMIT</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">mv</span> <span class="hljs-string">dist/*.*</span> <span class="hljs-string">dist/@thawkin3/root-config/$TRAVIS_COMMIT/</span>
<span class="hljs-attr">deploy:</span>
  <span class="hljs-attr">provider:</span> <span class="hljs-string">s3</span>
  <span class="hljs-attr">access_key_id:</span> <span class="hljs-string">"$AWS_ACCESS_KEY_ID"</span>
  <span class="hljs-attr">secret_access_key:</span> <span class="hljs-string">"$AWS_SECRET_ACCESS_KEY"</span>
  <span class="hljs-attr">bucket:</span> <span class="hljs-string">"single-spa-demo"</span>
  <span class="hljs-attr">region:</span> <span class="hljs-string">"us-west-2"</span>
  <span class="hljs-attr">cache-control:</span> <span class="hljs-string">"max-age=31536000"</span>
  <span class="hljs-attr">acl:</span> <span class="hljs-string">"public_read"</span>
  <span class="hljs-attr">local_dir:</span> <span class="hljs-string">dist</span>
  <span class="hljs-attr">skip_cleanup:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">on:</span>
    <span class="hljs-attr">branch:</span> <span class="hljs-string">master</span>
<span class="hljs-attr">after_deploy:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">chmod</span> <span class="hljs-string">+x</span> <span class="hljs-string">after_deploy.sh</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">"./after_deploy.sh"</span>
</code></pre>
<p>The main changes here are adding a global environment variable, installing the AWS CLI, and adding an <code>after_deploy</code> script as part of the pipeline. This references an <code>after_deploy.sh</code> file that we need to create. The contents will be:</p>
<pre><code class="lang-sh"><span class="hljs-built_in">echo</span> <span class="hljs-string">"Downloading import map from S3"</span>
aws s3 cp s3://single-spa-demo/@thawkin3/importmap.json importmap.json
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Updating import map to point to new version of @thawkin3/root-config"</span>
node update-importmap.mjs
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Uploading new import map to S3"</span>
aws s3 cp importmap.json s3://single-spa-demo/@thawkin3/importmap.json --cache-control <span class="hljs-string">'public, must-revalidate, max-age=0'</span> --acl <span class="hljs-string">'public-read'</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Deployment successful"</span>
</code></pre>
<p>This file downloads the existing import map from S3, modifies it to reference the new build artifact, and then re-uploads the updated import map to S3. To handle the actual updating of the import map file’s contents, we use a custom script that we’ll add in a file called <code>update-importmap.mjs.</code></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Note that this file requires node@13.2.0 or higher (or the --experimental-modules flag)</span>
<span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
<span class="hljs-keyword">import</span> path <span class="hljs-keyword">from</span> <span class="hljs-string">"path"</span>;
<span class="hljs-keyword">import</span> https <span class="hljs-keyword">from</span> <span class="hljs-string">"https"</span>;

<span class="hljs-keyword">const</span> importMapFilePath = path.resolve(process.cwd(), <span class="hljs-string">"importmap.json"</span>);
<span class="hljs-keyword">const</span> importMap = <span class="hljs-built_in">JSON</span>.parse(fs.readFileSync(importMapFilePath));
<span class="hljs-keyword">const</span> url = <span class="hljs-string">`https://single-spa-demo.s3-us-west-2.amazonaws.com/%40thawkin3/root-config/<span class="hljs-subst">${process.env.TRAVIS_COMMIT}</span>/root-config.js`</span>;

https
  .get(url, <span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
    <span class="hljs-comment">// HTTP redirects (301, 302, etc) not currently supported, but could be added</span>
    <span class="hljs-keyword">if</span> (res.statusCode &gt;= <span class="hljs-number">200</span> &amp;&amp; res.statusCode &lt; <span class="hljs-number">300</span>) {
      <span class="hljs-keyword">if</span> (
        res.headers[<span class="hljs-string">"content-type"</span>] &amp;&amp;
        res.headers[<span class="hljs-string">"content-type"</span>].toLowerCase().trim() ===
          <span class="hljs-string">"application/javascript"</span>
      ) {
        <span class="hljs-keyword">const</span> moduleName = <span class="hljs-string">`@thawkin3/root-config`</span>;
        importMap.imports[moduleName] = url;
        fs.writeFileSync(importMapFilePath, <span class="hljs-built_in">JSON</span>.stringify(importMap, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>));
        <span class="hljs-built_in">console</span>.log(
          <span class="hljs-string">`Updated import map for module <span class="hljs-subst">${moduleName}</span>. New url is <span class="hljs-subst">${url}</span>.`</span>
        );
      } <span class="hljs-keyword">else</span> {
        urlNotDownloadable(
          url,
          <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Content-Type response header must be application/javascript`</span>)
        );
      }
    } <span class="hljs-keyword">else</span> {
      urlNotDownloadable(
        url,
        <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP response status was <span class="hljs-subst">${res.statusCode}</span>`</span>)
      );
    }
  })
  .on(<span class="hljs-string">"error"</span>, <span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {
    urlNotDownloadable(url, err);
  });

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">urlNotDownloadable</span>(<span class="hljs-params">url, err</span>) </span>{
  <span class="hljs-keyword">throw</span> <span class="hljs-built_in">Error</span>(
    <span class="hljs-string">`Refusing to update import map - could not download javascript file at url <span class="hljs-subst">${url}</span>. Error was '<span class="hljs-subst">${err.message}</span>'`</span>
  );
}
</code></pre>
<p>Note that we need to make these changes for these three files in all of our GitHub repos so that each one is able to update the import map after creating a new build artifact. </p>
<p>The file contents will be nearly identical for each repo, but we’ll need to change the app names or URL paths to the appropriate values for each one.</p>
<h3 id="heading-a-side-note-on-the-import-map">A Side Note on the Import Map</h3>
<p>Earlier I mentioned that the import map file we manually uploaded to S3 doesn’t actually live anywhere in any of our GitHub repos or in any of our checked-in code. If you’re like me, this probably seems really odd! Shouldn’t everything be in source control?</p>
<p>The reason it’s not in source control is so that our CI pipeline can handle updating the import map with each new micro-frontend app release. </p>
<p>If the import map were in source control, making an update to one micro-frontend app would require changes in two repos: the micro-frontend app repo where the change is made, and the root config repo where the import map would be checked in. This sort of setup would invalidate one of micro-frontend architecture’s main benefits, which is that each app can be deployed completely independent of the other apps. </p>
<p>In order to achieve some level of source control on the import map, we can always use S3’s versioning feature for our bucket.</p>
<h1 id="heading-moment-of-truth">Moment of Truth</h1>
<p>With those modifications to our CI pipelines in place, it’s time for the final moment of truth: Can we update one of our micro-frontend apps, deploy it independently, and then see those changes take effect in production without having to touch any of our other apps?</p>
<p>In the <code>single-spa-demo-page-1</code> directory, in the <code>root.component.js</code> file, let's change the text from "Page 1 App" to "Page 1 App - UPDATED!" Next, let's commit that change and push and merge it to master. </p>
<p>This will kick off the Travis CI pipeline to build the new page 1 app artifact and then update the import map to reference that new file URL.</p>
<p>If we then navigate in our browser to <a target="_blank" href="https://thawkin3-single-spa-demo.herokuapp.com/page1">https://thawkin3-single-spa-demo.herokuapp.com/page1</a>, we’ll now see… drum roll please… our updated app!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/mfe12.png" alt="Demo app — successfully updating one of the micro-frontend apps" width="600" height="400" loading="lazy">
<em>Demo app — successfully updating one of the micro-frontend apps</em></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>I said it before, and I’ll say it again: <strong>Micro-frontends are the future of frontend web development.</strong> </p>
<p>The benefits are massive, including independent deployments, independent areas of ownership, faster build and test times, and the ability to mix and match various frameworks if needed. </p>
<p>There are some drawbacks, such as the initial set up cost and the complexity of maintaining a distributed architecture, but I strongly believe the benefits outweigh the costs.</p>
<p>Single-spa makes micro-frontend architecture easy. Now you, too, can go break up the monolith!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to automate deployment on GitHub-pages with Travis CI ]]>
                </title>
                <description>
                    <![CDATA[ By Dhruv Barochiya Disclaimer: This story is not sponsored by any of the tools that has been described into the article (Travis-CI, Github, Github-Pages) You have created a project in React.js and deployed it on the GitHub-pages (not yet ?? — creat... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-how-to-automate-deployment-on-github-pages-with-travis-ci/</link>
                <guid isPermaLink="false">66d45e3f182810487e0ce145</guid>
                
                    <category>
                        <![CDATA[ automation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Devops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Travis CI ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 21 Jun 2019 16:18:58 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/06/Druhv-article-image.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dhruv Barochiya</p>
<blockquote>
<p>Disclaimer: This story is not sponsored by any of the tools that has been described into the article (Travis-CI, Github, Github-Pages)</p>
</blockquote>
<p>You have created a project in React.js and deployed it on the GitHub-pages (not yet ?? — <a target="_blank" href="https://medium.com/free-code-camp/portfolio-app-using-react-618814e35843">create your first project in React.js</a>) But what if you are making frequent changes into the code base and also want to keep the deployed version updated to the latest ? … You will find yourself in the tedious process of running the deployment scripts again and again !!!</p>
<blockquote>
<p>What if the deployment process can be automated ??</p>
</blockquote>
<p>After some quick google search session, I found that it is possible and can be achieved by Travis CI — an open source tool can be used to automate the deployment of various types of projects.</p>
<h2 id="heading-what-you-will-learn-gt">What you will learn &gt;</h2>
<p>In this article, you will be able to learn how to implement the system which will trigger the react deployment scripts using the TRAVIS-CI to deploy the project onto the GitHub-pages whenever there are any changes found in the master branch of the code repository.</p>
<ul>
<li>Setup Automated deployment of <strong>‘</strong><a target="_blank" href="https://medium.com/free-code-camp/portfolio-app-using-react-618814e35843"><strong>react-portfolio’</strong></a> project</li>
<li>Learn about some frequent errors encountered while the process</li>
<li>Learn about some concepts related to ‘<strong>continuous deployment’</strong></li>
</ul>
<h2 id="heading-lets-learn-some-fundamentals">Let’s learn some fundamentals</h2>
<blockquote>
<p>Skip this section if you know you are not that type !!</p>
</blockquote>
<h3 id="heading-continuous-integrationci-amp-continuous-deliverycd-gt">Continuous Integration(CI) &amp; Continuous Delivery(CD) &gt;</h3>
<blockquote>
<p>“In <a target="_blank" href="https://en.wikipedia.org/wiki/Software_engineering">software engineering</a>, continuous integration (CI) is the practice of merging all developers’ working copies to a shared <a target="_blank" href="https://en.wikipedia.org/wiki/Trunk_%28software%29">mainline</a> several times a day” — <a target="_blank" href="https://en.wikipedia.org/wiki/Continuous_integration">wikipedia</a></p>
</blockquote>
<p>In other words, the developers will try to merge their feature code into the master branch as frequent as possible. Following this practice enables the developers and product managers to release the product more frequently.</p>
<p>There are some extended versions of the CI pipelines in which these changes are also being tested automatically which makes the code deployable at any time, it’s called <strong>‘Continuous Delivery</strong>’. A further extension of this pipeline is called <strong>‘Continuous Deployment’</strong> pipeline, where these tested code changes are pushed automatically into the production servers. ( We will be implementing the continuous deployment pipeline in our case)</p>
<h3 id="heading-travis-ci-gt">Travis CI &gt;</h3>
<p><strong>Travis CI</strong> is a hosted continuous integration service used to build and test software projects hosted at GitHub. Open source projects can be tested without any charges !!</p>
<p>Travis CI can be configured by adding a <code>.travis.yml</code> file to the repository. when Travis CI has been activated for a given repository, GitHub will notify whenever new commits are pushed to the repository or any pull request is submitted then according to the rules defined in the <code>.travis.yml</code> file, Travis CI will perform the steps which can be anything — from running tests, building the application or deployment scripts. Travis CI offers a wide range of options to build the software and of course, our beloved ❤️<code>javascript</code> is one of them.</p>
<blockquote>
<p><strong>NOTE<em>:</em></strong> <em>Github has</em> <a target="_blank" href="https://education.github.com/pack"><strong><em>student developer pack</em></strong></a> <em>available with a bunch of premium features from different platforms (Travis CI is one of them) for free to students who wish to learn new things — get your student pack now !!</em></p>
</blockquote>
<h3 id="heading-devops-gt">DevOps &gt;</h3>
<p><strong>DevOps</strong> is a set of software development practices that combines <a target="_blank" href="https://en.wikipedia.org/wiki/Software_development">software development</a> (<em>Dev</em>) and <a target="_blank" href="https://en.wikipedia.org/wiki/Information_technology_operations">information technology operations</a>(<em>Ops</em>) to shorten the <a target="_blank" href="https://en.wikipedia.org/wiki/Systems_development_life_cycle">systems development life cycle</a> while <a target="_blank" href="https://en.wikipedia.org/wiki/Continuous_delivery">delivering features, fixes, and updates</a> frequently. The concept of DevOps is founded on building a culture of collaboration between teams.</p>
<blockquote>
<p>“DevOps is more than practice — it’s about culture”</p>
</blockquote>
<p>Continuous Integration, Continuous Delivery, Continuous Deployment are some of the few key practices of the DevOps. Apart from these DevOps engineers heavily uses the power of the cloud infrastructure to make the deployment process seamless.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*9pVLG4BzEWIcMnfhFp9ULQ.png" alt="Image" width="1600" height="823" loading="lazy"></p>
<hr>
<h2 id="heading-enough-talking-lets-do-some-action">Enough talking !!! Let’s do some action</h2>
<p>As you have already deployed on the GitHub pages using the <code>gh-pages</code> node module, there will be a branch called <code>gh-pages</code>on the repository which holds the files which are deployed onto the Github pages servers. After the integration of the Travis CI, we would ab able to implement the system where any changes made by the user on the <code>master</code> branch will automatically trigger a build. If the build is successful, then the build scripts will be triggered which will update the <code>gh-pages</code> branch. User will be notified about the status of the build via email notifications from the Travis CI</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*athThq_0-5cg1foDqt0v5w.png" alt="Image" width="1052" height="744" loading="lazy"></p>
<h3 id="heading-create-an-account-on-travis-ci-gt">Create an account on Travis-CI &gt;</h3>
<ul>
<li>Go to <a target="_blank" href="https://travis-ci.com/">Travis-ci.com</a> and <a target="_blank" href="https://travis-ci.com/signin"><em>Sign up with GitHub</em></a>.</li>
<li>Accept the terms &amp; conditions of Travis CI. You’ll be redirected to GitHub.</li>
<li>Click the <em>Activate</em> button, and select the repositories you want to use with Travis CI.</li>
<li>Add authorization token ( This will be done automatically when you sign-in with GitHub)</li>
</ul>
<h3 id="heading-add-travisyml-file-into-the-repository-gt">Add travis.yml file into the repository &gt;</h3>
<p>This file contains the instructions which tell Travis-CI — what?..how?..when?</p>
<blockquote>
<p><strong>NOTE</strong>: When you trigger a job in the Travis-CI, it will boot up a virtual machine with the appropriate deployment environment configured in the <code>_.travis.yml_</code></p>
</blockquote>
<p>Let’s break down the code —</p>
<pre><code class="lang-yml"><span class="hljs-attr">language:</span> <span class="hljs-string">node_js</span>
<span class="hljs-attr">node_js:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">"stable"</span>
<span class="hljs-attr">cache:</span>
  <span class="hljs-attr">directories:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">node_modules</span>
<span class="hljs-attr">script:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span>
<span class="hljs-attr">deploy:</span>
  <span class="hljs-attr">provider:</span> <span class="hljs-string">pages</span>
  <span class="hljs-attr">skip_cleanup:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">github_token:</span> <span class="hljs-string">$github_token</span>
  <span class="hljs-attr">local_dir:</span> <span class="hljs-string">build</span>
  <span class="hljs-attr">on:</span>
    <span class="hljs-attr">branch:</span> <span class="hljs-string">master</span>
</code></pre>
<p><code>on</code> : Travis-CI will automatically trigger a job whenever there are some changes made on the branch specified in this field.</p>
<p><code>deploy</code> : In this filed we have declared that we will use the deployment <a target="_blank" href="https://docs.travis-ci.com/user/deployment/pages/">provider for the GitHub pages</a> provided by the Travis-CI which is nothing but the configuration instructions for setting up the environment for deployment.</p>
<p><code>script</code> : This filed contains the build scripts which will be executed while running the job. For this case that is the build script, you can also add test scrips ( code-coverage, fusion test, etc.) before the build.</p>
<p><code>cache</code> : Travis-CI provides an option to cache the library files and modules which will be the constant for all the builds. Cached files can be used again by the later build jobs which decreases the end-to-end running time of the job.</p>
<h2 id="heading-all-set-gt">All set &gt;</h2>
<p>Ohkay everything is in the place, now onwards if you commit anything on the master branch it will trigger a Travis-CI build job which will look something like in the below screenshots. You can also trigger a build manually from the Travis-CI dashboard itself.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*W34g38dx2jy5wxP4yS5y3w.png" alt="Image" width="1600" height="649" loading="lazy">
<em>Travis-CI job(Running)</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*V6MOHQiV2agPnAtfo6Wyjw.png" alt="Image" width="1600" height="558" loading="lazy">
<em>Travis-CI job (successful)</em></p>
<h2 id="heading-but-there-is-always-a-but-huh">But …. (there is always a but !! huh!!)</h2>
<p>I am pretty sure your build dashboard will not look like the above one same as life has not been smooth we were told it would be ?. There can be infinite reasons due to which your Travis-CI dashboard is full of failed builds ( I know..I have been through this)</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*xoGfeAu4sb-_l7ggTbjC7Q.png" alt="Image" width="1600" height="591" loading="lazy"></p>
<p>This is the time when your most valuable “googling” skills will come handy. I will explain what all are the errors I have faced while I was trying to create a pipeline.</p>
<ul>
<li>Security errors</li>
<li>Token errors</li>
<li>Just random errors (You have to get dirty &amp; find the solution!!)</li>
</ul>
<h3 id="heading-token-errors-gt">Token errors &gt;</h3>
<p>If your builds are failing due permissions error then there are high chances that there is some <a target="_blank" href="https://docs.travis-ci.com/user/deployment/pages/#setting-the-github-token">problem with tokens</a>. You need to go to the token URL <a target="_blank" href="https://github.com/settings/tokens">https://github.com/settings/tokens</a> and see when it was used lately, if it shows <strong><em>never</em></strong> then you have found your culprit.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*9NrQnLn0Mrp7Oex9H_F-Og.png" alt="Image" width="1600" height="479" loading="lazy"></p>
<p>Follow the below steps,</p>
<ul>
<li>Delete and create a new token</li>
<li>Add it to the Travis environment variables ( Go to job settings )</li>
<li>Re-try the build</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*5CtnigPrV0L3ylole9kvVw.png" alt="Image" width="1600" height="966" loading="lazy"></p>
<h3 id="heading-security-errors-gt">Security errors &gt;</h3>
<p>There are plenty of security practices we ignore while coding &amp; building web applications. When we run in local these security errors are not given much emphasis and often discarded as warning messages, but when we are trying to deploy the service using the Travis-CI these warnings will cause the build failure.</p>
<p>I will mention the errors I encountered while working on my project(I would encourage you to mention the errors you have encountered) The great thing is that most of them have their own dedicated web-pages which explain the underlying problem and offers the solutions/workarounds ( Workarounds — we all love it even knowing that we shouldn’t !! )</p>
<ul>
<li><strong>Using target=_blank in HTML  tag :</strong> This is more serious security flaw than it looks. You can learn more about it <a target="_blank" href="https://mathiasbynens.github.io/rel-noopener/">here.</a></li>
<li><strong>Redundancy in HTML code</strong>: There were many redundant tags/class names which were making the code look like junk.</li>
</ul>
<p>Best way to prevent these errors is to install the <code>es-lint</code> plug-in in whichever text-editor you are using.</p>
<hr>
<h2 id="heading-built-some-project-share-it">Built some project? — Share it</h2>
<p>I am trying to build a community of developers where people can share their ideas, knowledge, work with others and find other people with similar ideology to build things together. So, if you built some project and want to share it, post it on the channel.</p>
<ul>
<li>Gitter channel: <a target="_blank" href="https://gitter.im/weekend-devs/community">https://gitter.im/weekend-devs/community</a></li>
<li>Github Organization: <a target="_blank" href="https://github.com/weekend-developers">https://github.com/weekend-developers</a></li>
</ul>
<hr>
<h2 id="heading-wrapping-up">Wrapping up</h2>
<p>I would like to take a moment to acknowledge the work of the people who gave me the inspiration and knowledge to complete this article.</p>
<ul>
<li><strong>Travis CI community:</strong> for providing awesome tools for free.</li>
<li><strong><em>My dearest friends:</em></strong> who helped me in correcting my mistakes.</li>
<li><strong>YOU:</strong> for sticking around, I hope you had a productive time. Keep exploring and building amazing things!</li>
</ul>
<hr>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*vNXcdsgZAeulGy1r" alt="Image" width="1600" height="1066" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@clemensvanlay?utm_source=medium&amp;utm_medium=referral" data-href="https://unsplash.com/@clemensvanlay?utm_source=medium&amp;utm_medium=referral" class="markup--anchor markup--figure-anchor" rel="photo-creator noopener noopener noopener" target="_blank"&gt;Clemens van Lay on &lt;a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral" data-href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral" class="markup--anchor markup--figure-anchor" rel="photo-source noopener noopener noopener" target="<em>blank)</em></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
