<?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" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[André Monteiro's Blog]]></title><description><![CDATA[A journey through programming]]></description><link>https://andremonteiro.pt/</link><image><url>https://andremonteiro.pt/favicon.png</url><title>André Monteiro&apos;s Blog</title><link>https://andremonteiro.pt/</link></image><generator>Ghost 5.2</generator><lastBuildDate>Mon, 13 Apr 2026 15:57:24 GMT</lastBuildDate><atom:link href="https://andremonteiro.pt/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Gatsby and react-i18next: wrapping page elements without losing translations]]></title><description><![CDATA[Recently I've been commissioned to build a lawyer's website, to which I decided to develop using Gatsby for its Static Site Generation capability and its GraphQL API. As it is a business site, it needed to be translated to several languages - that's where I met trouble.]]></description><link>https://andremonteiro.pt/gatsby-i18next-wrap-page-element/</link><guid isPermaLink="false">621101548dbdc811cede2135</guid><category><![CDATA[React]]></category><category><![CDATA[Gatsby]]></category><category><![CDATA[i18next]]></category><category><![CDATA[Internationalization]]></category><category><![CDATA[SSG]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Sat, 19 Feb 2022 15:46:36 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2022/02/gatsby-i18next-wrap-page-element.png" medium="image"/><content:encoded><![CDATA[<img src="https://andremonteiro.pt/content/images/2022/02/gatsby-i18next-wrap-page-element.png" alt="Gatsby and react-i18next: wrapping page elements without losing translations"><p>Recently I&apos;ve been commissioned to build a lawyer&apos;s website, to which I decided to develop using <a href="https://www.gatsbyjs.com/">Gatsby</a> for its Static Site Generation capability and its GraphQL API. As it is a business site, it needed to be translated to several languages - that&apos;s where I met trouble.</p><p>At this point, I had a <code>Layout</code> component that I was using in every page component as a Wrapper, that was being rerendered every time the user navigated to another page. This caused some visual glitches, more specifically on some animations of the mobile navigation bar (a child of the <code>Layout</code> component).</p><figure class="kg-card kg-code-card"><pre><code class="language-tsx">const IndexPage = () =&gt; {
  return (
    &lt;Layout&gt;
      // Other stuff here
    &lt;/Layout&gt;
  );
}</code></pre><figcaption>Every page component was like this, unmanageable.</figcaption></figure><p>Gatsby provides certain APIs to customize building a site. I became interested in <code><a href="https://www.gatsbyjs.com/docs/reference/config-files/gatsby-ssr/#wrapPageElement">wrapPageElement</a></code>, which is a function available in both <a href="https://www.gatsbyjs.com/docs/reference/config-files/gatsby-ssr">Server Rendering</a> and <a href="https://www.gatsbyjs.com/docs/reference/config-files/gatsby-browser/">Browser</a> APIs. This function lets you wrap pages in a component of your choice - in my case, it let me wrap my pages in the <code>Layout</code> component. But, of course, things are never this easy. </p><figure class="kg-card kg-code-card"><pre><code class="language-jsx">// gatsby-ssr.js and gatsby-browser.js
const React = require(&apos;react&apos;);
const Layout = require(&apos;./src/components/Layout&apos;).default;

exports.wrapPageElement = ({ element }) =&gt; {
  return &lt;Layout&gt;{element}&lt;/Layout&gt;
};</code></pre><figcaption>What could go wrong?</figcaption></figure><p>This site I&apos;m building uses <a href="https://www.gatsbyjs.com/plugins/gatsby-plugin-react-i18next/">gatsby-plugin-react-i18next</a> to &quot;easily translate your Gatsby website into multiple languages&quot; (oh, the irony). As soon as I wrapped my pages that way, I lost the translations in the <code>Layout</code> component and its children, and started getting this error: <code>warn react-i18next:: You will need to pass in an i18next instance by using initReactI18next</code>.</p><p>I started investigating, first with some logs here and there. I noticed that the element that I was receiving as the element in <code>wrapPageElement</code> was of type <code>I18nextProvider</code>, and that piqued my interest. I went to look at this plugin&apos;s source code and discovered it has an <a href="https://github.com/microapps/gatsby-plugin-react-i18next/blob/master/src/plugin/wrapPageElement.tsx">implementation</a> of <code>wrapPageElement</code> which returns wraps pages inside an i18next Context and respective provider.</p><figure class="kg-card kg-code-card"><pre><code class="language-tsx">const withI18next = (i18n: I18n, context: I18NextContext) =&gt; (children: any) =&gt; {
  return (
    &lt;I18nextProvider i18n={i18n}&gt;
      &lt;I18nextContext.Provider value={context}&gt;
      	{children} // Page element here
      &lt;/I18nextContext.Provider&gt;
    &lt;/I18nextProvider&gt;
  );
};

export const wrapPageElement = (
  {element, props}: WrapPageElementBrowserArgs&lt;any, PageContext&gt;,
  ...otherArgs
 ) =&gt; {
  // i18next magic...
  return withI18next(i18n, context)(element);
}</code></pre><figcaption>An excerpt of gatsby-plugin-react-i18next wrapper implementation</figcaption></figure><p>Now, I know why <code>Layout</code> and its children had lost their translations: they weren&apos;t able to access the Context provided by the plugin. The solution for this was clear to me then: I had to put my pages inside the Context instead of wrapping the Context in my pages!</p><pre><code class="language-jsx">// gatsby-ssr.js and gatsby-browser.js
const React = require(&apos;react&apos;);
const Layout = require(&apos;./src/components/Layout&apos;).default;

exports.wrapPageElement = ({ element }) =&gt; {
  const newElement = React.cloneElement(
    element,  // I18nextProvider
    element.props,
    React.cloneElement(
      element.props.children,  // I18nextContext.Provider
      element.props.children.props,
      React.createElement(
        Layout,
        undefined,
        element.props.children.props.children,
      ),
    ),
  );

  return newElement;
};</code></pre><p>As a final note, do not forget that you have to use the <code>wrapPageElement</code> in both SSR and Browser APIs to achieve the same result server and client-side!</p>]]></content:encoded></item><item><title><![CDATA[Extending Chakra UI's Drawer to make it permanent]]></title><description><![CDATA[I have been using Chakra UI in a personal project. So far, I'm liking the library a lot since it has many similarities with Tailwind CSS. However, I found out that there is no property for making the Drawer component always open. After some searching, I discovered a solution.]]></description><link>https://andremonteiro.pt/chakra-ui-permanent-drawer/</link><guid isPermaLink="false">60fac23d8dbdc811cede2077</guid><category><![CDATA[Chakra UI]]></category><category><![CDATA[React]]></category><category><![CDATA[CSS]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Fri, 23 Jul 2021 13:57:28 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2021/07/thumbnail--1-.png" medium="image"/><content:encoded><![CDATA[<img src="https://andremonteiro.pt/content/images/2021/07/thumbnail--1-.png" alt="Extending Chakra UI&apos;s Drawer to make it permanent"><p>I have been using <a href="https://chakra-ui.com/">Chakra UI</a> in a personal project. So far, I&apos;m liking the library a lot since it has many similarities with Tailwind CSS. However, I found out that there is no property for making the Drawer component always open. After some searching, I discovered a solution.</p><p>To introduce the issue, the drawer is wrapped by a container <code>div</code>, which occupies the whole screen, blocking all click events to the underlying elements.</p><figure class="kg-card kg-image-card"><img src="https://andremonteiro.pt/content/images/2021/07/image.png" class="kg-image" alt="Extending Chakra UI&apos;s Drawer to make it permanent" loading="lazy" width="2000" height="1275" srcset="https://andremonteiro.pt/content/images/size/w600/2021/07/image.png 600w, https://andremonteiro.pt/content/images/size/w1000/2021/07/image.png 1000w, https://andremonteiro.pt/content/images/size/w1600/2021/07/image.png 1600w, https://andremonteiro.pt/content/images/size/w2400/2021/07/image.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>GitHub user <a href="https://github.com/jasonwarta">jasonwarta</a> came up with a <a href="https://github.com/chakra-ui/chakra-ui/issues/2893#issuecomment-780143150">workaround</a> that works by extending Chakra&apos;s default theme. Note that I have done some minor changes to their code.</p><p>First, we extend the Drawer component using the function <code>extendTheme</code>, creating a <strong>variant</strong> with the desired behavior - I called it <strong>permanent</strong>. This solution basically lets the pointer events go through the drawer&apos;s container, using the CSS property <code>pointer-events</code>.</p><pre><code class="language-javascript">// theme.ts
import { extendTheme } from &apos;@chakra-ui/react&apos;;

const theme = extendTheme({
  components: {
    Drawer: {
      variants: {
        permanent: {
          dialog: {
            pointerEvents: &apos;auto&apos;,
          },
          dialogContainer: {
            pointerEvents: &apos;none&apos;,
          },
        },
      },
    },
  },
});

export default theme;</code></pre><p>Then, we configure the <code>ChakraProvider</code> to use the created theme.</p><pre><code class="language-javascript">import { ChakraProvider } from &apos;@chakra-ui/react&apos;;

&lt;ChakraProvider theme={theme}&gt;
  // ...
&lt;/ChakraProvider&gt;</code></pre><p>At last, just pass the new <strong>variant</strong> as a property to your Drawer component.</p><pre><code class="language-javascript">const MyComponent = ({ children }) =&gt; {
  return (
    &lt;Drawer variant=&quot;permanent&quot;&gt;
      &lt;DrawerContent&gt;
        &lt;DrawerHeader borderBottomWidth=&quot;1px&quot;&gt;Drawer Header&lt;/DrawerHeader&gt;
        &lt;DrawerBody&gt;Drawer Body&lt;/DrawerBody&gt;
      &lt;/DrawerContent&gt;
    &lt;/Drawer&gt;
  );
};
</code></pre><p>In a similar way, I created another solution, although I haven&apos;t tested it thoroughly yet. Instead of working with <code>pointer-events</code>, I just set the width of the container to zero. &#xA0;</p><pre><code class="language-javascript">// theme.ts
import { extendTheme } from &apos;@chakra-ui/react&apos;;

const theme = extendTheme({
  components: {
    Drawer: {
      variants: {
        permanent: {
          dialogContainer: {
            width: 0,
          },
        },
      },
    },
  },
});

export default theme;</code></pre><p>If you find this post helpful, do not forget to give a thumbs up to the <a href="https://github.com/chakra-ui/chakra-ui/issues/2893#:~:text=commented-,on%2016%20Feb,-The%20%22correct%22%20way">original solution</a>!</p>]]></content:encoded></item><item><title><![CDATA[A clone of my blog with NextJS]]></title><description><![CDATA[I wanted to experiment on SSR with NextJS for a while, and creating a simple blog is a common sample project. As such, cloning my blog was a no-brainer.]]></description><link>https://andremonteiro.pt/blog-clone-nextjs/</link><guid isPermaLink="false">60f2e8418dbdc811cede1fce</guid><category><![CDATA[React]]></category><category><![CDATA[NextJS]]></category><category><![CDATA[SSR]]></category><category><![CDATA[Sass]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Unit Testing]]></category><category><![CDATA[Jest]]></category><category><![CDATA[Testing Library]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Sat, 17 Jul 2021 15:03:08 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2021/07/thumbnail.png" medium="image"/><content:encoded><![CDATA[<img src="https://andremonteiro.pt/content/images/2021/07/thumbnail.png" alt="A clone of my blog with NextJS"><p>I wanted to experiment on SSR with NextJS for a while, and creating a simple blog is a common sample project. As such, cloning my blog was a no-brainer.</p><p>The project can be cloned from the GitHub repository below.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/andremonteiro95/nextjs-blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">andremonteiro95/nextjs-blog</div><div class="kg-bookmark-description">Contribute to andremonteiro95/nextjs-blog development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" alt="A clone of my blog with NextJS"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">andremonteiro95</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/43e676dbcf53b141b37a2979d1277aaa3547858256e84be7e5c400512f62586f/andremonteiro95/nextjs-blog" alt="A clone of my blog with NextJS"></div></a></figure><p>The blog consists of two main pages: the home page, which presents the latest 5 posts, and the post page that shows the post&apos;s content to the reader. The front page features pagination so the user can navigate through the blog&apos;s archive. The post page features a comment section - with nested comments! - for each post. </p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://andremonteiro.pt/content/images/2021/07/frame_chrome_mac_dark--4--1.png" width="1997" height="1340" loading="lazy" alt="A clone of my blog with NextJS" srcset="https://andremonteiro.pt/content/images/size/w600/2021/07/frame_chrome_mac_dark--4--1.png 600w, https://andremonteiro.pt/content/images/size/w1000/2021/07/frame_chrome_mac_dark--4--1.png 1000w, https://andremonteiro.pt/content/images/size/w1600/2021/07/frame_chrome_mac_dark--4--1.png 1600w, https://andremonteiro.pt/content/images/2021/07/frame_chrome_mac_dark--4--1.png 1997w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://andremonteiro.pt/content/images/2021/07/frame_chrome_mac_dark--3--1.png" width="1997" height="1340" loading="lazy" alt="A clone of my blog with NextJS" srcset="https://andremonteiro.pt/content/images/size/w600/2021/07/frame_chrome_mac_dark--3--1.png 600w, https://andremonteiro.pt/content/images/size/w1000/2021/07/frame_chrome_mac_dark--3--1.png 1000w, https://andremonteiro.pt/content/images/size/w1600/2021/07/frame_chrome_mac_dark--3--1.png 1600w, https://andremonteiro.pt/content/images/2021/07/frame_chrome_mac_dark--3--1.png 1997w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>I tried to minimize the packages installed. In the front-end, I used both <a href="https://sass-lang.com/">SCSS</a> and <a href="https://styled-components.com/">styled-components</a> for styling, and <a href="https://react-hook-form.com/">React Hook Form</a> to handle the comment form. For the API, I used <a href="https://www.npmjs.com/package/json-server">JSON Server</a> - a package that creates a REST API from a JSON file.</p><p>To run the app, you just need to execute <code>npm run api</code> and <code>npm run dev</code> concurrently. I also decided to develop some unit tests using <a href="https://jestjs.io/">Jest</a> and <a href="https://testing-library.com/">Testing Library</a>. They can be run using <code>npm run test</code>.</p><p>Let me read what your thoughts are, and where and how I can improve.</p>]]></content:encoded></item><item><title><![CDATA[Creating a template for new React projects]]></title><description><![CDATA[As a software developer, I create a lot of new projects that I end up dropping, and sometimes I feel that configuring a new project is a hassle and makes me lose interest. I created a list of steps to set up a new React project and a template repository I can reuse to kickstart a workspace.]]></description><link>https://andremonteiro.pt/creating-a-template-for-new-react-projects/</link><guid isPermaLink="false">6067007a8dbdc811cede1ef5</guid><category><![CDATA[React]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[ESLint]]></category><category><![CDATA[Sass]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[Prettier]]></category><category><![CDATA[CRACO]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Mon, 15 Feb 2021 16:42:51 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2021/02/creating-a-template-for-new-react-projects.png" medium="image"/><content:encoded><![CDATA[<img src="https://andremonteiro.pt/content/images/2021/02/creating-a-template-for-new-react-projects.png" alt="Creating a template for new React projects"><p>As a software developer, I create a lot of new projects that I end up dropping, and sometimes I feel that configuring a new project is a hassle and makes me lose interest. That happened to me with React as there are several libraries I install and configure whenever I create a new app, namely TypeScript, CRACO, ESLint, Prettier, Sass and Tailwind CSS. To solve this issue, I created a list of steps to set up a new React project with the help of <code>create-react-app</code>, which led me to a template repository I can reuse to kickstart a workspace.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/andremonteiro95/react-template"><div class="kg-bookmark-content"><div class="kg-bookmark-title">andremonteiro95/react-template</div><div class="kg-bookmark-description">Contribute to andremonteiro95/react-template development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" alt="Creating a template for new React projects"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">andremonteiro95</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://avatars.githubusercontent.com/u/11173844?s=400&amp;v=4" alt="Creating a template for new React projects"></div></a></figure><h3 id="creating-a-new-react-app">Creating a new React app</h3><p>First steps first, let&apos;s create a new React app through <code>create-react-app</code>. Notice that I set the template flag to the TypeScript template; you can use any other template, or omit the flag to install the default JavaScript template. </p><pre><code class="language-bash"># npm &lt;= 6
npx create-react-app react-template --template typescript
# npm &gt;= 7
npm exec -- create-react-app react-template --template typescript</code></pre><h3 id="install-craco">Install CRACO</h3><p>CRACO, or Create React App Configuration Override, is &quot;an easy and comprehensible configuration layer for create-react-app&quot;. We will use this utility to configure ESLint and PostCSS, the latter to be able to use Tailwind CSS. Just install it using <code>npm</code>.</p><pre><code class="language-bash">npm install @craco/craco</code></pre><p>Following CRACO&apos;s instructions, &quot;update the existing calls to <code>react-scripts</code> in the <code>scripts</code> section of your <code>package.json</code> file to use the <code>craco</code> CLI&quot;:</p><pre><code class="language-diff">/* package.json */

