<?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" version="2.0"><channel><title><![CDATA[Dev Log by Michael Leners]]></title><description><![CDATA[Former physics instructor, recovering engineer, graduate student, Washington native, and "Iowa Captive". I love web development and am especially passionate abo]]></description><link>https://blog.micleners.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1607475477508/xwLHJQEDC.png</url><title>Dev Log by Michael Leners</title><link>https://blog.micleners.com</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 12 Oct 2026 21:48:14 GMT</lastBuildDate><atom:link href="https://blog.micleners.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Docker Command Bonus: Dockerizing React Apps]]></title><description><![CDATA[In a previous post on Dockerizing React Apps, I discussed a strategy for running React in a Docker container.
In the scripts, I put local-react as the image tag. You'll soon find out trying to use the same tag on all your containers is not the greate...]]></description><link>https://blog.micleners.com/docker-command-bonus-dockerizing-react-apps</link><guid isPermaLink="true">https://blog.micleners.com/docker-command-bonus-dockerizing-react-apps</guid><category><![CDATA[2Articles1Week]]></category><category><![CDATA[React]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Michael Leners]]></dc:creator><pubDate>Tue, 29 Dec 2020 02:41:27 GMT</pubDate><content:encoded><![CDATA[<p>In a previous post on <a target="_blank" href="https://blog.micleners.com/dockerizing-react-apps">Dockerizing React Apps</a>, I discussed a strategy for running React in a Docker container.</p>
<p>In the scripts, I put <code>local-react</code> as the image tag. You'll soon find out trying to use the same tag on all your containers is not the greatest idea!</p>
<p>For my local projects, I swap out <code>local-react</code> with <code>${PWD##*/}</code>. This says "get the folder name". This way, not all my images are tagged the same, they are tagged with the folder they are contained in. This is typically the name of the project and is a great starter tag for the image. Sweet!</p>
<p>So, the new commands will look like the following:</p>
<p>To build:</p>
<pre><code class="lang-docker">docker build . -t ${PWD##*/}
</code></pre>
<p>To run:</p>
<pre><code class="lang-docker">docker run \
  -it \
  --rm \
  -v ${PWD}:/app \
  -v /app/node_modules \
  -p 3000:3000 \
  ${PWD##*/}
</code></pre>
<p>Happy programming!!</p>
]]></content:encoded></item><item><title><![CDATA[Conditional Rendering of Components in React]]></title><description><![CDATA[I've been working through the Epic React course from Kent C. Dodd over this holiday season 🎄
It's interesting seeing how I code things while I "try it out", then compare it to how Kent codes things in his solutions. One difference I wanted to share ...]]></description><link>https://blog.micleners.com/conditional-rendering-of-components-in-react</link><guid isPermaLink="true">https://blog.micleners.com/conditional-rendering-of-components-in-react</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><category><![CDATA[logic]]></category><category><![CDATA[learning]]></category><dc:creator><![CDATA[Michael Leners]]></dc:creator><pubDate>Sat, 26 Dec 2020 21:52:12 GMT</pubDate><content:encoded><![CDATA[<p>I've been working through the <a target="_blank" href="https://epicreact.dev/learn/">Epic React</a> course from <a target="_blank" href="http://kentcdodds.com/">Kent C. Dodd</a> over this holiday season 🎄</p>
<p>It's interesting seeing how I code things while I "try it out", then compare it to how Kent codes things in his solutions. One difference I wanted to share was around methods to conditionally rendering within components.</p>
<p>Let's imagine we have a component that allows you to search for pokemon. It has the following states:</p>
<ul>
<li>Idle upon arrival to the page</li>
<li>Pending after submitting a search</li>
<li>A results view if proper data is returned</li>
<li>An error view if something goes wrong</li>
</ul>
<p>We can use conditional rendering to display different content depending on what state the page is in. </p>
<h2 id="pseudocode-example">Pseudocode Example</h2>
<p>The skeleton below shows the `state passed into the component and the four different resulting states that are expected.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ConditionallyRendered = <span class="hljs-function">(<span class="hljs-params">{ state }</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            {/* Display idle state when first loaded (state is "idle") */}
            {/* Display pending message if waiting for response (state is "pending") */}
            {/* Display the Pokemon if successfully received (state is "resolved") */}
            {/* Display an Error Message if there's an error (state is "rejected") */}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
};
</code></pre>
<p>Let's first take a look at rendering different JSX depending on the states.</p>
<h2 id="approach-1-javascript-rendering-different-jsx">Approach 1: JavaScript Rendering Different JSX</h2>
<p>Here, outside of the <code>return (&lt;jsx/&gt;)</code> block, we use an <code>if/else</code> statement to decide what to render.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ConditionallyRendered = <span class="hljs-function">(<span class="hljs-params">{ state }</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (state === <span class="hljs-string">"idle"</span>) {
        <span class="hljs-comment">// Display idle state when first loaded.</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Submit a pokemon"</span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (state === <span class="hljs-string">"pending"</span>) {
        <span class="hljs-comment">// Display pending message if waiting for response.</span>
        <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">PokemonInfoFallback</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{pokemonName}</span> /&gt;</span></span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (state === <span class="hljs-string">"resolved"</span>) {
        <span class="hljs-comment">// Display the Pokemon if successfully received.</span>
        <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">PokemonDataView</span> <span class="hljs-attr">pokemon</span>=<span class="hljs-string">{pokemon}</span> /&gt;</span></span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (state === <span class="hljs-string">"rejected"</span>) {
        <span class="hljs-comment">// Display an Error Message if there's an error.</span>
        <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ErrorMessage</span> <span class="hljs-attr">error</span>=<span class="hljs-string">{error}</span> /&gt;</span></span>;
    }
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};
</code></pre>
<p>You could easily use a <code>case/switch</code> statement if you'd prefer.</p>
<p>The alternative I will show <em>sounds</em> like a similar method, but there is a nuanced difference.</p>
<h2 id="approach-2-javascript-in-jsx-rendering-different-jsx">Approach 2: JavaScript in JSX Rendering Different JSX</h2>
<p>Here we jump right into JSX, then we drop into JavaScript and use some simple logic to decide what to render.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ConditionallyRendered = <span class="hljs-function">(<span class="hljs-params">{ state }</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
            {/* Display idle state when first loaded. */}
            {state === states.idle &amp;&amp; "Submit a pokemon"}
            {/* Display pending message if waiting for response. */}
            {state === states.pending &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">PokemonInfoFallback</span> <span class="hljs-attr">pokemon</span>=<span class="hljs-string">{pokemon}</span> /&gt;</span>}
            {/* Display the Pokemon if successfully received. */}
            {state === states.resolved &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">PokemonDataView</span> <span class="hljs-attr">pokemon</span>=<span class="hljs-string">{pokemon}</span> /&gt;</span>}
            {/* Display an Error Message if there's an error. */}
            {state === states.rejected &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">ErrorMessage</span> <span class="hljs-attr">error</span>=<span class="hljs-string">{error}</span> /&gt;</span>}
        <span class="hljs-tag">&lt;/&gt;</span></span>
    );
};
</code></pre>
<p>It's a bit weird when you first see it. We are taking advantage of the fact that <code>cond1 &amp;&amp; cond2</code> will stop evaluating at the <code>&amp;&amp;</code> if <code>cond1</code> is <code>falsy</code>. That means <code>cond2</code> will never be reached. In our case, the JSX will not be rendered.</p>
<p>In the case that <code>cond1</code> is <code>truthy</code>, <code>cond2</code> will be evaluated. In our case, the JSX will be rendered.</p>
<h2 id="pros-and-cons">Pros and Cons</h2>
<p>While I like the cleaner look to <code>Appoach 2</code>, if you think about it, there's a potential buggy state we could achieve with that.</p>
<ul>
<li>Using an <code>if/then</code> statement like in <code>Appoach 1</code>, <strong>one and only one</strong> <code>return (&lt;jsx/&gt;)</code> block will be reached.</li>
<li>Using the <code>&amp;&amp;</code> login in <code>Approach 1</code>, depending on the logic to the left of <code>&amp;&amp;</code> (called <code>cond1</code>), you could accidentally render two different states.</li>
</ul>
<p>Maybe this is a pro for you though. Perhaps you want to be able to render any number of states depending on complex conditioning. In this case <code>Approach 2</code> is definitely the way to go.</p>
<p>Another reason to go with <code>Approach 2</code> is if there is content you want on the page regardless of the state (a title, the data, etc). If you want this, you'll want to extract these conditional states into separate components to use <code>Approach 1</code>.</p>
<p>However, in the example we are looking at here, we only want one state to show at a time and there is no other content displayed in the component. This makes it a good candidate for <code>Approach 2</code></p>
<h2 id="conclusion">Conclusion</h2>
<p>So, between Kent and I, who chose <code>Approach 1</code> and who chose <code>Approach 2</code> in the ` <a target="_blank" href="https://epicreact.dev/learn/">Epic React</a> course? Hopefully, I keps an unbiased approach while writing this article and you'll just need to buy his course to find out! 😜</p>
]]></content:encoded></item><item><title><![CDATA[JavaScript Promises: Alternative to then/catch]]></title><description><![CDATA[I promise this won't be a long blog, but no guarantees against puns 😜
The promise is a prominent way to deal with asynchronous code in JavaScript. Many APIs return asyncronousely and use the promise as a return value. The promise is to return data o...]]></description><link>https://blog.micleners.com/javascript-promises-alternative-to-then-catch</link><guid isPermaLink="true">https://blog.micleners.com/javascript-promises-alternative-to-then-catch</guid><category><![CDATA[2Articles1Week]]></category><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[promises]]></category><dc:creator><![CDATA[Michael Leners]]></dc:creator><pubDate>Sun, 20 Dec 2020 16:52:10 GMT</pubDate><content:encoded><![CDATA[<p>I <em>promise</em> this won't be a long blog, but no guarantees against puns 😜</p>
<p>The <code>promise</code> is a prominent way to deal with asynchronous code in JavaScript. Many APIs return asyncronousely and use the <code>promise</code> as a return value. The <code>promise</code> is to return data once it's ready. </p>
<p>You can either <code>await</code> on the promise to be fulfilled or chain a <code>.then()</code> to tell JavaScript what to do once the promise is fulfilled. Let's consider a method <code>fetchPokemon()</code> that returns a <code>promise</code> that fulfills with <code>pokemonData</code>.</p>
<h2 id="handling-promises">Handling Promises</h2>
<p>Here are two general examples of handling promises in javascript.</p>
<ol>
<li><p>Using <code>async/await</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> pokemonData = <span class="hljs-keyword">await</span> fetchPokemon(pokemonName)
setPokemon(pokemonData)
</code></pre>
</li>
<li><p>Using <code>.then()</code> chain notation</p>
<pre><code class="lang-javascript">fetchPokemon(pokemonName)
 .then(<span class="hljs-function"><span class="hljs-params">pokemonData</span> =&gt;</span> setPokemon(pokemonData))
</code></pre>
</li>
</ol>
<p><strong>Note</strong>: To use <code>async/await</code> you will need this code to run in an asynchronous function.</p>
<h2 id="error-handling">Error Handling</h2>
<p>We can't forget about error handling! Here is how to error handle with both approaches.</p>
<ol>
<li><p>Using async/await</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">try</span> {
 <span class="hljs-keyword">const</span> pokemonData = <span class="hljs-keyword">await</span> fetchPokemon(pokemonName)
 setPokemon(pokemonData)
}
<span class="hljs-keyword">catch</span> (error) {
 setError(error)
}
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'completed'</span>)
</code></pre>
</li>
<li><p>Using .then() chain notation</p>
<pre><code class="lang-javascript">fetchPokemon(pokemonName)
 .then(<span class="hljs-function"><span class="hljs-params">pokemonData</span> =&gt;</span> setPokemon(pokemonData))
 .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> setError(error))
 .finally(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'completed'</span>))