&quot;scripts&quot;: {
-   &quot;start&quot;: &quot;react-scripts start&quot;,
+   &quot;start&quot;: &quot;craco start&quot;,
-   &quot;build&quot;: &quot;react-scripts build&quot;,
+   &quot;build&quot;: &quot;craco build&quot;
-   &quot;test&quot;: &quot;react-scripts test&quot;,
+   &quot;test&quot;: &quot;craco test&quot;
}</code></pre><p>Let&apos;s create a CRACO config file, <code>craco.config.js</code>. It will be empty for now, we will soon add to it.</p><pre><code class="language-javascript">// craco.config.js

module.exports = {};</code></pre><h3 id="adding-eslint-rules">Adding ESLint rules</h3><p>React projects created through <code>create-react-app</code> come with an ESLint configuration by default. However, I think it is not enough as I am a fan of opinionated environments (that&apos;s one of the reasons I like Angular and NestJS).</p><p>One of the most famous set of rules for React development is the <a href="https://www.npmjs.com/package/eslint-config-airbnb">Airbnb configuration</a> which enforces <a href="https://github.com/airbnb/javascript">Airbnb&apos;s JavaScript style guide</a>. There is a community package that brings TypeScript support to this configuration: <code>eslint-config-airbnb-typescript</code>. Start by installing it as a dev dependency. </p><pre><code class="language-bash">npm install eslint-config-airbnb-typescript --save-dev</code></pre><p>Then, we have to install some plugins for it to work. There is a limitation with ESLint, see <a href="https://github.com/eslint/rfcs/tree/master/designs/2019-config-simplification">RFC</a> and <a href="https://github.com/eslint/eslint/issues/13481">progress</a> for more information.</p><pre><code class="language-bash">npm install eslint-plugin-import@^2.22.0 eslint-plugin-jsx-a11y@^6.3.1 eslint-plugin-react@^7.20.3 eslint-plugin-react-hooks@^4.0.8 @typescript-eslint/eslint-plugin@^4.4.1 --save-dev</code></pre><p>If you are having issues installing it using <code>npm &gt;= 7</code> because of <code>npm</code> not being able to resolve the dependency tree, just add the flag <code>--legacy-peer-deps</code> to the command - it will ensure the peer dependencies are not installed automatically.</p><p>Now, create an ESLint configuration file, <code>.eslintrc.js</code>, and add the following content to it:</p><pre><code class="language-javascript">// .eslintrc.js

module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    &apos;plugin:react/recommended&apos;,
    &apos;airbnb-typescript&apos;,
  ],
  parser: &apos;@typescript-eslint/parser&apos;,
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    project: &apos;./tsconfig.json&apos;,
    sourceType: &apos;module&apos;,
  },
  plugins: [&apos;react&apos;, &apos;@typescript-eslint&apos;]
};</code></pre><p>Let&apos;s not forget to point the CRACO configuration file to our ESLint configuration file.</p><pre><code class="language-javascript">// craco.config.js

const { ESLINT_MODES } = require(&apos;@craco/craco&apos;);

module.exports = {
  eslint: {
    mode: ESLINT_MODES.file,
  },
};
</code></pre><h3 id="turn-your-code-pretty-with-prettier">Turn your code pretty with Prettier</h3><p>I can&apos;t state enough how much I love <a href="https://prettier.io/">Prettier</a> and its Visual Studio Code <a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode">extension</a>. I have the &quot;Format on Save&quot; option on all the time, and with the help of Prettier I always have my code perfectly organized.</p><p>Install the following dependencies in your app.</p><pre><code class="language-bash">npm i prettier eslint-config-prettier eslint-plugin-prettier --save-dev</code></pre><p>Extend your ESLint configuration with the installed configuration and plugin. Add also a custom rule to show errors if Prettier rules are not followed.</p><pre><code class="language-diff-javascript">// .eslintrc.js

module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    &apos;plugin:react/recommended&apos;,
    &apos;airbnb-typescript&apos;,
+   &apos;prettier&apos;,
  ],
  parser: &apos;@typescript-eslint/parser&apos;,
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    project: &apos;./tsconfig.json&apos;,
    sourceType: &apos;module&apos;,
  },
- plugins: [&apos;react&apos;, &apos;@typescript-eslint&apos;],
+ plugins: [&apos;react&apos;, &apos;@typescript-eslint&apos;, &apos;prettier&apos;],
+ rules: {
+   &apos;prettier/prettier&apos;: &apos;error&apos;,
+ },
};</code></pre><p>If you wish, create also a <code>.prettierrc</code> file to configure Prettier in VS Code. This is my default configuration: </p><pre><code class="language-json">{
  &quot;singleQuote&quot;: true,
  &quot;tabWidth&quot;: 2,
  &quot;trailingComma&quot;: &quot;all&quot;
}</code></pre><p>It&apos;s possible that you find some Prettier errors after this step - just fix them accordingly!</p><h3 id="style-your-app-with-tailwind-css">Style your app with Tailwind CSS </h3><p><a href="https://tailwindcss.com/">Tailwind CSS</a> is a marvel for styling your apps. While most CSS frameworks are component based (e.g. Bootstrap, Bulma), Tailwind CSS is an utility-first framework, with classes for practically everything - text colors, layouts, animations, etc.</p><p>Begin by installing the required packages. As of this writing, <code>create-react-app</code> still uses PostCSS 7, but Tailwind CSS 2 requires PostCSS 8. As such, we have to install the compatibility build of Tailwind CSS. </p><pre><code class="language-bash">npm i tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat autoprefixer@^9</code></pre><p>After installing, override the default React PostCSS config with the help of CRACO: </p><pre><code class="language-diff-javascript">// craco.config.js

  const { ESLINT_MODES } = require(&apos;@craco/craco&apos;);
+ const autoprefixer = require(&apos;autoprefixer&apos;);
+ const tailwind = require(&apos;tailwindcss&apos;);

  module.exports = {
    eslint: {
      mode: ESLINT_MODES.file,
    },
+   style: {
+     postcss: {
+       plugins: [autoprefixer, tailwind],
+     },
+   },
  };
</code></pre><p>Now, we need to configure Tailwind CSS to remove unused styles in production so it does not create an oversized bundle. Create a <code>tailwind.config.js</code> file in the root of your project and add the following code: </p><pre><code class="language-javascript">// tailwind.config.js

module.exports = {
  purge: [&apos;./src/**/*.{js,jsx,ts,tsx}&apos;, &apos;./public/index.html&apos;],
};</code></pre><p>Finally, include Tailwind in your main CSS file.</p><pre><code class="language-css">// src/index.css

@tailwind base;
@tailwind components;
@tailwind utilities;</code></pre><p>Check if it is working by changing any class name in your app. I added <code>text-red-400</code> as the class name to the default paragraph in <code>App.tsx</code>.</p><figure class="kg-card kg-image-card"><img src="/content/images/2021/02/image.png" class="kg-image" alt="Creating a template for new React projects" loading="lazy"></figure><h3 id="power-up-your-css-with-sass">Power up your CSS with Sass</h3><p>There&apos;s a habit I kept from all the time I spent working with Angular, which is using SCSS for styling my apps. It is a mix of the powerful features from Sass and the known CSS syntax, which makes it easy to learn and use.</p><p>Install the <code>sass</code> package in your project, and you can start changing your CSS files to SCSS or Sass files! Also, do not forget to change the imports in your <code>.tsx/.jsx</code> files. </p><pre><code class="language-bash">npm i sass</code></pre><h3 id="final-thoughts">Final thoughts</h3><p>It can be tiresome to configure a new React project, more so if it is the first time since some research is required for some problems that may occur. With the template I created through these steps, I want to minimize the hassle of creating new React apps.</p><p>If you have any suggestions or questions, please feel free to open an issue in the linked repository.</p>]]></content:encoded></item><item><title><![CDATA[Creating a centralized modal in React with Redux]]></title><description><![CDATA[While working on an application, I found some modals were duplicated because they could be shown in different parts of it. Also, there was an instance of the modal component for each modal, instead of reusing the same. I came up with a modal system that uses Redux to solve these issues.]]></description><link>https://andremonteiro.pt/react-redux-modal/</link><guid isPermaLink="false">6067007a8dbdc811cede1ef3</guid><category><![CDATA[React]]></category><category><![CDATA[Redux]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Fri, 27 Nov 2020 15:01:55 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2020/11/thumbnail.png" medium="image"/><content:encoded><![CDATA[<img src="https://andremonteiro.pt/content/images/2020/11/thumbnail.png" alt="Creating a centralized modal in React with Redux"><p>While working on an application, I found some modals were duplicated because they could be shown in different parts of it. Also, there was an instance of the modal component for each modal, instead of reusing the same. I came up with a modal system that centralizes the management using Redux to solve these issues. </p><p>This tutorial explains how to build a simple, centralized modal component using React and Redux.</p><p>If you don&apos;t want to follow the tutorial, you can just check the GitHub repository below.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/andremonteiro95/react-redux-modal"><div class="kg-bookmark-content"><div class="kg-bookmark-title">andremonteiro95/react-redux-modal</div><div class="kg-bookmark-description">Contribute to andremonteiro95/react-redux-modal development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" alt="Creating a centralized modal in React with Redux"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">andremonteiro95</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://avatars0.githubusercontent.com/u/11173844?s=400&amp;v=4" alt="Creating a centralized modal in React with Redux"></div></a></figure><h3 id="setting-up-the-project">Setting up the project</h3><p>Let&apos;s create a new React project using Create React App. It creates a new React project with TypeScript support; if you don&apos;t want to develop in TypeScript, go ahead and remove the <code>template</code> flag.</p><pre><code class="language-bash">npx create-react-app react-redux-modal --template typescript</code></pre><p>I use TypeScript for all my projects because I find many advantages in it, such as finding errors in build time (which leads to higher code quality), and better usability in the development environment (type hinting, code completion, etc.). If you are not acquainted with TypeScript in React projects, the <a href="https://github.com/typescript-cheatsheets/react">React + TypeScript Cheatsheets</a> may be useful to you. </p><h3 id="creating-the-modal-component">Creating the modal component</h3><p>First, let&apos;s change the styling of the default content a little. I want my modal to add an overlay to the page so it&apos;s more apparent that an action is due, which will not work as good if I keep the default dark background. Open <code>App.css</code> and change the following properties of <code>App-header</code> class.</p><pre><code class="language-css">.App-header {
  background-color: #ffffff;
  // ...
  color: #202020;
}</code></pre><p>Your app should look like the screenshot below. </p><figure class="kg-card kg-image-card"><img src="/content/images/2020/11/image-5.png" class="kg-image" alt="Creating a centralized modal in React with Redux" loading="lazy"></figure><p>Now it is time to build our modal component. Create a <code>components</code> directory, and a <code>Modal.tsx</code> file inside it. For now, we won&apos;t care about the modal itself, we will just declare a simple component with some placeholder text. </p><pre><code class="language-tsx">import React from &apos;react&apos;;

function Modal() {
  return &lt;span&gt;This is my new modal!&lt;/span&gt;;
}

export default Modal;</code></pre><p>Since the purpose is to create a centralized modal, add your modal to the root of your project - in this case, the <code>App</code> component in <code>App.tsx</code>.</p><pre><code class="language-typescript">import React from &apos;react&apos;;
import logo from &apos;./logo.svg&apos;;
import &apos;./App.css&apos;;
import Modal from &apos;./components/Modal&apos;;

function App() {
  return (
    &lt;&gt;
      &lt;Modal /&gt;
      &lt;div className=&quot;App&quot;&gt;
        &lt;header className=&quot;App-header&quot;&gt;
          &lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /&gt;
          &lt;p&gt;
            Edit &lt;code&gt;src/App.tsx&lt;/code&gt; and save to reload.
          &lt;/p&gt;
          &lt;a
            className=&quot;App-link&quot;
            href=&quot;https://reactjs.org&quot;
            target=&quot;_blank&quot;
            rel=&quot;noopener noreferrer&quot;
          &gt;
            Learn React
          &lt;/a&gt;
        &lt;/header&gt;
      &lt;/div&gt;
    &lt;/&gt;
  );
}

export default App;</code></pre><p>In the top of your page should now appear the phrase &quot;This is my new modal!&quot;. Create a <code>div</code> for the modal overlay, and another <code>div</code> inside for the modal itself. Then, create a new <code>Modal.css</code> stylesheet to include our new containers&apos; styles. </p><pre><code class="language-tsx">import React from &apos;react&apos;;
import &apos;./Modal.css&apos;;

function Modal() {
  return (
    &lt;div className=&quot;modal-overlay&quot;&gt;
      &lt;div className=&quot;modal&quot;&gt;This is my new modal!&lt;/div&gt;
    &lt;/div&gt;
  );
}

export default Modal;</code></pre><pre><code class="language-css">.modal-overlay {
  position: absolute;
  z-index: 9;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.7);
  display: flex;
  justify-content: center;
  align-items: center;
}

.modal {
  background-color: #ffffff;
  border: 1px solid #bebebe;
  border-radius: 2px;
  padding: 12px 16px;
}
</code></pre><p>Feel free to choose your own approach for styling the components, I&apos;m using stylesheet files just for demonstration purposes.</p><p>After these changes, our app should look like this:</p><figure class="kg-card kg-image-card"><img src="/content/images/2020/11/image-6.png" class="kg-image" alt="Creating a centralized modal in React with Redux" loading="lazy"></figure><p>Right now, there is no way to close or open the modal, it simply opens as soon as we refresh the page. &#xA0;We will add a button to the modal for it to close when clicked.</p><pre><code class="language-tsx">import React from &apos;react&apos;;
import &apos;./Modal.css&apos;;

type ModalProps = {
  onCloseButtonClick: () =&gt; void;
};