</code></pre>
</li>
</ol>
<p>Depending on the circumstance, folks prefer one versus the other. With <code>async/await</code> the flow of code is more similar to synchronous code flow. </p>
<p>However, some prefer the chaining syntax for simple circumstances - especially in the <code>useEffect</code> hook in react.</p>
<h2 id="alternative-to-thencatch">Alternative to then/catch</h2>
<p>Did you know that the <code>.then()</code> can take two parameters? If you supply the second parameter, it will specify what the code should do when there is an error. This way, you no longer need to provide a <code>.catch()</code> chain.</p>
<p>Here's the <code>.then()</code> example from above update:</p>
<pre><code class="lang-javascript">fetchPokemon(pokemonName)
    .then(
        <span class="hljs-function"><span class="hljs-params">pokemonData</span> =&gt;</span> setPokemon(pokemonData),
        <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> setError(error),
    )
    .finally(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'completed'</span>))
</code></pre>
<p>This is especially nice for simple one-line arrow functions like the ones shown here. Try it out and let me know what you think!</p>
]]></content:encoded></item><item><title><![CDATA[How My Team Uses Cypress for End-to-End Testing]]></title><description><![CDATA[This blog is part of a series on end-to-end (E2E) testing in Cypress. In this post, we will take a look at how our team uses Cypress to benefit our workflow and increase the safety in which we deploy new features. This information is available in thi...]]></description><link>https://blog.micleners.com/how-my-team-uses-cypress-for-end-to-end-testing</link><guid isPermaLink="true">https://blog.micleners.com/how-my-team-uses-cypress-for-end-to-end-testing</guid><category><![CDATA[2Articles1Week]]></category><category><![CDATA[Angular]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[Testing]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Michael Leners]]></dc:creator><pubDate>Thu, 17 Dec 2020 14:02:04 GMT</pubDate><content:encoded><![CDATA[<p>This blog is part of a series on end-to-end (E2E) testing in Cypress. In this post, we will take a look at how our team uses Cypress to benefit our workflow and increase the safety in which we deploy new features. This information is available in <a target="_blank" href="https://cypress-retro.micleners.com/">this presentation</a> I give on the topic. You can also check out a demo application with Cypress in <a target="_blank" href="http://github.com/micleners/cypress-cotd">this repo</a>.</p>
<h2 id="what-is-cypress">What is Cypress?</h2>
<p><a target="_blank" href="https://www.cypress.io/features">Cypress</a> is "fast, easy and reliable testing for anything that runs in a browser". It is batteries included so it comes fully baked-in tons of features and perks. It is also open-source, has a strong user community, and great documentation.</p>
<p>Cypress accesses the application via the browser, therefore it is most suitable for end-to-end (E2E) acceptance tests or user interface (UI) tests. Cypress can be used to unit test your components with some home-brewing. Cypress also allows for full-on traffic control of API calls, so it can also be used for API testing.</p>
<h2 id="levels-of-our-application-that-cypress-tests">Levels of Our Application that Cypress Tests</h2>
<p>Our team uses Angular, which comes with Jasmine/Karma for unit testing and Protractor for E2E tests. We chose to replace the former with Jest since our team had more experience with it. We chose not to use Protractor because of past experiences with Selenium testing.</p>
<p><a target="_blank" href="https://angular.io/guide/testing#testing-services-with-the-testbed">TestBed</a> is the Angular testing way to set up the modules, providers, and child components necessary to shallow mount a component. It is necessary in order to do any UI testing on a unit test level. We did not enjoy the developer experience that TestBed provides for UI testing. It was difficult to set up (see code block below) and cumbersome to interact with the document object model (DOM - the term used for the outline of HTML elements on a webpage).</p>
<p>We use Jest to unit test our components. Instead of doing these tests with TestBed, we reserved Jest unit testing for TypeScript logic only. This means any logic around function calls and flags were tested, but their connection to the template or DOM was not at this level. This is where we leveraged Cypress tests</p>
<h2 id="our-team-workflow">Our Team Workflow</h2>
<p>The tech ecosystem regarding QA requirements and dynamics is complex. Every team or project will vary in their approach as they all have unique needs. QA can be embedded on a team or separated as a different group. Developers can write automated tests or QA automation engineers can. Below is the workflow that our team uses.</p>
<p>A quality assurance (QA) team member writes test cases and manually tests, while our developers write automated tests. We’ve found that writing E2E tests have bolstered communication on our team, particularly tightening our dev-to-QA feedback loop.</p>
<p>At the beginning of each story, developers and testing come together to whiteboard a story around acceptance criteria. If needed, developers will have a separate technical implementation whiteboarding session to further refine their approach.</p>
<p>When the developers are wrapping up feature work, they meet again with QA to discuss what was implemented. At this point, test cases have been written, are refined, and the developers and QA can decide which E2E test cases should be automated via Cypress.</p>
<p>Even if test cases are automated, at feature implementation QA still rigorously manually tests them. They also check the effectiveness of the Cypress tests against their manual testing for a given case. From that point, the tests are marked as “automated” and Cypress can act as our regression test suite. This allows us to focus on smoke and exploratory testing, rather than redoing tedious and manual regression testing.</p>
<h3 id="integration-with-build-and-deploys-working-towards-cicd">Integration with Build and Deploys (working towards CI/CD)</h3>
<p>Let’s get some definitions set out around builds and deploys, as it can be a bit technical and confusing! First, for those that don’t know, CI/CD continuous integration/continuous deployment. This refers to the practice of getting code into master and deployed to your environments faster and in smaller chunks.</p>
<p>I will refer to a <strong>build or build artifact</strong> as the code that is going to be released to an environment. The release process involves deploying code, therefore another term for a release is a <strong>deploy</strong>. Both a build and a release have the possibility to fail (red) or pass (green). <strong>Failing</strong> means that the next step will not be performed.</p>
<p>The deploy process releases a build to an <strong>environment</strong>. An environment consists of a group of resources that are required to run an instance of our digital application (distinct URL, database, API server, UI server, functions, etc). The five environments we deploy to builds are DEV, TEST, AUTO, STAGE, and PROD. <strong>DEV</strong> is for developers to check their work, <strong>TEST</strong> is for QA, <strong>AUTO</strong> is for our E2E tests, <strong>STAGE</strong> is for our business users, and <strong>PROD</strong> is for our customers to use.</p>
<p>Our deploy process as it pertains to Cypress is that we run Cypress tests on deploy to AUTO. The tests are required to pass in AUTO (green) in order to go to STAGE. You can see the details of this in the figure below and in the text that follows:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1608213306401/rLUvYdulK.png" alt="diagram of our build and deploy process" /></p>
<p>When we create a <strong>pull request</strong> (PR) to master, we are requesting new code to be merged and deployed. At this point, a build happens. As part of our build process, before any releases happen, we run integration tests. These include unit tests in Jest on the frontend, unit tests in MSTest on the back end, and SpecFlow acceptance tests on our API. If these fail, the build does not release to any of our environments.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1608213366025/k2IIyK0DQ.png" alt="Focus of our pipeline on the build process where unit and API tests are run" /></p>
<p>After building, we deploy to DEV and AUTO environments concurrently. If the DEV release passes (green), the build also goes to TEST. These releases stand up resources and deploy our new code — nothing special.</p>
<p>The AUTO release does the same release as DEV and AUTO with an additional step. Once the new code has been deployed to the environment, we trigger an additional build that runs all of our Cypress E2E tests against the AUTO environment. If the tests fail, the release fails (red) and rolls back to the previous build. If the tests pass, the release passes (green).</p>
<p>For tests that fail, we capture screen-shots. Regardless of tests passing or failing, videos are captured of each test. Both of these are saved to the build artifact after Cypress tests are run.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1608213396870/j8nzsh6Ai.png" alt="Focus of our pipeline where the build deploys to dev, test, and auto environments" /></p>
<p>In order for a build to go to STAGE, we require two things: Cypress tests passing in auto (green) and QA signing off on all features merged. Once a release is in STAGE, it can go to PROD if it has been signed off by our business counterparts.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1608213413199/nNQO70mji.png" alt="Focus of our pipeline where cypress tests and manual testing allows or blocks release to stage and prod" /></p>
<h2 id="working-with-feature-flags">Working with Feature Flags</h2>
<p>We use <a target="_blank" href="https://launchdarkly.com/">Launch Darkly</a> for feature flags to help remove barriers to releasing partial features. Given our deployment and QA workflows, we needed to figure out how to integrate feature flags into our Cypress testing flow. While it is possible to toggle feature flags for certain Cypress tests, we decided to create a workflow that was suitable for us. What we ended up agreeing on as a dev team is:</p>
<ol>
<li>Start with a feature flag on in DEV/Local for initial feature</li>
<li>We submit a PR to merge the feature with the flag off in</li>
<li>We update Cypress tests locally with the feature flag</li>
<li>When the Cypress PR merges we turn the feature flag on in</li>
<li>The Cypress tests pass in AUTO with the new feature 🎉</li>
</ol>
<h2 id="conclusion">Conclusion</h2>
<p>Cypress has brought a lot to our team and our process. It has encouraged our team to communicate feature expectations. It has provided us with a tool to catch defects as they are being generated. Possibly the biggest value, Cypress serves as a regression test suite. This helps us feel assured that we have not negatively affected any previous features when implementing new ones.</p>
<p>Cypress also offers a breadth of helpful features allowing developers to dive into E2E testing without having to create a Page Object Model or write wait helpers. Also, the value of the interactive test runner, screen-shot, and video output makes this tool highly valuable to non-developer members of our team.</p>
]]></content:encoded></item><item><title><![CDATA[Creating Netlify Cloud Functions]]></title><description><![CDATA[I began dabbling with cloud functions with AWS Lambda. That was when I started developing. Around the same time, I learned the difference between a backend and a frontend - and the role of an API. It was a lot to take in, but the differences between ...]]></description><link>https://blog.micleners.com/creating-netlify-cloud-functions</link><guid isPermaLink="true">https://blog.micleners.com/creating-netlify-cloud-functions</guid><category><![CDATA[serverless]]></category><category><![CDATA[Netlify]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Michael Leners]]></dc:creator><pubDate>Sun, 13 Dec 2020 03:28:53 GMT</pubDate><content:encoded><![CDATA[<p>I began dabbling with cloud functions with AWS Lambda. That was when I started developing. Around the same time, I learned the difference between a backend and a frontend - and the role of an API. It was a lot to take in, but the differences between <code>serverless architecture</code> and <code>lift-and-shift</code> cloud were clear.</p>
<p>Since then, I've worked with AWS Lambda Functions, Azure Functions, Firebase (Google Cloud) Functions, and Netlify Functions for various work tasks and side projects. </p>
<p>I've discovered the utility of these functions by using them where they are needed. For example: </p>
<ul>
<li>Lambdas are easy to edit data between a Firehose and S3</li>
<li>Firebase functions can be triggered off of changes from RTD or Firestore databases</li>
<li>Netlify functions are a simple and elegant way to run backend API calls without having to spin up a backend</li>
</ul>
<p>I need to be honest, I love using Netlify to deploy my frontend apps. It's amazing to have functions bundled in with my frontend repo, deployed on the same TLD so that there are no CORS issues to deal with.</p>
<h2 id="case-study">Case Study</h2>
<p>To get up and running quickly, we will be hitting the Github API. This is partly due to the widespread familiarity with Github. Also, Github API allows calls to be made without authentication so that headache can be saved for another blog!</p>
<p>The basic flow will look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607822828825/Sw3ec_qzD.png" alt="Group 66.png" /></p>
<p>We will:</p>
<ul>
<li>Set up local repo </li>
<li>Create Netlify function to call Github API</li>
<li>Deploy function to Netlify</li>
</ul>
<h2 id="prerequisites">Prerequisites</h2>
<p>To follow along, you will want the following:</p>
<ul>
<li><a target="_blank" href="https://www.netlify.com/">Netlify</a> for deploying our site and using functions</li>
<li><a target="_blank" href="https://github.com/">Github</a> to integrate our site with netlify</li>
<li>A text editor like <a target="_blank" href="https://code.visualstudio.com/">VS Code</a></li>
<li><a target="_blank" href="https://nodejs.org/en/">Node</a> installed (go with the LTS version)</li>
<li><a target="_blank" href="https://docs.netlify.com/cli/get-started/">Netlify CLI</a> installed</li>
</ul>
<h2 id="create-repository">Create Repository</h2>
<p>We are going to create a clean repository, hooked up to Github. We can do this in several ways. Instructions are given on Github when you create a fresh repository:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607823505084/7dLdWBIFm.png" alt="image.png" /></p>
<p>The second option of <code>create a new repository on the command line</code> is my typical go-to. That is because I usually forget to create my repo before I start my project locally 😅</p>
<p>Once you have your repo set up, <code>cd</code> into the project. For example, my repo is: <code>netlify-function-blog</code> so I will go:</p>
<pre><code>cd netlify-<span class="hljs-keyword">function</span>-blog
</code></pre><h2 id="initiation-netlify">Initiation Netlify</h2>
<p>To initiate this as netlify project, we will run:</p>
<pre><code>netlify <span class="hljs-keyword">init</span>
</code></pre><p>If you get an error here, make sure you have the  <a target="_blank" href="https://docs.netlify.com/cli/get-started/">Netlify CLI</a> installed.</p>
<p>If you have the CLI and have not logged in before, you will get a request to log in.</p>
<p>After you are logged in, you should get a message like:</p>
<pre><code class="lang-html">? What would you like to do? 
  ⇄  Connect this directory to an existing Netlify site 