function Modal(props: ModalProps) {
  const { onCloseButtonClick } = props;
  return (
    &lt;div className=&quot;modal-overlay&quot;&gt;
      &lt;div className=&quot;modal&quot;&gt;
        &lt;span className=&quot;modal-close&quot; onClick={onCloseButtonClick}&gt;
          &amp;#10005; {/* HTML code for a multiplication sign */}
        &lt;/span&gt;
        This is my new modal!
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

export default Modal;</code></pre><pre><code class="language-css">.modal-overlay {
  position: absolute;
  z-index: 9;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.7);
  display: flex;
  justify-content: center;
  align-items: center;
}

.modal {
  background-color: #ffffff;
  border: 1px solid #bebebe;
  border-radius: 2px;
  padding: 12px 16px;
  position: relative;
  height: 200px;
  width: 350px;
}

.modal-close {
  position: absolute;
  right: 8px;
  top: 4px;
  font-size: 24px;
  cursor: pointer;
}</code></pre><p>Add a variable to the <code>App</code> component&apos;s state so we can show and hide the modal, and replace the default content with a button to show the modal. I also added some global button styles to <code>index.css</code>.</p><pre><code class="language-tsx">import React, { useState } from &apos;react&apos;;
import logo from &apos;./logo.svg&apos;;
import &apos;./App.css&apos;;
import Modal from &apos;./components/Modal&apos;;

function App() {
  const [showModal, setShowModal] = useState(false);

  return (
    &lt;&gt;
      {showModal &amp;&amp; (
        &lt;Modal
          onCloseButtonClick={() =&gt; {
            setShowModal(false);
          }}
        /&gt;
      )}
      &lt;div className=&quot;App&quot;&gt;
        &lt;header className=&quot;App-header&quot;&gt;
          &lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /&gt;
          &lt;button
            onClick={() =&gt; {
              setShowModal(true);
            }}
          &gt;
            Show Modal
          &lt;/button&gt;
        &lt;/header&gt;
      &lt;/div&gt;
    &lt;/&gt;
  );
}

export default App;
</code></pre><pre><code class="language-css">button {
  font-size: 18px;
  padding: 8px;
}</code></pre><p>Note that we are using React hooks for the component state. When we click the button in the <code>App</code> component, we set the state variable <code>showModal</code> to <code>true</code>. When clicking the modal&apos;s close button, an event is triggered and passed to <code>App</code> through the <code>Modal</code>&apos;s properties, and then a function is called which sets <code>showModal</code> to false. The conditional rendering of <code>Modal</code> makes sure that the modal is only shown when <code>showModal</code> is truthy.</p><figure class="kg-card kg-image-card"><img src="/content/images/2020/11/image-8.png" class="kg-image" alt="Creating a centralized modal in React with Redux" loading="lazy"></figure><h3 id="managing-the-modal-through-redux">Managing the modal through Redux</h3><p>In the last section we implemented a way to show the dialog from the <code>App</code> component, but what we wish to achieve is a way to show the dialog from any component. It would be unmaintainable to pass a function to show the modal from <code>App</code> to every child component of it, so we need another method to do it. </p><p>Redux centralizes the application state and logic in a global store, thus allowing us to centralize the dialog state and logic. We can dispatch actions to update the store and have components react to its changes. The Redux official documentation recommends the installation of the Redux Toolkit. We&apos;ll install react-redux also for the components.</p><pre><code class="language-bash">npm install @reduxjs/toolkit react-redux
npm i --save-dev @types/react-redux</code></pre><p>We&apos;ll start by building some actions. Create a <code>store/actions.ts</code> file that will hold the actions and their respective action types.</p><pre><code class="language-typescript">export enum ModalActionTypes {
  ShowModal,
  HideModal,
}

export interface ModalAction {
  type: ModalActionTypes;
  payload?: any;
}

export function showModal(): ModalAction {
  return {
    type: ModalActionTypes.ShowModal,
  };
}

export function hideModal(): ModalAction {
  return {
    type: ModalActionTypes.HideModal,
  };
}</code></pre><p>Redux&apos;s documentation shows a different way of <a href="https://redux.js.org/recipes/usage-with-typescript#type-checking-actions--action-creators">type checking actions and action creators</a> from mine. I would say this way leverages TypeScript capabilities, but feel free to choose whatever version you like more.</p><p>For now, these actions won&apos;t be sending any payload since all we want to do is show and hide the modal. Now, create a file for our reducer, <code>reducers.ts</code>, under the <code>store</code> directory.</p><pre><code class="language-typescript">import { combineReducers } from &apos;@reduxjs/toolkit&apos;;
import { ModalAction, ModalActionTypes } from &apos;./actions&apos;;

const initialState = {
  modal: false,
};

function modalReducer(state = initialState, action: ModalAction) {
  switch (action.type) {
    case ModalActionTypes.ShowModal:
      return {
        ...state,
        modal: true,
      };
    case ModalActionTypes.HideModal:
      return {
        ...state,
        modal: false,
      };
    default:
      return state;
  }
}

const rootReducer = combineReducers({ modal: modalReducer });
export type RootState = ReturnType&lt;typeof rootReducer&gt;;
export default rootReducer;</code></pre><p>A Redux app only has one reducer function, the root reducer, which will handle all dispatched actions. Although, we can split this reducer in many reducers and combine them using <code>combineReducers</code> to get a root reducer. This root reducer is then used on the store creation, which we will do in <code>store/store.ts</code>.</p><pre><code class="language-typescript">import { createStore } from &apos;@reduxjs/toolkit&apos;;
import rootReducer from &apos;./reducers&apos;;

const store = createStore(rootReducer);
export default store;</code></pre><p>At last, we link Redux to our app&apos;s UI. First, wrap the application in a <code>Provider</code>. I chose to do so in <code>index.tsx</code>.</p><pre><code class="language-tsx">import React from &apos;react&apos;;
import ReactDOM from &apos;react-dom&apos;;
import { Provider } from &apos;react-redux&apos;;
import &apos;./index.css&apos;;
import App from &apos;./App&apos;;
import store from &apos;./store/store&apos;;

ReactDOM.render(
  &lt;React.StrictMode&gt;
    &lt;Provider store={store}&gt;
      &lt;App /&gt;
    &lt;/Provider&gt;
  &lt;/React.StrictMode&gt;,
  document.getElementById(&apos;root&apos;),
);</code></pre><p>Let&apos;s set the button in <code>App.tsx</code> to dispatch an action to show the modal.</p><pre><code class="language-tsx">import React from &apos;react&apos;;
import { connect, ConnectedProps } from &apos;react-redux&apos;;
import logo from &apos;./logo.svg&apos;;
import &apos;./App.css&apos;;
import Modal from &apos;./components/Modal&apos;;
import { showModal } from &apos;./store/actions&apos;;

const mapDispatchToProps = {
  dispatchShowModal: showModal,
};

const connector = connect(undefined, mapDispatchToProps);

type AppProps = {} &amp; ConnectedProps&lt;typeof connector&gt;;

function App(props: AppProps) {
  const { dispatchShowModal } = props;

  return (
    &lt;&gt;
      &lt;Modal /&gt;
      &lt;div className=&quot;App&quot;&gt;
        &lt;header className=&quot;App-header&quot;&gt;
          &lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /&gt;
          &lt;button
            onClick={() =&gt; {
              dispatchShowModal();
            }}
          &gt;
            Show Modal
          &lt;/button&gt;
        &lt;/header&gt;
      &lt;/div&gt;
    &lt;/&gt;
  );
}

export default connector(App);</code></pre><p>Don&apos;t worry if your app doesn&apos;t compile after removing <code>onCloseButtonClick</code> from the modal&apos;s properties, we will remove it from there soon enough. </p><p>Let&apos;s now link up the <code>Modal</code> component to our Redux store. </p><pre><code class="language-tsx">import React from &apos;react&apos;;
import { connect, ConnectedProps } from &apos;react-redux&apos;;
import { hideModal } from &apos;../store/actions&apos;;
import { RootState } from &apos;../store/reducers&apos;;
import &apos;./Modal.css&apos;;

const mapStateToProps = (state: RootState) =&gt; ({
  modal: state.modal.modal,
});

const mapDispatchToProps = {
  dispatchHideModal: hideModal,
};

const connector = connect(mapStateToProps, mapDispatchToProps);

type ModalProps = {} &amp; ConnectedProps&lt;typeof connector&gt;;

function Modal(props: ModalProps) {
  const { dispatchHideModal, modal } = props;

  if (!modal) {
    return null;
  }

  const onCloseButtonClick = () =&gt; {
    dispatchHideModal();
  };

  return (
    &lt;div className=&quot;modal-overlay&quot;&gt;
      &lt;div className=&quot;modal&quot;&gt;
        &lt;span className=&quot;modal-close&quot; onClick={onCloseButtonClick}&gt;
          &amp;#10005; {/* HTML code for a multiplication sign */}
        &lt;/span&gt;
        This is my new modal!
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

export default connector(Modal);</code></pre><p>Now, your app should work just as fine as before, without relying on <code>App</code>&apos;s state! To recap, we now use <code>dispatchShowModal</code> to show the modal and <code>dispatchHideModal</code> to hide it, and those functions can be used wherever in the app as long as the component is connected to Redux.</p><h3 id="creating-dynamic-modals">Creating dynamic modals</h3><p>Our modal only has a single sentence, but we want it to have more information. More than that, we wish that we could specify the information dynamically. </p><p>Right now, the modal state in Redux is a simple boolean that specifies if it is shown or not. We will change it so it accepts an object instead - this object will contain our modal&apos;s information, such as title and description.</p><p>Let&apos;s start by defining an interface for the modal&apos;s properties in <code>interfaces/modal-properties.ts</code>. For now, a title and a description are enough - later we will add buttons to it.</p><pre><code class="language-typescript">interface ModalProperties {
  title: string;
  description: string;
}
export default ModalProperties;</code></pre><p>Since the modal state will now be an object of type ModalProperties, we must change the state of our store to reflect it. Set the modal property to null - the intended logic is to show a modal if the state is not null - and define a type for the state in <code>reducers.ts</code>. We also change the reducer to set the modal to null when a hide modal action is dispatched, and set the modal to one with placeholder title and description when a show modal action is dispatched.</p><pre><code class="language-typescript">import { combineReducers } from &apos;@reduxjs/toolkit&apos;;
import ModalProperties from &apos;../interfaces/modal-properties&apos;;
import { ModalAction, ModalActionTypes } from &apos;./actions&apos;;

type ModalState = {
  modal: ModalProperties | null | undefined;
};

const initialState: ModalState = {
  modal: null,
};

function modalReducer(state = initialState, action: ModalAction): ModalState {
  switch (action.type) {
    case ModalActionTypes.ShowModal:
      return {
        ...state,
        modal: {
          title: &apos;Hello world!&apos;,
          description: &apos;This is a description.&apos;,
        },
      };
    case ModalActionTypes.HideModal:
      return {
        ...state,
        modal: null,
      };
    default:
      return state;
  }
}

const rootReducer = combineReducers({ modal: modalReducer });
export type RootState = ReturnType&lt;typeof rootReducer&gt;;
export default rootReducer;</code></pre><p>Change your <code>Modal</code> component to display the title and description.</p><pre><code class="language-tsx">function Modal(props: ModalProps) {
  const { dispatchHideModal, modal } = props;

  if (!modal) {
    return null;
  }

  const onCloseButtonClick = () =&gt; {
    dispatchHideModal();
  };

  return (
    &lt;div className=&quot;modal-overlay&quot;&gt;
      &lt;div className=&quot;modal&quot;&gt;
        &lt;span className=&quot;modal-close&quot; onClick={onCloseButtonClick}&gt;
          &amp;#10005; {/* HTML code for a multiplication sign */}
        &lt;/span&gt;
        &lt;h1&gt;{modal.title}&lt;/h1&gt;
        &lt;p&gt;{modal.description}&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Your app should now display the modal&apos;s title and description from Redux when you click in the &quot;Show Modal&quot; button.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="/content/images/2020/11/image-9.png" class="kg-image" alt="Creating a centralized modal in React with Redux" loading="lazy"><figcaption>As you may notice, this tutorial is not about styling... &#x1F605;</figcaption></figure><p>The modal isn&apos;t totally dynamic yet: we still need to somehow pass the title and description to the store. So, we go to our <code>actions.ts</code> and change the <code>showModal</code> action creator. We can also change the payload type in <code>ModalAction</code> to the previously created interface. </p><pre><code class="language-ts">export interface ModalAction {
  type: ModalActionTypes;
  payload?: ModalProperties;
}

export function showModal(payload: ModalProperties): ModalAction {
  return {
    type: ModalActionTypes.ShowModal,
    payload,
  };
}</code></pre><p>Go back to your reducer and change the static properties for the action payload. </p><pre><code class="language-ts">function modalReducer(state = initialState, action: ModalAction): ModalState {
  switch (action.type) {
    case ModalActionTypes.ShowModal:
      return {
        ...state,
        modal: action.payload,
      };
    case ModalActionTypes.HideModal:
      return {
        ...state,
        modal: null,
      };
    default:
      return state;
  }
}</code></pre><p>Pass now some properties to <code>dispatchShowDialog</code> in your <code>App.tsx</code>.</p><pre><code class="language-tsx">function App(props: AppProps) {
  const { dispatchShowModal } = props;

  return (
    &lt;&gt;
      &lt;Modal /&gt;
      &lt;div className=&quot;App&quot;&gt;
        &lt;header className=&quot;App-header&quot;&gt;
          &lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /&gt;
          &lt;button
            onClick={() =&gt; {
              dispatchShowModal({
                title: &apos;A new title.&apos;,
                description: &apos;And a new description too.&apos;,
              });
            }}
          &gt;
            Show Modal
          &lt;/button&gt;
        &lt;/header&gt;
      &lt;/div&gt;
    &lt;/&gt;
  );
}</code></pre><h3 id="adding-functionality-to-the-modal">Adding functionality to the modal</h3><p>Usually, modals or dialogs have buttons to achieve some effect, for instance to confirm some action. We will add a button to our modal which will open an alert in the browser, just for illustration purposes.</p><p>First, let&apos;s check what type of event is fired when the button is clicked. IntelliSense tells me it&apos;s of type <code>React.MouseEvent&lt;HTMLButtonElement, MouseEvent&gt;</code>. Let&apos;s add a new property to our <code>ModalProperties</code> that will specify the behavior of the button when clicked, with an event of the correct type as a parameter. We will keep it generic, although if you find that you need some specific property you can specify <code>HTMLButtonElement</code> in the type. </p><pre><code class="language-typescript">import React from &apos;react&apos;;
interface ModalProperties {
  title: string;
  description: string;
  onButtonClick: (event: React.MouseEvent) =&gt; void;
}</code></pre><p>Now, add a button to the modal and link up this new property to the button&apos;s <code>onClick</code> event. </p><pre><code class="language-tsx">function Modal(props: ModalProps) {
  const { dispatchHideModal, modal } = props;

  if (!modal) {
    return null;
  }

  const onCloseButtonClick = () =&gt; {
    dispatchHideModal();
  };

  return (
    &lt;div className=&quot;modal-overlay&quot;&gt;
      &lt;div className=&quot;modal&quot;&gt;
        &lt;span className=&quot;modal-close&quot; onClick={onCloseButtonClick}&gt;
          &amp;#10005; {/* HTML code for a multiplication sign */}
        &lt;/span&gt;
        &lt;h1&gt;{modal.title}&lt;/h1&gt;
        &lt;p&gt;{modal.description}&lt;/p&gt;
        &lt;button type=&quot;button&quot; onClick={modal.onButtonClick}&gt;
          Do something
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre><p>All that&apos;s left to do is set the behavior of that button in the modal properties when we dispatch the action to show the modal in the <code>App</code> component!</p><pre><code class="language-tsx">function App(props: AppProps) {
  const { dispatchShowModal } = props;

  return (
    &lt;&gt;
      &lt;Modal /&gt;
      &lt;div className=&quot;App&quot;&gt;
        &lt;header className=&quot;App-header&quot;&gt;
          &lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /&gt;
          &lt;button
            onClick={() =&gt; {
              dispatchShowModal({
                title: &apos;A new title.&apos;,
                description: &apos;And a new description too.&apos;,
                onButtonClick: (event: React.MouseEvent) =&gt; {
                  alert(&apos;You clicked that button!&apos;);
                },
              });
            }}
          &gt;
            Show Modal
          &lt;/button&gt;
        &lt;/header&gt;
      &lt;/div&gt;
    &lt;/&gt;
  );
}</code></pre><p>Click that button now! You should see an alert window with the sentence &quot;You clicked that button!&quot;.</p><figure class="kg-card kg-image-card"><img src="/content/images/2020/11/image-10.png" class="kg-image" alt="Creating a centralized modal in React with Redux" loading="lazy"></figure><h3 id="final-thoughts">Final thoughts</h3><p>I&apos;ve used polished, thoroughly tested versions of this approach in applications that are in production. For instance, to improve code reusability and maintainability I created a &quot;library&quot; of sorts that holds all modal definitions (like a list of items of type <code>ModalProperties</code>) so that when I want to change a modal that is reused in several places I only need to edit a single item. </p><p>Another way you can improve on this mechanic is to implement a stack of modals so that you don&apos;t lose a modal that is being shown in case another pops up.</p><p>The usage of TypeScript shown in this tutorial may be biased, and there may be better ways to type check Redux, so take it with a grain of salt.</p>]]></content:encoded></item><item><title><![CDATA[NGX-Translate and Server-Side Rendering - Angular Universal]]></title><description><![CDATA[With more than 400.000 weekly downloads, ngx-translate might just be the most used internationalization library for Angular. It works out-of-the-box wonderfully  on the client side, however it needs some tweaks to work with Angular Universal's SSR.]]></description><link>https://andremonteiro.pt/ngx-translate-angular-universal-ssr/</link><guid isPermaLink="false">6067007a8dbdc811cede1ef2</guid><category><![CDATA[Angular]]></category><category><![CDATA[Angular Universal]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Mon, 03 Aug 2020 18:50:26 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2020/08/thumbnail--2-.png" medium="image"/><content:encoded><![CDATA[<img src="https://andremonteiro.pt/content/images/2020/08/thumbnail--2-.png" alt="NGX-Translate and Server-Side Rendering - Angular Universal"><p>With more than 400.000 weekly downloads, ngx-translate might just be the most used internationalization library for Angular. It works out-of-the-box wonderfully on the client-side, however, it needs some tweaks to work with Angular Universal&apos;s SSR.</p><blockquote>NGX-Translate is an internationalization library for Angular. It lets you define translations for your content in different languages and switch between them easily.<br>- <a href="http://www.ngx-translate.com/">NGX-Translate: The i18n library for Angular 2+</a></blockquote><p>If you&apos;re not familiar with the library, I suggest reading their documentation on <a href="https://github.com/ngx-translate/core">GitHub</a>. </p><h3 id="the-issue-with-ssr">The issue with SSR</h3><p>The library provides a simple way to load the translation files on the client-side through their <a href="https://github.com/ngx-translate/http-loader">HTTP loader</a>. However, it does not work too well with the SSR solution the Angular team provides: Angular Universal.</p><p>In a previous post, <a href="https://andremonteiro.pt/caching-server-side-requests-ng-universal/">Caching server-side requests - Angular Universal</a>, I described an issue similar to the one that occurs when using ngx-translate. When using Angular Universal, I noticed that the content would &quot;blink&quot; because duplicate requests were being made, once on the server-side, and then again on the client-side.</p><p>The issue with ngx-translate is also related to the request of translation files. The files could not be retrieved over HTTP on the server-side, and as such the page would first appear in the browser with the translation keys, and only after the client receives the translations the translation keys would change to the actual translations.</p><h3 id="loading-the-translation-files-on-the-server-side">Loading the translation files on the server-side </h3><p>We need the translation files on the server-side. Working on the server-side, we can get the files through the file system. </p><p>First, I created a custom loader, <code>translate-server.loader.ts</code>, for the server module. It uses <code>TransferState</code> in order to later retrieve the translations on the client-side. </p><pre><code class="language-javascript">// shared/loaders/translate-server.loader.ts
import { join } from &apos;path&apos;;
import { Observable } from &apos;rxjs&apos;;
import { TranslateLoader } from &apos;@ngx-translate/core&apos;;
import {
  makeStateKey,
  StateKey,
  TransferState
} from &apos;@angular/platform-browser&apos;;
import * as fs from &apos;fs&apos;;

export class TranslateServerLoader implements TranslateLoader {
  constructor(
    private transferState: TransferState,
    private prefix: string = &apos;i18n&apos;,
    private suffix: string = &apos;.json&apos;
  ) {}

  public getTranslation(lang: string): Observable&lt;any&gt; {
    return new Observable((observer) =&gt; {
      const assets_folder = join(
        process.cwd(),
        &apos;dist&apos;,
        &apos;project-name&apos;, // Your project name here
        &apos;browser&apos;,
        &apos;assets&apos;,
        this.prefix
      );

      const jsonData = JSON.parse(
        fs.readFileSync(`${assets_folder}/${lang}${this.suffix}`, &apos;utf8&apos;)
      );

      // Here we save the translations in the transfer-state
      const key: StateKey&lt;number&gt; = makeStateKey&lt;number&gt;(
        &apos;transfer-translate-&apos; + lang
      );
      this.transferState.set(key, jsonData);

      observer.next(jsonData);
      observer.complete();
    });
  }
}

export function translateServerLoaderFactory(transferState: TransferState) {
  return new TranslateServerLoader(transferState);
}</code></pre><p>Then, I set the <code>TranslateModule</code>&apos;s settings on the <code>app.server.module.ts</code>.</p><pre><code class="language-javascript">// app.server.module.ts
import { NgModule } from &apos;@angular/core&apos;;
import {
  ServerModule,
  ServerTransferStateModule
} from &apos;@angular/platform-server&apos;;
import { AppModule } from &apos;./app.module&apos;;
import { AppComponent } from &apos;./app.component&apos;;
import { TranslateModule, TranslateLoader } from &apos;@ngx-translate/core&apos;;
import { translateServerLoaderFactory } from &apos;./shared/loaders/translate-server.loader&apos;;
import { TransferState } from &apos;@angular/platform-browser&apos;;

@NgModule({
  imports: [
    AppModule,
    ServerModule,
    ServerTransferStateModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: translateServerLoaderFactory,
        deps: [TransferState]
      }
    })
  ],
  bootstrap: [AppComponent]
})
export class AppServerModule {}</code></pre><p>To take advantage of loading the translation files on the server-side, I created another loader, <code>translate-browser.loader.ts</code>, to fetch the previously loaded data from <code>TransferState</code>. If it does not find the translations in the cache, it uses the HTTP loader to get them. </p><pre><code class="language-javascript">// shared/loaders/translate-browser.loader.ts
import { Observable } from &apos;rxjs&apos;;
import { TranslateLoader } from &apos;@ngx-translate/core&apos;;

import {
  makeStateKey,
  StateKey,
  TransferState
} from &apos;@angular/platform-browser&apos;;
import { TranslateHttpLoader } from &apos;@ngx-translate/http-loader&apos;;
import { HttpClient } from &apos;@angular/common/http&apos;;

export class TranslateBrowserLoader implements TranslateLoader {
  constructor(private http: HttpClient, private transferState: TransferState) {}

  public getTranslation(lang: string): Observable&lt;any&gt; {
    const key: StateKey&lt;number&gt; = makeStateKey&lt;number&gt;(
      &apos;transfer-translate-&apos; + lang
    );
    const data = this.transferState.get(key, null);

    // First we are looking for the translations in transfer-state, 
	// if none found, http load as fallback
    if (data) {
      return new Observable((observer) =&gt; {
        observer.next(data);
        observer.complete();
      });
    } else {
      return new TranslateHttpLoader(this.http).getTranslation(lang);
    }
  }
}

export function translateBrowserLoaderFactory(
  httpClient: HttpClient,
  transferState: TransferState
) {
  return new TranslateBrowserLoader(httpClient, transferState);
}
</code></pre><p>Finally, declare it in your <code>app.module.ts</code>. </p><pre><code class="language-javascript">// app.module.ts
import { BrowserModule, TransferState } from &apos;@angular/platform-browser&apos;;
import { NgModule } from &apos;@angular/core&apos;;
import { TranslateModule, TranslateLoader } from &apos;@ngx-translate/core&apos;;
import { TranslateHttpLoader } from &apos;@ngx-translate/http-loader&apos;;

import { AppRoutingModule } from &apos;./app-routing.module&apos;;
import { AppComponent } from &apos;./app.component&apos;;
import { HttpClient, HttpClientModule } from &apos;@angular/common/http&apos;;

import { TransferHttpCacheModule } from &apos;@nguniversal/common&apos;;
import { translateBrowserLoaderFactory } from &apos;./shared/loaders/translate-browser.loader&apos;;

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule.withServerTransition({ appId: &apos;serverApp&apos; }),
    TransferHttpCacheModule,
    HttpClientModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: translateBrowserLoaderFactory,
        deps: [HttpClient, TransferState]
      }
    }),
    AppRoutingModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}</code></pre><h3 id="final-thoughts">Final thoughts</h3><p>It may be helpful to load the translations on the server-side, if working with SSR, to deliver a page with the correct content faster. It is way more elegant to show the page with its true information instead of with the translation keys, even for a split second. </p>]]></content:encoded></item><item><title><![CDATA[Caching server-side requests - Angular Universal]]></title><description><![CDATA[If you are rendering your SPA using Angular Universal you may have noticed a common issue with the page loading: the content "blinks" and loads again. This behavior may occur due to duplicate requests being made, once in the server, and then in the client.]]></description><link>https://andremonteiro.pt/caching-server-side-requests-ng-universal/</link><guid isPermaLink="false">6067007a8dbdc811cede1ef1</guid><category><![CDATA[Angular]]></category><category><![CDATA[Angular Universal]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Express]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Wed, 17 Jun 2020 10:53:50 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2020/06/caching-server-side-requests-ng-universal-2.png" medium="image"/><content:encoded><![CDATA[<img src="https://andremonteiro.pt/content/images/2020/06/caching-server-side-requests-ng-universal-2.png" alt="Caching server-side requests - Angular Universal"><p>If you are rendering your SPA using Angular Universal you may have noticed a common issue with the page loading: the content &quot;blinks&quot; and loads again. This behavior may occur due to duplicate requests being made, once in the server, and then in the client. Angular Universal provides a module called <code>TransferHttpCacheModule</code> to tackle this problem by caching requests made while rendering the page on the server-side.</p><h3 id="prerequisites">Prerequisites</h3><p>Before starting, add Angular Universal to an existing Angular project by running the following schematic. </p><pre><code class="language-bash">ng add @nguniversal/express-engine</code></pre><p>I won&apos;t delve further into this topic. For an Angular Universal&apos;s beginners guide please refer to <a href="https://angular.io/guide/universal">Server-side rendering (SSR) with Angular Universal</a>.</p><h3 id="setting-up-caching">Setting up caching</h3><p>Setting up server-side caching is pretty easy. All you have to do is add <code>TransferHttpCacheModule</code> to your <code>app.module.ts</code>, and <code>ServerTransferStateModule</code> to your <code>app.server.module.ts</code>.</p><pre><code class="language-javascript">// app.module.ts
import { TransferHttpCacheModule } from &apos;@nguniversal/common&apos;;

@NgModule({
  imports: [
    (...)
    TransferHttpCacheModule
  ]
})
export class AppModule {}</code></pre><pre><code class="language-javascript">// app.server.module.ts
import { ServerTransferStateModule } from &apos;@angular/platform-server&apos;;

@NgModule({
  imports: [
    (...)
    ServerTransferStateModule
  ]
})
export class AppServerModule {}</code></pre><p>After adding these, you will see that the requests done in the server while the page is being rendered will not be duplicated in the browser.</p><h3 id="how-it-works">How it works</h3><p><code>TransferHttpCacheModule</code> provides a HTTP interceptor that uses the <code>TransferState</code> from <code>@angular/platform-browser</code>. <code>TransferState</code> is &quot;a key value store that is transferred from the application on the server side to the application on the client side&quot;, according to <a href="https://angular.io/api/platform-browser/TransferState">Angular&apos;s documentation</a>.</p><p>First, when intercepting a request, it checks the cache (key value store) to see if that specific request has been made. This may branch into two different behaviors whether the request has been cached or not. </p><p>If the request key is found in the key value store, it will handle the request by returning the cached response.</p><pre><code class="language-javascript">if (this.transferState.hasKey(storeKey)) {
  // Request found in cache. Respond using it.
  const response = this.transferState.get(storeKey, {} as TransferHttpResponse);

  return observableOf(new HttpResponse&lt;any&gt;({
    body: response.body,
    headers: new HttpHeaders(response.headers),
    status: response.status,
    statusText: response.statusText,
    url: response.url,
  }));
}</code></pre><p>If the request key is not found in the cache, it proceeds with the original request and sets a key-value pair to the <code>TransferState</code> cache with the response.</p><pre><code class="language-javascript">else {
  // Request not found in cache. Make the request and cache it.
  const httpEvent = next.handle(req);

  return httpEvent
    .pipe(
      tap((event: HttpEvent&lt;unknown&gt;) =&gt; {
        if (event instanceof HttpResponse) {
          this.transferState.set(storeKey, {
            body: event.body,
            headers: getHeadersMap(event.headers),
            status: event.status,
            statusText: event.statusText,
            url: event.url || &apos;&apos;,
          });
        }
      })
    );
}</code></pre><h3 id="handling-relative-path-requests">Handling relative path requests</h3><p>You may run into issues when using relative paths in requests on the server-side. You can use a HTTP interceptor in this case to transform your relative paths to absolute paths.</p><pre><code class="language-javascript">import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
  HttpEvent
} from &apos;@angular/common/http&apos;;
import { Observable } from &apos;rxjs&apos;;
import { Inject, Injectable } from &apos;@angular/core&apos;;
import { REQUEST } from &apos;@nguniversal/express-engine/tokens&apos;;
import { Request } from &apos;express&apos;;

function isAbsoluteUrl(url: string) {
  return url.startsWith(&apos;http&apos;) || url.startsWith(&apos;//&apos;);
}

@Injectable()
export class ServerStateInterceptor implements HttpInterceptor {
  constructor(@Inject(REQUEST) private request: Request) {}

  intercept(
    req: HttpRequest&lt;any&gt;,
    next: HttpHandler
  ): Observable&lt;HttpEvent&lt;any&gt;&gt; {
    if (this.request &amp;&amp; !isAbsoluteUrl(req.url)) {
      const protocolHost = `${this.request.protocol}://${this.request.get(
        &apos;host&apos;
      )}`;

      const pathSeparator = !req.url.startsWith(&apos;/&apos;) ? &apos;/&apos; : &apos;&apos;;
      const url = protocolHost + pathSeparator + req.url;
      const serverRequest = req.clone({ url });

      return next.handle(serverRequest);
    }

    return next.handle(req);
  }
}
</code></pre><p>This interceptor works explicitly with the Express engine, so if you are using another engine you will have to adapt it.</p><h3 id="final-thoughts">Final thoughts</h3><p>Angular provides out-of-the-box features to easily tackle the duplicate requests issue, with none to minimal configuration from the developer.</p><p>I found some other issues working with Angular Universal and third-party packages, so I will be writing about these in the near future.</p><p>Sources:</p><!--kg-card-begin: markdown--><ul>
<li><a href="https://angular.io/guide/universal">Server-side rendering (SSR) with Angular Universal</a></li>
<li><a href="https://github.com/angular/universal/blob/master/docs/transfer-http.md">TransferHttpCacheModule @ GitHub</a></li>
<li><a href="https://itnext.io/angular-universal-caching-transferstate-96eaaa386198">Angular Universal + Caching (TransferState) - ITNEXT</a></li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Understanding Hot and Cold Observables using RxJS]]></title><description><![CDATA[In this post I'll try to demystify ReactiveX's Observables, how they can be hot or cold, and how to turn one into another. By the way, it doesn't have anything to do with Katy Perry's 2008 song.]]></description><link>https://andremonteiro.pt/hot-vs-cold-observa/</link><guid isPermaLink="false">6067007a8dbdc811cede1eef</guid><category><![CDATA[Angular]]></category><category><![CDATA[ReactiveX]]></category><category><![CDATA[RxJS]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Wed, 08 Apr 2020 18:13:31 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2020/06/understanding-hot-cold-observables-rxjs.png" medium="image"/><content:encoded><![CDATA[<img src="https://andremonteiro.pt/content/images/2020/06/understanding-hot-cold-observables-rxjs.png" alt="Understanding Hot and Cold Observables using RxJS"><p>In this post I&apos;ll try to demystify ReactiveX&apos;s Observables, how they can be hot or cold, and how to turn one into another. By the way, it doesn&apos;t have anything to do with Katy Perry&apos;s 2008 song.</p><h3 id="what-is-an-observable">What is an Observable?</h3><p>An Observable is an object that emits objects and can be subscribed by an observer (or subscriber). When an observer subscribes to an Observable, the observer must specify a reaction that will be triggered when the Observable emits a value. This behavior allows a system to have concurrent actions as it won&apos;t need to block until values are received. Observables may be hot or cold, the difference between them being that they start emitting objects at different times.</p><h3 id="what-are-cold-observables">What are cold Observables?</h3><p>A <strong>cold</strong> Observable waits until an observer subscribes to it to start emitting. Observables are lazy by default, meaning they only execute when an observer subscribes to it. This behavior allows an observer to observe the entire sequence of emitted values.</p><pre><code class="language-typescript">import { Observable, interval } from &apos;rxjs&apos;;

const observable$ = new Observable((observer) =&gt; {
  const interval$ = interval(1000);

  interval$.subscribe((value: number) =&gt; {
    observer.next(value);
  });
});

observable$.subscribe((value) =&gt; {
  this.logger.log(&apos;Subcription #1 - Received:&apos;, value);
});

setTimeout(() =&gt; {
  observable$.subscribe((value) =&gt; {
    this.logger.log(&apos;Subcription #2 - Received:&apos;, value);
  });
}, 2500);

// Logs
// Subcription #1 - Received: 0
// Subcription #1 - Received: 1
// Subcription #1 - Received: 2
// Subcription #2 - Received: 0
// Subcription #1 - Received: 3
// Subcription #2 - Received: 1
// Subcription #1 - Received: 4
// Subcription #2 - Received: 2</code></pre><p>The example above illustrates the behavior of a <strong>cold </strong>Observable. Notice that the sequence of values received in the second subscription is totally independent from the first one - this is called <strong>unicasting</strong>.</p><h3 id="what-are-hot-observables">What are hot Observables?</h3><p>A <strong>hot </strong>Observable will start emitting as soon as it&apos;s created, and as such the values it emits are produced outside of it. A hot Observable&apos;s emitted objects are shared between its subscribers - this is called <strong>multicasting</strong>. Because of this behavior, an observer may start observing the sequence somewhere in the middle of it.</p><pre><code class="language-typescript">import { Observable, Subject, interval } from &apos;rxjs&apos;;

const subject$ = new Subject();

interval(1000).subscribe((value: number) =&gt; {
  subject$.next(value);
});

const observable$ = new Observable((observer) =&gt; {
  subject$.subscribe((value: number) =&gt; {
    observer.next(value);
  });
});

observable$.subscribe((value) =&gt; {
  this.logger.log(&apos;Subcription #1 - Received:&apos;, value);
});

setTimeout(() =&gt; {
  observable$.subscribe((value) =&gt; {
    this.logger.log(&apos;Subcription #2 - Received:&apos;, value);
  });
}, 2500);

// Logs
// Subcription #1 - Received: 0
// Subcription #1 - Received: 1
// Subcription #1 - Received: 2
// Subcription #2 - Received: 2
// Subcription #1 - Received: 3
// Subcription #2 - Received: 3
// Subcription #1 - Received: 4
// Subcription #2 - Received: 4</code></pre><p>The example above illustrates the behavior of a <strong>hot</strong> Observable. Notice that the second subscription set of received values starts with &quot;2&quot;, meaning that it started observing in the middle of the sequence. </p><h3 id="turning-a-cold-observable-hot">Turning a cold Observable hot</h3><p>To turn a cold Observable hot we use a special kind of Observable named <strong>Subject</strong>. Subjects work both as Observables and observers: it can subscribe to other Observables and reemit the items it observes, and also emit new objects.</p><pre><code class="language-typescript">createHotObservable&lt;T&gt;(coldObservable: Observable&lt;T&gt;) {
  const subject$ = new Subject();
  coldObservable.subscribe(subject$);

  // Returns teardown logic, i.e. function called when the observable is unsubscribed
  return new Observable((observer) =&gt; {
    const sub = subject$.subscribe(observer);
    
    return () =&gt; {
      sub.unsubscribe();
    };
  });
}</code></pre><p>This method doesn&apos;t track the source subscription, which means it is possible to have a subscription open when unnecessary. For that, we&apos;ll keep a reference count for how many subscriptions there are for our hot Observable, and when that counter reaches zero unsubscribe to the source.</p><figure class="kg-card kg-code-card"><pre><code class="language-typescript">createHotObservable&lt;T&gt;(coldObservable: Observable&lt;T&gt;) {
  const subject$ = new Subject();
  const sourceSub = coldObservable.subscribe(subject$);
  let refCount = 0;

  return new Observable((observer) =&gt; {
    refCount++;
    const sub = subject$.subscribe(observer);

    return () =&gt; {
      refCount--;
      sub.unsubscribe();
      if (refCount === 0) {
        sourceSub.unsubscribe();
      }
    };
  });
}</code></pre><figcaption>Thank you <a href="https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339">Ben Lesh</a> for the great example with a refCount!&#xA0;</figcaption></figure><h3 id="making-a-hot-observable-cold">Making a hot Observable cold</h3><p>Let&apos;s assume there&apos;s a function <code>websocket</code> which creates a connection using WebSockets to an endpoint as soon as it&apos;s called and returns a hot Observable. If we wish to turn this Observable to cold, we can&apos;t call this function and pass the result to a function as we did in the previous section. Instead, we will create an Observable factory, i.e. a function that returns an Observable.</p><pre><code class="language-typescript">const observableFactory = () =&gt; websocket();</code></pre><p>We can pass this factory to the method below to create a cold Observable from a hot one.</p><pre><code class="language-typescript">createColdObservable&lt;T&gt;(observableFactory: () =&gt; Observable&lt;T&gt;): Observable&lt;T&gt; {
  return new Observable((subscriber) =&gt; {
    const subscription = observableFactory().subscribe(subscriber);

    return () =&gt; {
      subscription.unsubscribe();
    };
  });
}</code></pre><p>Using the result of this function, the (previously) hot Observable will only start emitting values when it is subscribed. </p><h3 id="final-thoughts">Final thoughts</h3><p>ReactiveX creates a whole plethora of possibilities for asynchronous operations in a system. Observables may seem confusing and complex at first, but don&apos;t give up on them, they&apos;re worthwhile learning. </p><!--kg-card-begin: markdown--><p>Sources:</p>
<ul>
<li><a href="http://reactivex.io">ReactiveX</a></li>
<li><a href="https://www.learnrxjs.io">Learn RxJS</a></li>
<li><a href="https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339">Hot vs Cold Observables - Ben Lesh - Medium</a></li>
<li><a href="https://medium.com/@luukgruijs/understanding-hot-vs-cold-observables-62d04cf92e03">Understanding hot vs cold Observables - Luuk Gruijs - Medium</a></li>
</ul>
<!--kg-card-end: markdown--><p></p>]]></content:encoded></item><item><title><![CDATA[Introduction to using Redux with React Native]]></title><description><![CDATA[According to the State of JavaScript 2019, React, React Native and Redux can be found in the top three of most used frameworks, in their respective categories. I thought the timing is right to learn more about these frameworks, and thus improving my knowledge in JavaScript and its ecosystem.]]></description><link>https://andremonteiro.pt/react-native-and-redux/</link><guid isPermaLink="false">6067007a8dbdc811cede1eee</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><category><![CDATA[React Native]]></category><category><![CDATA[Redux]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Tue, 04 Feb 2020 15:26:10 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2020/06/intro-redux-react-native.png" medium="image"/><content:encoded><![CDATA[<img src="https://andremonteiro.pt/content/images/2020/06/intro-redux-react-native.png" alt="Introduction to using Redux with React Native"><p>According to the <a href="https://2019.stateofjs.com">State of JavaScript 2019</a>, React, React Native and Redux can be found in the top three of most used frameworks, in their respective categories. I thought the timing is right to learn more about these frameworks, and thus improving my knowledge in JavaScript and its ecosystem.</p><p>I recommend going through React&apos;s and Redux&apos;s official documentation and following the &quot;getting started&quot; tutorials to get acquainted with the frameworks.</p><h3 id="creating-a-new-react-native-project">Creating a new React Native project</h3><p>In this article we will be creating a simple counter application. First, make sure you have <code>react-native</code> installed. I decided to install its CLI globally.</p><pre><code class="language-bash">npm install -g react-native</code></pre><p>Let&apos;s create a new React Native project using its CLI. I&apos;m using TypeScript, so I have to specify the a template. You may use JavaScript if you wish, but please notice that file extensions and some code syntax may differ.</p><pre><code class="language-bash">react-native init MyCounter