❯ +  Create &amp; configure a new site
</code></pre>
<p>Since we have not created our netlify site yet (you can do so from their GUI at netlify.com), chose the <strong>second option</strong>.</p>
<p>You can choose all of the default options while setting things up. What's important is the site name and the location for functions. I like the default of <code>functions</code> folder. The name makes sense, right?</p>
<p>Commit and push. You can check out your site by running</p>
<pre><code>netlify <span class="hljs-keyword">open</span>
</code></pre><p>Nothing really there. This is because we're going to focus on creating cloud functions.</p>
<h2 id="creating-functions">Creating functions</h2>
<p>We told netlify to look in the folder <code>functions</code> folder, so let's create this folder with <code>mkdir functions</code> and create a new file in it called <code>helloWorld.js</code>. </p>
<p>Let's create a new function here:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">exports</span>.handler = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">event, context</span>) </span>{
    <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
        <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({<span class="hljs-attr">message</span>: <span class="hljs-string">"Hello World"</span>})
    };
}
</code></pre>
<p>This is a simple function that returns a "Hello World" message. We can locally test our function by running the command:</p>
<pre><code><span class="hljs-attribute">netlify</span> dev
</code></pre><p>The server should automatically open up at <a target="_blank" href="http://localhost:8888/">localhost:8888</a>. You can access your function by navigating to the subroute <a target="_blank" href="http://localhost:8888/.netlify/functions/helloWorld">.netlify/functions/helloWorld</a>.</p>
<p>You should get the response:</p>
<pre><code class="lang-json">{
<span class="hljs-attr">"message"</span>: <span class="hljs-string">"Hello World"</span>
}
</code></pre>
<p>You can also commit and push your changes and check out the same subroute on your netlify app. For example, with my app, the url is <a target="_blank" href="https://netlify-function-blog.netlify.app/.netlify/functions/helloWorld">https://netlify-function-blog.netlify.app/.netlify/functions/helloWorld</a>.</p>
<h4 id="nice">Nice! 🎉</h4>
<p>Now let's do something a bit more interesting. Let's use a function to make a call to Github to get our repositories and return them. </p>
<p>To make our API calls, we'll want fetch installed. Install this with npm like this:</p>
<pre><code>npm <span class="hljs-keyword">install</span> node-<span class="hljs-keyword">fetch</span>
</code></pre><p>Then, create a new file in the <code>functions</code> folder called <code>getRepos.js</code>.Your code should look something like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fetch = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node-fetch'</span>);