# To use TypeScript:
react-native init MyCounter --template react-native-template-typescript@6.2.0</code></pre><p>It will download the starter template, and install its dependencies. After that, you&apos;ll notice you have a file called <code>App.tsx</code> - this will be your application&apos;s entry point. For arrangement purposes, I created a <code>src</code> folder for the source code in the root of the project and moved <code>App.tsx</code> there, and consequently updated the import inside <code>index.js</code>.</p><pre><code class="language-javascript">import App from &apos;./src/App&apos;;</code></pre><h3 id="adding-react-navigation-to-the-app">Adding React Navigation to the app</h3><p></p><blockquote>React Navigation is born from the React Native community&apos;s need for an extensible yet easy-to-use navigation solution written entirely in JavaScript (so you can read and understand all of the source), on top of powerful native primitives.<br><br>- <a href="https://reactnavigation.org/docs/en/getting-started.html">Getting started &#xB7; React Navigation</a></blockquote><p>Run the following command to install React Navigation. In my case, I ran into a problem - some modules couldn&apos;t be resolved. If you find that issue, install the other packages in the excerpt below. </p><pre><code class="language-bash">npm install --save react-navigation react-native-gesture-handler react-navigation-stack

# If modules cannot be resolved:
npm install --save @react-native-community/masked-view react-native-safe-area-context</code></pre><p>I created a <code>HomeScreen.tsx</code> file under <code>src/screens/home/</code>, and I will leave it empty for now. </p><pre><code class="language-typescript">// src/screens/home/HomeScreen.tsx
import React, { Component } from &apos;react&apos;;
import { StyleSheet, View } from &apos;react-native&apos;;

class HomeScreen extends Component {
  render() {
    return (
      &lt;View style={styles.container}&gt;
      &lt;/View&gt;
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: &apos;center&apos;,
    alignItems: &apos;center&apos;
  }
});

export default HomeScreen;</code></pre><p>Let&apos;s get our app ready to show the home screen once it starts. For that, we create a stack navigator and an app container, and render this container as an element in <code>App.tsx</code>.</p><pre><code class="language-typescript">// src/App.tsx
import React, { Component } from &apos;react&apos;;
import { createAppContainer } from &apos;react-navigation&apos;;
import { createStackNavigator } from &apos;react-navigation-stack&apos;;
import HomeScreen from &apos;./screens/home/HomeScreen&apos;;

const MainNavigator = createStackNavigator({
  Home: { screen: HomeScreen }
});

const Navigation = createAppContainer(MainNavigator);

export default class App extends Component {
  render() {
    return (
      &lt;Navigation /&gt;
    );
  }
}</code></pre><p>If you run your app, it will show a blank activity with a toolbar on top that says &quot;Home&quot;. We will add a counter to the page now, with two buttons to increment and decrement it. </p><pre><code class="language-typescript">// src/screens/home/HomeScreen.tsx

class HomeScreen extends Component {
  state = {
    counter: 0
  };

  increment() {
    this.setState({ counter: this.state.counter + 1 });
  }

  decrement() {
    this.setState({ counter: this.state.counter - 1 });
  }

  render() {
    const { counter } = this.state;

    return (
      &lt;View style={styles.container}&gt;
        &lt;Button title=&quot;increment&quot; onPress={() =&gt; this.increment()} /&gt;
        &lt;Text&gt;{counter}&lt;/Text&gt;
        &lt;Button title=&quot;decrement&quot; onPress={() =&gt; this.decrement()} /&gt;
      &lt;/View&gt;
    );
  }
}</code></pre><p>The screen should look like this now:</p><figure class="kg-card kg-image-card"><img src="/content/images/2020/01/image.png" class="kg-image" alt="Introduction to using Redux with React Native" loading="lazy"></figure><h3 id="adding-redux-actions-and-reducers">Adding Redux actions and reducers</h3><p>If you haven&apos;t installed Redux yet in your project, do so using the following command. </p><pre><code class="language-bash">npm i --save redux react-redux</code></pre><blockquote>Actions are JavaScript objects that represent payloads of information that send data from your application to your Redux store.<br><br> - <a href="https://alligator.io/react/react-native-redux/">Introduction to Using Redux in a React Native App &#x2190; Alligator.io</a></blockquote><p>We&apos;ll need an action that changes the counter. So, I created a file <code>index.ts</code> in <code>src/core/store/actions/</code> to declare my Redux actions. </p><pre><code class="language-typescript">// src/core/store/actions/index.ts
export const ACTION_TYPES = { COUNTER_CHANGE: &apos;COUNTER_CHANGE&apos; };

export function changeCount(count) {
  return {
    payload: count,
    type: ACTION_TYPES.COUNTER_CHANGE
  };
}
</code></pre><p>In this file I&apos;ve create a constant <code>ACTION_TYPES</code> which will hold all the action types, and a <code>changeCount</code> function that receives a <code>count</code> parameter and returns an object with a payload and an action of the type <code>COUNTER_CHANGE</code>. </p><p>Now for the reducer...</p><blockquote>A <code>reducer</code> is a pure function that takes the previous <code>state</code> and an <code>action</code> as arguments and returns a new state.<br><br> - <a href="https://alligator.io/react/react-native-redux/">Introduction to Using Redux in a React Native App &#x2190; Alligator.io</a></blockquote><p>Let&apos;s now create a file for our reducer, <code>index.ts</code>, inside the folder <code>src/core/store/reducers/</code>. </p><pre><code class="language-typescript">// src/core/store/reducers/index.ts
import { Reducer, combineReducers } from &apos;redux&apos;;
import { ACTION_TYPES } from &apos;../actions&apos;;

const INITIAL_STATE = {
  count: 0
};

const countReducer: Reducer = (state = INITIAL_STATE, action) =&gt; {
  switch (action.type) {
    case ACTION_TYPES.COUNTER_CHANGE:
      return { ...state, count: action.payload };
    default:
      return state;
  }
};

export default combineReducers({
  count: countReducer
});</code></pre><p>This piece of code is pretty standard. It declares a new Reducer that receives the previous state and an action, and returns a new state, in this case overwriting the <code>count</code> property.</p><h3 id="connecting-redux-to-the-screen">Connecting Redux to the screen</h3><p>Open <code>App.tsx</code> and edit its <code>render</code> method. The <code>Navigation</code> element will now be nested in a <code>Provider</code> element. This way, every page will have access to our Redux store. </p><pre><code class="language-typescript">// src/App.tsx
// There is code omitted, don&apos;t delete the previous changes

import { Provider } from &apos;react-redux&apos;;
import { createStore } from &apos;redux&apos;;
import countReducer from &apos;./core/store/reducers/index&apos;;

const store = createStore(countReducer);

export default class App extends Component {
  render() {
    return (
      &lt;Provider store={store}&gt;
        &lt;Navigation /&gt;
      &lt;/Provider&gt;
    );
  }
}</code></pre><p>Next, we&apos;ll connect the home screen to the store, using two different objects. <code>mapStateToProps</code> will extract the data from the store to the component&apos;s properties, and <code>mapDispatchToProps</code> will be used to dispatch actions to the store. Moreover, we&apos;ll define the behavior of both increment and decrement buttons. </p><pre><code class="language-typescript">// src/screens/home/HomeScreen.tsx
import React, { Component } from &apos;react&apos;;
import { Button, StyleSheet, Text, View } from &apos;react-native&apos;;
import { connect } from &apos;react-redux&apos;;
import { bindActionCreators } from &apos;redux&apos;;
import { changeCount } from &apos;../../core/store/actions&apos;;

class HomeScreen extends Component {
  increment() {
    let { store, actions } = this.props;
    store.count++;
    actions.changeCount(store.count);
  }

  decrement() {
    let { store, actions } = this.props;
    store.count--;
    actions.changeCount(store.count);
  }

  render() {
    const { store } = this.props;

    return (
      &lt;View style={styles.container}&gt;
        &lt;Button title=&quot;increment&quot; onPress={() =&gt; this.increment()} /&gt;
        &lt;Text&gt;{store.count}&lt;/Text&gt;
        &lt;Button title=&quot;decrement&quot; onPress={() =&gt; this.decrement()} /&gt;
      &lt;/View&gt;
    );
  }
}

// styles...

const mapStateToProps = state =&gt; ({
  // Change the property name to whatever you want it to be called
  // In my case, I chose &apos;store&apos;
  store: state.count
});

const mapDispatchToProps = dispatch =&gt; ({
  actions: bindActionCreators(
    {
      changeCount
    },
    dispatch
  )
});

export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen);
</code></pre><p>Notice that the <code>this.props</code> used inside the component&apos;s methods are the values obtained from <code>mapStateToProps</code> and <code>mapDispatchToProps</code>, namely the store and actions. </p><h3 id="final-thoughts">Final thoughts</h3><p>Although simple, this app covers a lot from the React and Redux ecosystem for a beginner. There is a lot more that you can do with Redux, such as persisting your store using <a href="https://github.com/rt2zz/redux-persist">Redux Persist</a>, or <a href="https://redux.js.org/faq/miscellaneous/#how-can-i-implement-authentication-in-redux">implement authentication</a> to keep unauthorized users from accessing the store.</p>]]></content:encoded></item><item><title><![CDATA[iOS 13 and Bluetooth Permissions - Issues I've experienced working with Ionic Native]]></title><description><![CDATA[After updating to iOS 13, I've begun receiving a prompt to allow my application to use Bluetooth. In reality, a lot of apps started asking for Bluetooth permission. This caught me by surprise because I did not know my app used Bluetooth and because I did not want it to use Bluetooth. ]]></description><link>https://andremonteiro.pt/ios-bluetooth-permissions-ionic-native/</link><guid isPermaLink="false">6067007a8dbdc811cede1eeb</guid><category><![CDATA[Programming]]></category><category><![CDATA[Ionic]]></category><category><![CDATA[Cordova]]></category><category><![CDATA[iOS]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Thu, 02 Jan 2020 16:00:00 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2020/06/ios-bluetooth-permissions-ionic.png" medium="image"/><content:encoded><![CDATA[<img src="https://andremonteiro.pt/content/images/2020/06/ios-bluetooth-permissions-ionic.png" alt="iOS 13 and Bluetooth Permissions - Issues I&apos;ve experienced working with Ionic Native"><p>After updating to iOS 13, I&apos;ve begun receiving a prompt to allow my application to use Bluetooth. In reality, <a href="https://www.theverge.com/2019/9/19/20867286/ios-13-bluetooth-permission-privacy-feature-apps">a lot of apps started asking for Bluetooth permission</a>. This caught me by surprise because I did not know my app used Bluetooth and because I did not want it to use Bluetooth. </p><p>I found an <a href="https://github.com/dpa99c/cordova-diagnostic-plugin/issues/365">issue</a> on GitHub from September 19, 2019, which explains why I was having this issue. The app uses the Cordova plugin referenced in the issue: cordova.plugins.diagnostic. This plugin is used to &quot;manage device settings such as Location, Bluetooth and WiFi&quot;, and I was specifically using it to request the Location permission and check if the Wi-Fi is on. </p><p>It was my first time submitting to App Store so, na&#xEF;ve as I was, I tried to send the app for review without removing the Bluetooth alert, just changing the purpose string. For it, I added the following lines to config.xml.</p><pre><code class="language-xml">&lt;config-file parent=&quot;NSBluetoothAlwaysUsageDescription&quot; platform=&quot;ios&quot; target=&quot;*-Info.plist&quot;&gt;
    &lt;string&gt;Bluetooth permission is required because of X, Y and Z&lt;/string&gt;
&lt;/config-file&gt;</code></pre><p>Of course, I received an email from Apple:</p><blockquote><em>During review, we were prompted to provide consent to access the Bluetooth. However, we were not able to locate any features in your app that use the Bluetooth.<br><br>If your app does not include any features that use the Bluetooth, please remove access to the Bluetooth from your app.</em></blockquote><p>The easy way didn&apos;t work out, so I guess I had to make sure my app doesn&apos;t request this feature. After a quick check on the documentation, I found out that <a href="https://github.com/dpa99c/cordova-diagnostic-plugin#specifying-modules">modules can be specified</a>. By default, all modules are added to the project. I followed their suggestion to add a preference to config.xml stating which modules I wanted to include.</p><figure class="kg-card kg-code-card"><pre><code class="language-xml">&lt;preference name=&quot;cordova.plugins.diagnostic.modules&quot; value=&quot;LOCATION WIFI&quot; /&gt;</code></pre><figcaption>So... I removed Bluetooth and a couple more. (Full list of modules <a href="https://github.com/dpa99c/cordova-diagnostic-plugin#specifying-modules">here</a>)</figcaption></figure><p>I had to uninstall the plugin and reinstall it after adding this preference. Basically, during the plugin installation, parts of plugin.xml get commented so the files for the modules left out of the preference are excluded. After that, I removed the iOS platform, added it again and built the app.</p><p>I would rather have the plugin add nothing by default, making the developer choose the plugins it needs instead of importing a lot of unnecessary code.</p><hr><p>I have a love-hate relationship with <a href="https://ionicframework.com">Ionic</a>. While I like that this framework allows me to use <a href="https://angular.io">Angular</a> to develop mobile applications (an environment I&apos;m personally fond of), I encounter problems with its plugins more often than not.</p><p>Ionic is a very powerful framework for hybrid mobile applications that look and feel native, both through UI components that look like the <a href="https://material.io">Material</a> and iOS ones, and plugins to use the devices&apos; functionalities (e.g. camera, location). It&apos;s built on top of <a href="https://cordova.apache.org">Apache Cordova</a>, which is a framework for building mobile applications using HTML, CSS and JavaScript instead of platform-specific APIs. Cordova can be extended using native plugins, creating links between the native layer and the web application. </p><p>I&apos;ve experienced countless issues with the native plugins, often because of incompatibilities with each other or with updated versions of the Cordova platforms. Through a series of posts, I will try to summarize some of those problems I encountered, the investigations I did, and how I solved them through the means at my disposal.</p>]]></content:encoded></item><item><title><![CDATA[Server-Side Rendering on Firebase Cloud Functions using Angular Universal]]></title><description><![CDATA[Breaking down the hard task of deploying an Angular Universal application to Firebase with Hosting and Cloud Functions. ]]></description><link>https://andremonteiro.pt/angular-universal-ssr-on-firebase/</link><guid isPermaLink="false">6067007a8dbdc811cede1eea</guid><category><![CDATA[Programming]]></category><category><![CDATA[Angular]]></category><category><![CDATA[Firebase]]></category><category><![CDATA[SysAdmin]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Mon, 18 Nov 2019 09:00:00 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2020/06/ssr-firebase-cloud-functions.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://andremonteiro.pt/content/images/2020/06/ssr-firebase-cloud-functions.png" alt="Server-Side Rendering on Firebase Cloud Functions using Angular Universal"><p>I start a lot of projects that never see the daylight. One of those projects was a tracker of prices of a specific store, which had a single page web application to consult the results, developed using Angular. I wanted to make it available on the Internet, and so I decided to change the project to use Angular Universal for a couple of reasons.</p>
<blockquote>
<p><em>1. Facilitate web crawlers through search engine optimization (SEO)</em><br>
<em>2. Improve performance on mobile and low-powered devices</em><br>
<em>3. Show the first page quickly with a first-contentful paint (FCP)</em></p>
<p>(<a href="https://angular.io/guide/universal#why-use-server-side-rendering">Source</a>)</p>
</blockquote>
<!--kg-card-end: markdown--><p><a href="https://firebase.google.com">Firebase</a> is a platform for web and mobile development. I usually choose it to host my personal projects for two major reasons:</p><ul><li>The Spark plan (free tier) is pretty generous, and provides all the services I need - a key-value database (Cloud Firestore), hosting for static websites, and a serverless execution environment (Cloud Functions);</li><li><a href="https://github.com/angular/angularfire">AngularFire</a>, the &quot;official library for Firebase and Angular&quot;, is a great library that is easy to use and has support for most Firebase functionalities.</li></ul><p>Before starting, make sure you have <a href="https://nodejs.org">Node.js</a>, <a href="https://cli.angular.io">Angular</a> and <a href="https://github.com/firebase/firebase-tools">Firebase Tools</a> installed.</p><!--kg-card-begin: markdown--><style>    
    .collapsible {
        cursor: pointer;
    }
    
    .collapsible:after {
        content: '\002B';
        cursor: pointer;
        margin-left: 15px;
    }

    .active:after {
        content: "\2212";
    }

    .content {
        width: 100%;
        max-height: 0;
        margin-bottom: 1em;
        overflow: hidden;
        transition: max-height 0.2s ease-out;
    }
</style>
<script>
    $(document).ready(function(){
        var coll = document.getElementsByClassName("collapsible");
        var i;

        for (i = 0; i < coll.length; i++) {
            coll[i].addEventListener("click", function() {
                this.classList.toggle("active");
                var content = this.nextElementSibling;
                if (content.style.maxHeight){
                    content.style.maxHeight = null;
                } else {
                    content.style.maxHeight = content.scrollHeight + "px";
                } 
            });
        }
    });
</script>
<h3 class="collapsible">Table of Contents</h3>
<div class="content">
<ol>
<li><a href="#adding-angular-universal-to-a-project">Adding Angular Universal to a project</a></li>
<li><a href="#testing-locally">Testing locally</a></li>
<li><a href="#initializing-a-firebase-project">Initializing a Firebase project</a></li>
<li><a href="#removing-the-express-server-listener-and-updating-the-webpack-config">Removing the Express Server Listener and updating the Webpack config</a></li>
<li><a href="#copy-the-angular-app-to-the-function-environment">Copy the Angular app to the Function environment</a></li>
<li><a href="#deploying-the-application">Deploying the application</a></li>
<li><a href="#final-thoughts">Final thoughts</a></li>
</ol>
</div><!--kg-card-end: markdown--><h3 id="adding-angular-universal-to-a-project">Adding Angular Universal to a project</h3><p>To use Angular Universal to an existing Angular project, we add the published package <code>@nguniversal/express-engine</code> using the following command: </p><pre><code class="language-bash">ng add @nguniversal/express-engine --clientProject myProjectName</code></pre><p>This adds some new, important files to the project. There are three new files related to the Angular Universal app, which is used to render content on the server-side:</p><ul><li>tsconfig.server.json</li><li>src/main.server.ts</li><li>src/app/app.server.module.ts</li></ul><p>Also, there are files for the <a href="https://expressjs.com">Express.js</a> server, which will be used to handle requests and responses:</p><ul><li>server.ts</li><li>webpack.server.config.js</li></ul><h3 id="testing-locally">Testing locally</h3><p>In <code>package.json</code> you&apos;ll notice there are four new scripts related to Universal. To run the app locally, run the following scripts: </p><pre><code class="language-bash">npm run build:ssr &amp;&amp; npm run serve:ssr</code></pre><p>The app should now be running on <code>localhost:4000</code>.</p><p>Some errors may occur, such as missing <code>XHLHttpRequest</code>. To solve that, we need to install some <a href="https://en.wikipedia.org/wiki/Polyfill_(programming)">polyfills</a>. </p><p>Polyfills are pieces of code that implement features on web browsers that do not support those features. Firebase uses Websockets and XHR not included in Angular that we need to polyfill [<a href="#sources">2</a>].</p><pre><code class="language-bash">npm install ws xhr2 bufferutil utf-8-validate -D</code></pre><h3 id="initializing-a-firebase-project">Initializing a Firebase project</h3><p>Assuming you&apos;ve installed Firebase tools, initialize a Firebase project in the same folder as the Angular app with the Hosting and Cloud Functions services. Feel free to take a break and go read about these services if you are not familiar with the Firebase environment.</p><pre><code class="language-bash">firebase init
# Select: hosting, functions</code></pre><p>Now, let&apos;s redirect all traffic from hosting to a function, which we will call <code>ssr</code>. </p><pre><code class="language-json">// firebase.json

&quot;hosting&quot;: {
    &quot;public&quot;: &quot;dist/browser&quot;,
    // ...
    &quot;rewrites&quot;: [
    	{
        	&quot;source&quot;: &quot;**&quot;,
        	&quot;function&quot;: &quot;ssr&quot;
      	}
    ]
}</code></pre><h3 id="removing-the-express-server-listener-and-updating-the-webpack-config">Removing the Express Server Listener and updating the Webpack config</h3><p>In a normal server, we would just run <code>server.ts</code> using Node.js and forget about it, making Express.js deal with all the requests. Cloud Functions already do that under the hood, so our application does not need to listen for requests, therefore we have to change the code. In <code>server.ts</code> remove or comment out the request listener.</p><pre><code class="language-javascript">// server.ts
// Remove these lines &#x1F447;

// Start up the Node server
// app.listen(PORT, () =&gt; {
//   console.log(`Node Express server listening on http://localhost:${PORT}`);
// })</code></pre><p>In <code>webpack.server.config.js</code>, update the &quot;output&quot; property. These changes tell Webpack to package the server code as a library so it can be consumed by a Cloud Function.</p><pre><code class="language-javascript">output: {
    path: path.join(__dirname, &apos;dist&apos;),
    library: &apos;app&apos;,
    libraryTarget: &apos;umd&apos;,
    filename: &apos;[name].js&apos;,
}</code></pre><p>Rebuild the app again using <code>npm run build:ssr</code>.</p><h3 id="copy-the-angular-app-to-the-function-environment">Copy the Angular app to the Function environment</h3><p>Let&apos;s automate copying the app to the Function environment. Navigate to the functions directory and install a necessary package: fs-extra.</p><pre><code class="language-bash">cd functions
npm i fs-extra</code></pre><p>Next, we&apos;ll create the script with the name <code>cp-angular.js</code>, and then update the build script to automate the copy in <code>functions/package.json</code>.</p><pre><code class="language-javascript">// functions/cp-angular.js

const fs = require(&apos;fs-extra&apos;);

(async() =&gt; {

    const src = &apos;../dist&apos;;
    const copy = &apos;./dist&apos;;

    await fs.remove(copy);
    await fs.copy(src, copy);

})();</code></pre><pre><code class="language-json">// functions/package.json

{
  &quot;name&quot;: &quot;functions&quot;,
  &quot;engines&quot;: {
    &quot;node&quot;: &quot;8&quot;
  },
  &quot;scripts&quot;: {
    &quot;build&quot;: &quot;node cp-angular &amp;&amp; tsc&quot;
  }
}</code></pre><p>Now we need to create the Cloud Function. We need to state that whenever an HTTPS request is made to our server, it is redirected to our Angular Universal app. </p><pre><code class="language-javascript">// functions/index.ts

import * as functions from &apos;firebase-functions&apos;;
const universal = require(`${process.cwd()}/dist/server`).app;

export const ssr = functions.https.onRequest(universal);</code></pre><h3 id="deploying-the-application">Deploying the application</h3><p>All there&apos;s left to do is build both Angular and Firebase projects, and serve the latter. If everything looks good, deploy it!</p><pre><code class="language-bash"># /
npm run build:ssr
cd functions

# /functions
npm run build
cd ..

# /
firebase serve

# If everything is ok
firebase deploy</code></pre><h3 id="final-thoughts">Final thoughts</h3><p>In my opinion, it turned out to be quite difficult to deploy an Angular Universal application to the Firebase Cloud Functions. I&apos;ve decided to go with Functions as I wanted to keep all my assets on the same platform, but there are easier alternatives: you can deploy it to a common <a href="https://www.vultr.com/?ref=8282306">VPS</a> or use a serverless computing platform such as Google App Engine (which deployment is covered in <a href="https://fireship.io/lessons/angular-universal-firebase/#deploy-option-a-appengine-node-standard/">Angular Universal SSR with Firebase</a>). </p><!--kg-card-begin: markdown--><p><span id="sources"><span>Sources: [<a href="https://angular.io/guide/universal">1</a>] [<a href="https://fireship.io/lessons/angular-universal-firebase/">2</a>]</span></span></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Semantic Versioning and why it's important - a story on dependency hell]]></title><description><![CDATA[A project I worked on was running fine for a long time when they informed me that it was crashing after a new build, all because of package versioning. ]]></description><link>https://andremonteiro.pt/semantic-versioning-and-why-its-important/</link><guid isPermaLink="false">6067007a8dbdc811cede1ee9</guid><category><![CDATA[Programming]]></category><category><![CDATA[Node]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Mon, 11 Nov 2019 09:00:00 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2020/06/semantic-versioning-and-why-its-important.png" medium="image"/><content:encoded><![CDATA[<img src="https://andremonteiro.pt/content/images/2020/06/semantic-versioning-and-why-its-important.png" alt="Semantic Versioning and why it&apos;s important - a story on dependency hell"><p>Some time ago I was working on a back-end application using <a href="https://nestjs.com">NestJS</a>. Everything was running fine for weeks when, out of nowhere, they informed me that the solution was crashing at run time after a new build. </p><pre><code>SyntaxError: Unexpected token ...</code></pre><p>After some inspection, I found out the error was originating from the ws package. The build process was changing one instruction which broke the whole application!</p><pre><code class="language-javascript">// Original instruction
Object.assign({}, this._options.zlibInflateOptions, { windowBits })

// After build
{ ...this._options.zlibInflateOptions, ...windowBits }</code></pre><p>I started looking for the problem on Google. There were issues at GitHub and <a href="https://stackoverflow.com/questions/33745118/browserify-babel-6-gulp-unexpected-token-on-spread-operator">questions</a> at StackOverflow similar to mine. All the answers I was finding advised adding a specific plugin for Babel. </p><!--kg-card-begin: markdown--><blockquote>
<p>This plugin allows Babel to transform rest properties for object destructuring assignment and spread properties for object literals.</p>
</blockquote>
<!--kg-card-end: markdown--><p>There was only one problem: <strong>I wasn&apos;t using Babel at all</strong>. &#xA0;This was not a solution for me, but it pointed me in the right direction. I read in some of the answers that the spread operator was introduced in <a href="https://en.wikipedia.org/wiki/ECMAScript">ES6</a> (or ES2015). I thought that, maybe, the Node.js version I was using to run the solution (6.9.5) did not support ES6. </p><p>I went to <a href="https://node.green/#ES2015">Node.js ES2015 Support</a> to check if I was right. I found the feature compatibility under &quot;<a href="https://github.com/tc39/proposal-object-rest-spread">object spread properties</a>&quot; and found out that the version I had doesn&apos;t support said feature. The fastest solution would be to update Node to version 8.3.0, at least, but I could not do that because of requirements, so I had to make sure I could make it work in that Node version. Anyways, it was running fine earlier, so what changed?</p><pre><code>@nestjs/websockets
&#x2514;&#x2500;  socket.io
    &#x2514;&#x2500;  engine.io
        &#x2514;&#x2500;  ws</code></pre><p>I began the &quot;dissection&quot; of the packages, in search of the problem. The first thing I did was to find the chain of dependencies that lead to this problem.</p><p>After that, I checked the release notes for each of those packages and found out that the ws package dropped the support for Node 6 on their version 7 on their <a href="https://github.com/websockets/ws/releases/tag/7.0.0">GitHub</a>.</p><p>&quot;How did this happen?&quot;, I wondered. The <code>package.json</code> of the project wasn&apos;t updated, so <strong>breaking changes</strong> shouldn&apos;t have occurred. I started investigating again, this time going up to the root, and took note of every referenced version of the dependencies.</p><pre><code>@nestjs/websockets@^4.6.6