<span class="hljs-built_in">exports</span>.handler = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event, context</span>) </span>{
  <span class="hljs-keyword">const</span> url = <span class="hljs-string">'https://api.github.com/users/micleners/repos'</span>;
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url);
  <span class="hljs-keyword">const</span> json = <span class="hljs-keyword">await</span> response.json();

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(json),
  };
};
</code></pre>
<p>Of course, you should fill in your username for <code>micleners</code> in the code above! And when you run it locally, you should get a list of repos you own!</p>
<p>To get this to run on Netlify, you'll need to do two things.</p>
<ol>
<li>Create a <code>package.json</code> by running this command:</li>
</ol>
<pre><code>npm <span class="hljs-keyword">init</span>
</code></pre><ol>
<li>Go into <code>netlify.toml</code> and change the build command to <code>npm install</code>. Your <code>netlify.toml</code> should start like this:</li>
</ol>
<pre><code><span class="hljs-section">[build]</span>
  <span class="hljs-attr">command</span> = <span class="hljs-string">"npm install"</span>
  <span class="hljs-attr">functions</span> = <span class="hljs-string">"functions"</span>
</code></pre><p>With these changes, you should be able to merge and push your changes. Then you can hit your deployed function on Netlify.</p>
<h2 id="next-steps">Next Steps</h2>
<p>This is just a tickle of what Netlify functions can do. You can imagine filtering and processing results in a function. You can also use Netlify environment variables to store and access secrets within functions. Check out <a target="_blank" href="https://docs.netlify.com/configure-builds/environment-variables/#declare-variables">Netlify docs on environment variables</a> for more info!</p>
]]></content:encoded></item><item><title><![CDATA[Dockerizing React Apps]]></title><description><![CDATA[Containerized development is hot 🔥  What makes these tools so popular? From my experience, containers:

Make complex local environments quick and easy to spin up
Allow for specific versioning of languages and packages to coexist locally
Provide an e...]]></description><link>https://blog.micleners.com/dockerizing-react-apps</link><guid isPermaLink="true">https://blog.micleners.com/dockerizing-react-apps</guid><category><![CDATA[2Articles1Week]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Michael Leners]]></dc:creator><pubDate>Wed, 09 Dec 2020 02:21:34 GMT</pubDate><content:encoded><![CDATA[<p>Containerized development is hot 🔥  What makes these tools so popular? From my experience, containers:</p>
<ul>
<li>Make complex local environments quick and easy to spin up</li>
<li>Allow for specific versioning of languages and packages to coexist locally</li>
<li>Provide an easy tool to ship code for pipeline integration and deployment</li>
<li>Help create a consistent work environment across developers</li>
</ul>
<p>Docker has taken the spotlight for creating development containers. This tutorial will show you how to dockerize a project created with Create React App.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>In order to go through this tutorial, you should have <a target="_blank" href="https://nodejs.org/en/">node</a> (LTS version if you're uncertain) and <a target="_blank" href="https://docs.docker.com/get-docker/">docker</a> installed. The links just listed should work for you, but feel free to use <a target="_blank" href="https://brew.sh/">Homebrew</a> or installer you prefer.</p>
<h2 id="project-startup">Project Startup</h2>
<p>If you don't have a CRA project yet, use <code>npm</code> to create a new one using the <code>npx</code> command:</p>
<pre><code class="lang-jsx">npx create-react-app my-project
</code></pre>
<p>Move into your project:</p>
<pre><code class="lang-jsx">cd my-project
</code></pre>
<p>Start up and check out your app:</p>
<pre><code class="lang-jsx">yarn start
</code></pre>
<p>It soon should be running at <a target="_blank" href="http://localhost:3000">http://localhost:3000</a>. When you've had your fun exploring, turn off the server when with <code>ctrl+c</code> and get ready to start dockerizing 🤓</p>
<h2 id="dockerize">Dockerize!</h2>
<p>New docker images are built on a base image and ours will be no different. <a target="_blank" href="https://hub.docker.com">Docker hub</a> contains a multitude of images. It is probably no surprise that we will be using a <a target="_blank" href="https://hub.docker.com/_/node">node docker image</a> as our base (we'll use <code>14.15.1</code> which is LTS at the time of writing). </p>
<p>To specify this docker image and other configuration, create the file <code>Dockerfile</code> in the root of your project and add the following:</p>
<pre><code class="lang-docker"># pull official base image
FROM node:lts-alpine

# set working directory
WORKDIR /app

# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH

# copies package.json and package-lock.json
COPY package*.json ./

# installs app dependencies
RUN npm install
RUN npm install react-scripts -g

# add app contents to the container
COPY . ./

# start app
CMD ["npm", "start"]
</code></pre>
<p>Let's break this down line by line</p>
<ol>
<li><code>FROM node:lts-alpine</code>
This line tells docker what base image to use. We want to use the latest stable (LTS stands for long term stable) version of node. Alpine is a distribution of linux that is designed for security, simplicity, and resource efficiency. It is a common choice for docker images because of this.</li>
<li><code>WORKDIR /app</code>
It's good practice to chose a working directory to enter into. If you don't, docker will copy all the contents into the root of the image. If there is namespace clashes, there may be </li>
</ol>
<p>Also, create a <code>.dockerignore</code> file in the root of your project with the following content:</p>
<pre><code class="lang-docker">node_modules
build
.dockerignore
Dockerfile
Dockerfile.prod
</code></pre>
<p>This makes sure not to copy any unnecessary files to our docker image.</p>
<h2 id="start-up-docker">Start Up Docker</h2>
<p>First, we need to build the docker image:</p>
<pre><code class="lang-docker">docker build . -t local-react
</code></pre>
<p>The <code>-t local-react</code> is a tag to easily reference our docker container later. You can change <code>local-react</code> to whatever name you want, just make sure you change the next script as well!</p>
<p>You should see the steps from the above <code>Dockerfile</code> run. Then we can start up our docker server with this command:</p>
<pre><code class="lang-docker">docker run \
  -it \
  --rm \
  -v ${PWD}:/app \
  -v /app/node_modules \
  -p 3000:3000 \
  local-react
</code></pre>
<p>Let's go through what's happening here line by line</p>
<ol>
<li><code>docker run</code> starts up the docker container</li>
<li><code>-it</code> runs the docker container in interactive mode so that the container remains open after it starts. As of <a target="_blank" href="[https://stackoverflow.com/questions/60790440/docker-container-exiting-immediately-after-starting-when-using-npm-init-react-ap](https://stackoverflow.com/questions/60790440/docker-container-exiting-immediately-after-starting-when-using-npm-init-react-ap">react-scripts v3.4.1 this is now required</a>).</li>
<li><code>-v ${PWD}:/app</code> creates a volume of your current working directory into the app directory. This way, when changes are made locally, they will be reflected in docker</li>
<li><code>-v /app/node_modules</code> is a workaround to ensure that we use the <code>node_modules</code> in the docker container rather than the <code>node_modules</code> locally</li>
<li><code>-p 3000:3000</code> exposes the docker port 3000 on your <a target="_blank" href="http://localhost:3000">localhost</a> so you can view the app running</li>
<li><code>local-react</code> is the tag of the container we built</li>
</ol>
<p>Boom 🎉 With any luck you should be up and running!</p>
]]></content:encoded></item></channel></rss>