&#x2514;&#x2500;  socket.io@^2.0.3
    &#x2514;&#x2500;  engine.io@~3.1.0
        &#x2514;&#x2500;  ws@~2.3.1</code></pre><p>At first glance, I thought there was no problem with it since ws is pointed to the version 3.3.1, but then I realized there&apos;s one dependency which range specifies that it can be installed with <strong>any minor above 2.0.3</strong>: socket.io. Turns out the version of socket.io installed was 2.3.0.</p><figure class="kg-card kg-code-card"><pre><code>socket.io@2.3.0
&#x2514;&#x2500;  engine.io@~3.4.0
    &#x2514;&#x2500;  ws@^7.1.2</code></pre><figcaption>Dependency tree of socket.io 2.3.0</figcaption></figure><p>There&apos;s the problem: this version of socket.io needs engine.io 3.4.0, which depends on <strong>ws 7.1.2</strong>. The solution I went with was to find a version of socket.io that would allow me to use ws 6 (that version being 2.2.0) and add it to the dependencies of the project with a fixed version so it doesn&apos;t upgrade automatically.</p><figure class="kg-card kg-code-card"><pre><code>socket.io@2.2.0
&#x2514;&#x2500;  engine.io@~3.3.2
    &#x2514;&#x2500;  ws@^6.1.0</code></pre><figcaption>Dependency tree of socket.io 2.2.0</figcaption></figure><h3 id="what-about-semantic-versioning">What about Semantic Versioning?</h3><p><a href="https://semver.org">Semantic Versioning</a> (or SemVer) is a way of assigning unique identifiers (either names or numbers) to unique builds of software. Their introduction reads:</p><!--kg-card-begin: markdown--><blockquote>
<p>In the world of software management there exists a dreaded place called &#x201C;<strong>dependency hell</strong>.&#x201D; The bigger your system grows and the more packages you integrate into your software, the more likely you are to find yourself, one day, in this pit of despair.</p>
</blockquote>
<!--kg-card-end: markdown--><p>This is exactly what I experienced throughout this story. The ws package developers were kind enough to warn in their release notes that their new version would break applications running on Node 6.</p><p>The programmers of socket.io and engine.io should have noticed this change. From engine.io 3.3.2 to 3.4.0 were introduced breaking changes, causing applications like the one I was working on to crash, and that would not have happened if they increased their version as Semantic Versioning suggests.</p><!--kg-card-begin: markdown--><blockquote>
<p>Given a version number MAJOR.MINOR.PATCH, increment the:</p>
<p><strong>1. MAJOR version when you make incompatible API changes,</strong><br>
2. MINOR version when you add functionality in a backwards compatible manner, and<br>
3. PATCH version when you make backwards compatible bug fixes.</p>
</blockquote>
<!--kg-card-end: markdown--><p>I would have increased the version to 4.0.0 instead of 3.4.0, following the Semantic Versioning protocol.</p><p>Take this post with a grain of salt, this is just a personal rant about something I experienced at work. I would have preferred to update the Node version to a recent one but, unfortunately, this was the solution I had to go with.</p>]]></content:encoded></item><item><title><![CDATA[How I set up Ghost using Docker containers]]></title><description><![CDATA[I decided that it was time to create the personal project that I already had in mind for quite some time: a blog to record the interesting things I find as a software developer. More than that, I also wanted to learn something out of it, and to have some fun while doing it.]]></description><link>https://andremonteiro.pt/how-i-set-up-ghost-using-docker-containers/</link><guid isPermaLink="false">6067007a8dbdc811cede1ee7</guid><category><![CDATA[Programming]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Ghost]]></category><category><![CDATA[SysAdmin]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[André Monteiro]]></dc:creator><pubDate>Mon, 04 Nov 2019 11:39:46 GMT</pubDate><media:content url="https://andremonteiro.pt/content/images/2020/06/how-setup-ghost-docker-containers.png" medium="image"/><content:encoded><![CDATA[<img src="https://andremonteiro.pt/content/images/2020/06/how-setup-ghost-docker-containers.png" alt="How I set up Ghost using Docker containers"><p>I decided that it was time to create the personal project that I already had in mind for quite some time: a blog to record the interesting things I find as a software developer. More than that, I also wanted to learn something out of it, and to have some fun while doing it.</p><!--kg-card-begin: markdown--><p>I thought Docker would be ideal to organize the services I need. Simply put, Docker is a tool that allows creating and managing applications inside containers. I ended up having three of them, one for each of the services I needed:</p>
<ul>
<li><a href="https://www.nginx.com">NGINX</a>, to serve my web pages;</li>
<li><a href="https://www.mysql.com">MySQL</a>, to host my databases;</li>
<li><a href="https://ghost.org">Ghost</a>, to manage my content.</li>
</ul>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><style>    
    .collapsible {
        cursor: pointer;
    }
    
    .collapsible:after {
        content: '\002B';
        cursor: pointer;
        margin-left: 15px;
    }

    .active:after {
        content: "\2212";
    }

    .content {
        width: 100%;
        max-height: 0;
        margin-bottom: 1em;
        overflow: hidden;
        transition: max-height 0.2s ease-out;
    }
</style>
<script>
    $(document).ready(function(){
        var coll = document.getElementsByClassName("collapsible");
        var i;

        for (i = 0; i < coll.length; i++) {
            coll[i].addEventListener("click", function() {
                this.classList.toggle("active");
                var content = this.nextElementSibling;
                if (content.style.maxHeight){
                    content.style.maxHeight = null;
                } else {
                    content.style.maxHeight = content.scrollHeight + "px";
                } 
            });
        }
    });
</script>
<h3 class="collapsible">Table of Contents</h3>
<div class="content">
<ol>
<li><a href="#before-starting">Before starting</a></li>
<li><a href="#install-docker">Install Docker</a></li>
<li><a href="#creating-the-docker-compose-file">Creating the Docker Compose file</a></li>
<li><a href="#create-the-nginx-docker-image">Create the NGINX Docker Image</a></li>
<li><a href="#run-and-test-the-new-blog">Run and test the new blog</a></li>
<li><a href="#final-thoughts">Final thoughts</a></li>
</ol>
</div><!--kg-card-end: markdown--><h3 id="before-starting">Before starting</h3><p>First I chose and bought my domain, and my VPS to host the applications. I&apos;m using <a href="https://www.vultr.com/?ref=8282306">Vultr</a> as both my VPS and DNS provider.</p><p>I obtained an SSL/TLS certificate for my blog to be accessed through HTTPS. For that purpose, I used <a href="https://certbot.eff.org">Certbot</a> to request a certificate from <a href="https://letsencrypt.org">Let&apos;s Encrypt</a> <strong>for free</strong>! </p><pre><code class="language-shell">sudo apt install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt update
sudo apt install certbot
sudo certbot certonly --standalone -d blog.afmonteiro.pt</code></pre><!--kg-card-begin: markdown--><p>The certificate is downloaded to the folder <code>/etc/letsencrypt/live/example.com/</code>.</p>
<!--kg-card-end: markdown--><h3 id="install-docker">Install Docker</h3><!--kg-card-begin: markdown--><p>My VPS is running a Linux machine based on Debian, so I used <code>apt</code> to manage my packages, following the official <a href="https://docs.docker.com/install/linux/docker-ce/ubuntu/#install-using-the-repository">Docker documentation</a>.</p>
<ol>
<li>Install all the necessary packages:<pre><code class="language-bash">sudo apt install apt-transport-https ca-certificates curl software-properties-common
</code></pre>
</li>
<li>Add Docker&apos;s GPG key to authenticate the packages:<pre><code class="language-bash">curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - 
</code></pre>
</li>
<li>Verify the key&apos;s fingerprint:<pre><code class="language-bash">sudo apt-key fingerprint 0EBFCD88
</code></pre>
</li>
<li>Add the <code>stable</code> Docker repository:<pre><code class="language-bash">sudo add-apt-repository &quot;deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable&quot;
</code></pre>
</li>
<li>Update the package index and install Docker Community Edition:<pre><code class="language-bash">sudo apt-get update
sudo apt install docker-ce
</code></pre>
</li>
<li>Add your Linux user to the <code>docker</code> group:<pre><code class="language-bash">sudo usermod -aG docker $USER
</code></pre>
</li>
<li>Download and install the latest version of Docker Compose, and set permissions to run it. I&apos;m running the version 1.24.1, check the <a href="https://github.com/docker/compose/releases">releases</a> page for the latest version.<pre><code class="language-bash">sudo curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
</code></pre>
</li>
</ol>
<!--kg-card-end: markdown--><p>Now that Docker and Docker Compose are installed, the process can continue to its next step - installing the three main components, which will be listed in a single Docker Compose file. For those who don&apos;t know Compose, it is described as the following in the <a href="https://docs.docker.com/compose/">official documentation</a>: </p><blockquote>Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application&#x2019;s services. Then, with a single command, you create and start all the services from your configuration.</blockquote><h3 id="creating-the-docker-compose-file">Creating the Docker Compose file</h3><!--kg-card-begin: markdown--><ol>
<li>
<p>Create and change to the directory that will hold all the Docker services:</p>
<pre><code class="language-bash">mkdir docker &amp;&amp; cd docker
</code></pre>
</li>
<li>
<p>Create an empty file named <code>docker-compose.yml</code>:</p>
<pre><code class="language-bash">touch docker-compose.yml
</code></pre>
</li>
<li>
<p>Open <code>docker-compose.yml</code> with your favorite text editor, and paste the following snippet. Replace <code>MY_DOMAIN</code> with your domain, and insert a new database password where <code>MY_DB_PASSWORD</code> appears.</p>
<pre><code class="language-yaml"># docker/docker-compose.yml
version: &apos;3&apos;
services:

  ghost:
    image: ghost:latest
    restart: always
    depends_on:
      - db
    environment:
      url: MY_DOMAIN
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: MY_DB_PASSWORD
      database__connection__database: ghost
    volumes:
      - /opt/ghost_content:/var/lib/ghost/content

  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: MY_DB_PASSWORD
    volumes:
      - /opt/ghost_mysql:/var/lib/mysql

  nginx:
    build:
      context: ./nginx
      dockerfile: Dockerfile
    restart: always
    depends_on:
      - ghost
    ports:
      - &quot;80:80&quot;
      - &quot;443:443&quot;
    volumes:
       - /etc/letsencrypt/:/etc/letsencrypt/
       - /usr/share/nginx/html:/usr/share/nginx/html
</code></pre>
</li>
<li>
<p>Docker Compose creates a few <a href="https://docs.docker.com/storage/bind-mounts/#choosing-the--v-or---mount-flag">Docker bind mounts</a>:</p>
<ul>
<li><code>/var/lib/ghost/content</code> and <code>/var/lib/mysql</code> inside the containers are mapped to <code>/opt/ghost_content</code> and <code>/opt/ghost_mysql</code>, respectively. These locations will store Ghost and MySQL data.</li>
<li>A bind mount for <code>/etc/letsencrypt/</code> is created for NGINX to access the Lets Encrypt certificates.</li>
<li>NGINX also uses a bind mount for <code>/usr/share/nginx/html</code> so that it can access the Let&#x2019;s Encrypt challenge files that are created when your certificate is renewed.</li>
</ul>
<p>Directories should be created if they do not exist already:</p>
<pre><code class="language-bash">sudo mkdir /opt/ghost_content
sudo mkdir /opt/ghost_mysql
sudo mkdir -p /usr/share/nginx/html
</code></pre>
</li>
</ol>
<!--kg-card-end: markdown--><h3 id="create-the-nginx-docker-image">Create the NGINX Docker Image</h3><!--kg-card-begin: markdown--><ol>
<li>Create a new directory <code>nginx</code> (inside the previously created directory):<pre><code class="language-bash">mkdir nginx
</code></pre>
</li>
<li>Create a file named <code>Dockerfile</code> and paste in the following contents:<pre><code class="language-docker"># nginx/Dockerfile
FROM nginx:latest

COPY default.conf /etc/nginx/conf.d
</code></pre>
</li>
<li>Create a file named <code>default.conf</code> and paste in the following contents. Replace <code>MY_DOMAIN</code> with your own domain.<pre><code class="language-nginx"># nginx/default.conf
server {
  listen 80;
  listen [::]:80;
  server_name MY_DOMAIN;
  # Useful for Let&apos;s Encrypt
  location /.well-known/acme-challenge/ { root /usr/share/nginx/html; allow all; }
  location / { return 301 https://$host$request_uri; }
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name MY_DOMAIN;

  ssl_protocols TLSv1.2;
  ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;

  ssl_certificate     /etc/letsencrypt/live/MY_DOMAIN/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/MY_DOMAIN/privkey.pem;

  location / {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto https;
    proxy_pass http://ghost:2368;
  }
}
</code></pre>
</li>
</ol>
<!--kg-card-end: markdown--><h3 id="run-and-test-the-new-blog">Run and test the new blog</h3><p>When the environment is ready, run <code>docker-compose up -d</code>. This creates a daemon which runs the components in the background. To stop the instances, run the command <code>docker-compose down</code>. These commands should be run inside the folder that contains the Docker Compose file!</p><p>The command <code>docker-compose up</code> can be issued without the flag <code>-d</code> so the logs are shown in the console, running Docker Compose in attached state, this being useful for seeing errors if one occurs. To shut down the services in this case, press the combination <code>CTRL-C</code> in your keyboard.</p><h3 id="final-thoughts">Final thoughts</h3><p>Docker Compose is an ideal tool for a simple environment in which multiple applications need to be running in parallel and communicating with each other.</p><p>Creating an environment using Docker Compose may seem easy, but some unexpected errors may occur to some people. I had some trouble configuring the different components which required me to do some research on the side. Please use this guide at your own discretion, and feel free to leave me a comment if you have any doubt or suggestion.</p><p>Source: <a href="https://www.linode.com/docs/websites/cms/how-to-install-ghost-cms-with-docker-compose-on-ubuntu-18-04/">How to Install Ghost CMS with Docker Compose on Ubuntu 18.04</a></p>]]></content:encoded></item></channel></rss>