<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dzung Nguyen</title>
    <description>The latest articles on DEV Community by Dzung Nguyen (@dzungnguyen179).</description>
    <link>https://dev.to/dzungnguyen179</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F51037%2Fc0bcf758-9c12-4f0a-a64d-55522f0ca181.jpg</url>
      <title>DEV Community: Dzung Nguyen</title>
      <link>https://dev.to/dzungnguyen179</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dzungnguyen179"/>
    <language>en</language>
    <item>
      <title>Develop Spotify Player web extension</title>
      <dc:creator>Dzung Nguyen</dc:creator>
      <pubDate>Sun, 16 Aug 2020 06:55:09 +0000</pubDate>
      <link>https://dev.to/dzungnguyen179/develop-spotify-player-web-extension-3n85</link>
      <guid>https://dev.to/dzungnguyen179/develop-spotify-player-web-extension-3n85</guid>
      <description>&lt;h1&gt;
  
  
  Motivation
&lt;/h1&gt;

&lt;p&gt;When we are working or just browsing it is inconvenient to have to switch to another window to play / pause or jump to previous tracks or forward to upcoming tracks. Also, we lose focus or get distracted once we navigate away from our current window and open Spotify. With this simple extension we can eliminate the need to navigate away from your current window to control Spotify. This extension has another nifty feature. With a quick right click on the widget, you can search a song by name. So for example if you hear a tune on Youtube you can quickly search it on Spotify without navigating away from your current window. Then you can maybe add it to a playlist later.&lt;/p&gt;

&lt;h1&gt;
  
  
  UX / UI
&lt;/h1&gt;

&lt;h2&gt;
  
  
  How many features does it support?
&lt;/h2&gt;

&lt;p&gt;The goal of Spotify extension is to provide basic features that allow the user to quickly and easily control the Spotify app. Below is the list of basic features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Play / Pause&lt;/li&gt;
&lt;li&gt;Next / Previous&lt;/li&gt;
&lt;li&gt;Like&lt;/li&gt;
&lt;li&gt;Right click &amp;amp; search song in Spotify&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Right click to search a song
&lt;/h2&gt;

&lt;p&gt;Sometimes, we unintentionally find a good melody on youtube or some other websites and we want to find that song in Spotify to add to a playlist. We usually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;highlight &amp;amp; copy song title&lt;/li&gt;
&lt;li&gt;go to Spotify desktop app or web player&lt;/li&gt;
&lt;li&gt;search by song name&lt;/li&gt;
&lt;li&gt;add it to a playlist&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see it takes a few steps and we have to switch context (open web player with a new tab or switch to desktop app) to achieve the goal. So finding optimal way to do this is needed to reduce switching context (which can lead to lost focus)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is it possible to find a song in Spotify while I am on the current page (where I found the song)?&lt;/li&gt;
&lt;li&gt;If it is possible, how can I make it natural for users?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are the steps that I found optimal &amp;amp; natural:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;highlight the song title&lt;/li&gt;
&lt;li&gt;right click on the song, select item search in Spotify&lt;/li&gt;
&lt;li&gt;navigate to Spotify web player with that song name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From there I can add the song to my playlist. Everything is done in the browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0eU_vIYc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327706-8de55f80-dfd1-11ea-846f-179219950c48.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0eU_vIYc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327706-8de55f80-dfd1-11ea-846f-179219950c48.png" alt="Right click to search a song"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What kind of information needs to be displayed in Spotify extension?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Web extensions are small software programs that customize the browsing experience. Therefore only basic information is displayed .&lt;/li&gt;
&lt;li&gt;Song title &amp;amp; artist name are the basis of any song.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, I decided to display the song title, artist name, and their links.&lt;/p&gt;

&lt;h2&gt;
  
  
  But, how does it look ?
&lt;/h2&gt;

&lt;p&gt;The UI of Spotify extension is inspired by built-in “control your music, videos &amp;amp; more” feature of Chrome browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Chrome browser has a built-in extension that allows controlling any media playing in the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here is UI of built-in&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZKd9X_IN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327749-d6048200-dfd1-11ea-9db6-43a3fef22cca.png" class="article-body-image-wrapper"&gt;&lt;img title="built-in add on" alt="built-in add on" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZKd9X_IN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327749-d6048200-dfd1-11ea-9db6-43a3fef22cca.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spotify extension UI has 3 cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;User is not logged in&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cEzeB4BQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327796-4f9c7000-dfd2-11ea-96af-5a4c2b0073cf.png" class="article-body-image-wrapper"&gt;&lt;img title="not logged in" alt="not-logged-in" src="https://res.cloudinary.com/practicaldev/image/fetch/s--cEzeB4BQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327796-4f9c7000-dfd2-11ea-96af-5a4c2b0073cf.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Spotify desktop app or web player is not opened&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--balp4C7r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327854-a73adb80-dfd2-11ea-872a-f92a79961436.png" class="article-body-image-wrapper"&gt;&lt;img title="not opened" alt="not-opened" src="https://res.cloudinary.com/practicaldev/image/fetch/s--balp4C7r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327854-a73adb80-dfd2-11ea-872a-f92a79961436.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Happy case&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XmN8J-Gg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327876-c0dc2300-dfd2-11ea-9d47-d04a7fae4fdb.png" class="article-body-image-wrapper"&gt;&lt;img title="Once there were dragons" alt="once-there-were-dragons" src="https://res.cloudinary.com/practicaldev/image/fetch/s--XmN8J-Gg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327876-c0dc2300-dfd2-11ea-9d47-d04a7fae4fdb.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BrRheXSK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327872-bde13280-dfd2-11ea-83fa-b78360a4ae65.png" class="article-body-image-wrapper"&gt;&lt;img title="There are the times" alt="there-are-the-times" src="https://res.cloudinary.com/practicaldev/image/fetch/s--BrRheXSK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327872-bde13280-dfd2-11ea-83fa-b78360a4ae65.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0FylJk8s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327912-039dfb00-dfd3-11ea-93ef-92a016908dea.png" class="article-body-image-wrapper"&gt;&lt;img title="Pneuma" alt="pneuma" src="https://res.cloudinary.com/practicaldev/image/fetch/s--0FylJk8s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327912-039dfb00-dfd3-11ea-93ef-92a016908dea.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Logo
&lt;/h1&gt;

&lt;p&gt;The logo is very important for any product or business, it helps other people to recognize you. At first, I tried to design one by myself but could not come up with a good design so I asked my friend who is a designer to help. Here is what he came up with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GpTLbTUq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327943-54155880-dfd3-11ea-8ae9-e35c92feb858.png" class="article-body-image-wrapper"&gt;&lt;img title="spotify-mini-player" alt="spotify-mini-player" src="https://res.cloudinary.com/practicaldev/image/fetch/s--GpTLbTUq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90327943-54155880-dfd3-11ea-8ae9-e35c92feb858.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Spotify Web API
&lt;/h1&gt;

&lt;p&gt;To control the state of the Spotify application via web extension, I need a way to tell the Spotify application that I want to update state, e.g from playing to pause the song. Fortunately, Spotify provides the Web API endpoints to control the state of the application.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://developer.spotify.com/documentation/web-api/reference/"&gt;https://developer.spotify.com/documentation/web-api/reference/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Tech stack
&lt;/h1&gt;

&lt;p&gt;At first, I used JS, HTML &amp;amp; CSS to set up a simple development. Because I thought that creating the Spotify Player extension would be as simple as building a UI and integrating with the API. It turned out to be more than that. During development I encountered edge cases that forced me to refactor the code. Refactoring code has never been an easy task, especially for JS which does not have strong type support and I think it’s not good in the long run. So I decided to rewrite the whole code base using a new stack and put a lot of effort into development set up. Here is what I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Webpack&lt;/li&gt;
&lt;li&gt;Typescript (compile to JS)&lt;/li&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;Jest&lt;/li&gt;
&lt;li&gt;Travis for CI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why not use a library or framework?
&lt;/h2&gt;

&lt;p&gt;Because libraries and frameworks are for larger scale projects and the JS file size is usually pretty big especially for plugins. So I decided to stick with Typescript with DOM rendering and manage application state on my own. You can check the details here:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/davidnguyen179/spotify-extension"&gt;https://github.com/davidnguyen179/spotify-extension&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Edge cases
&lt;/h1&gt;

&lt;p&gt;After integrating the API with the UI, the extension works pretty well. However, there are some edge cases which took me some time to fix.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happens if you leave the Spotify related app (desktop app or web player) idle for sometime (without playing any song) and you use Spotify Player extension to play a song?&lt;/li&gt;
&lt;li&gt;What happens if you suddenly turn off the Spotify app and you open the Spotify Player extension, how does the UI look?&lt;/li&gt;
&lt;li&gt;What if your token expired or you’re not logged in? How does the UI look?&lt;/li&gt;
&lt;li&gt;What if you don’t open any Spotify related app on your PC? Then, how does the UI of Spotify Player extension look?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To bring the best UX possible for users, I had to think about all possible cases and fix them all. Whenever I fixed things, I had to update my test suite in code to make sure future fixes or features won’t break the extension.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cross Browser support
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7S4d1LPE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90328091-b91d7e00-dfd4-11ea-8372-f71fd209e1eb.png" class="article-body-image-wrapper"&gt;&lt;img title="browser stats" alt="browser-stats" src="https://res.cloudinary.com/practicaldev/image/fetch/s--7S4d1LPE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90328091-b91d7e00-dfd4-11ea-8372-f71fd209e1eb.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My initial goal was only to create a Chrome extension. Then I realized web extensions are a standard for most browsers. They are all developed using JS, CSS, HTML and manifest file to manage configuration and permission of extension. Knowing this, I decided to support 3 browsers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chrome&lt;/li&gt;
&lt;li&gt;Firefox&lt;/li&gt;
&lt;li&gt;Microsoft Edge (Chromium)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Solution 1 — poly repo
&lt;/h2&gt;

&lt;p&gt;Create 2 more repositories and develop for Firefox &amp;amp; Edge. This solution will work, but there are some downsides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What if you decided to add more functionality to the extension? Then you have to do it 3 times in 3 different repos.&lt;/li&gt;
&lt;li&gt;What if you have bugs? Then you have to fix it 3 times.&lt;/li&gt;
&lt;li&gt;How do you release it? You have to assure that 3 repos have the same version number and repeat the same process of publishing 3 times.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well, switching contexts (switching repo to another repo) multiple times and doing many things can make you feel confused and tired. And with this approach, we violate the &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY&lt;/a&gt; design principle. Because the logic and functionality is the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution 2 — mono repo
&lt;/h2&gt;

&lt;p&gt;With this approach, I keep one source code only and analyze what are differences between Chrome, Firefox, and Microsoft Edge. Here are the differences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;manifest.json&lt;/li&gt;
&lt;li&gt;background.ts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How can we make those files dynamic and correspond to each browser?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This can be done at build-time. That means I will have 3 build scripts for each browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dYdRNiYO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90328259-ecacd800-dfd5-11ea-8f24-b03aa5dca847.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dYdRNiYO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6290720/90328259-ecacd800-dfd5-11ea-8f24-b03aa5dca847.png" alt="build process"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this approach, I can only solve the first 2 problems that are listed above. But the core logic is shared between each browser.&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing
&lt;/h1&gt;

&lt;p&gt;My first purpose is to build this extension to solve my own problem. But things are getting serious, I want to publish it to the web stores, that means Spotify Player Extension will have its own users. So it’s better to make sure the extension has no bugs and works smoothly.&lt;/p&gt;

&lt;p&gt;After completing the development, I asked friends who are willing to try it out, but I have to write down detailed documentation on how to install this extension with developer mode in the browser. I tried to gather feedback, bug reports, and filter which ones should be fixed. After fixing those issues, I also updated my test suites to make sure those issues will not happen again.&lt;/p&gt;

&lt;p&gt;My lesson is if you ask people to test it for you, you need to make sure that everything is super simple for them to test and you only have 2 – 3 chances to ask them to do it again, because they have jobs to do. Otherwise, it becomes annoying for them.&lt;/p&gt;

&lt;h1&gt;
  
  
  Publishing
&lt;/h1&gt;

&lt;p&gt;Here are the resources for publishing the extension to web stores&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/webstore/publish"&gt;Chrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://extensionworkshop.com/documentation/publish/submitting-an-add-on/"&gt;Firefox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/microsoft-edge/extensions-chromium/publish/publish-extension"&gt;Microsoft Edge&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While publishing the web extension, I faced some issues which prevented me from publishing. Specifically, they will send an email to inform you if you have violated some rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chrome&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The email is sent by Google support team is done by bot and it is hard to understand because it contains many rules. Here is a resource I found really useful&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you have a problem, you can post it in the google group and provide them your extension ID. &lt;a href="https://groups.google.com/a/chromium.org/forum/#!forum/chromium-extensions"&gt;https://groups.google.com/a/chromium.org/forum/#!forum/chromium-extensions&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/channel/UCVj3dGw75v8aHFYD6CL1tFg"&gt;Jack and Amy Dev youtube channel&lt;/a&gt;, which explains some common mistakes when we develop Chrome extension.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Microsoft Edge&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They will require file “PRIVACY POLICY”. Make sure you have it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Firefox&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They might require you to upload your source code if your source code is minified.&lt;/p&gt;

&lt;h1&gt;
  
  
  Marketing
&lt;/h1&gt;

&lt;p&gt;The “Spotify Player Extension” has been published in 3 web stores. To let everyone know it exists, I used social media:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reddit&lt;/li&gt;
&lt;li&gt;Facebook&lt;/li&gt;
&lt;li&gt;Twitter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After I posted it I thought my work was done. However, I received a bunch of feedback from “Reddit”. They suggested a lot of improvements. Here we go again, I have to filter which ones I should implement, which ones are not going to add to a better UX, and just keep fixing and improving until it is stable.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Here is how it looks like&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6bv67t7q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://user-images.githubusercontent.com/6290720/90328322-7ceb1d00-dfd6-11ea-8c31-8a47524c29fe.gif" class="article-body-image-wrapper"&gt;&lt;img title="final look" alt="final look" src="https://res.cloudinary.com/practicaldev/image/fetch/s--6bv67t7q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://user-images.githubusercontent.com/6290720/90328322-7ceb1d00-dfd6-11ea-8c31-8a47524c29fe.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is the number of users of Chrome &amp;amp; Firefox browsers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/spotify-player/bhdjjppbnlpjpeicimhemencfgjeldoa"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vfvMc6xw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/chrome-web-store/users/bhdjjppbnlpjpeicimhemencfgjeldoa%3Fcolor%3D0099ff%26label%3Dchrome%2520users%26logo%3Dgoogle-chrome%26logoColor%3Dd2ccd2" alt="Chrome Extension Users"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/spotify-player/bhdjjppbnlpjpeicimhemencfgjeldoa"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--csOGo6Jn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/chrome-web-store/v/bhdjjppbnlpjpeicimhemencfgjeldoa%3Fcolor%3D0099ff%26logo%3Dgoogle-chrome%26logoColor%3Dd2ccd2" alt="Chrome Extension Version"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/spotify-player/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zgk94KnB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/amo/users/spotify-player%3Fcolor%3DFF9500%26label%3Dmozilla%2520users%26logo%3Dfirefox" alt="Firefox Add-On Users"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/spotify-player/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rwhyKU_C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/amo/v/spotify-player%3Fcolor%3DFF9500%26logo%3Dfirefox" alt="Firefox Add-On Version"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Spotify Player extension is available on 3 web stores:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chrome&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/spotify-player/bhdjjppbnlpjpeicimhemencfgjeldoa"&gt;https://chrome.google.com/webstore/detail/spotify-player/bhdjjppbnlpjpeicimhemencfgjeldoa&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Microsoft Edge&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://microsoftedge.microsoft.com/addons/detail/spotify-player/odplfjpibjdajlmaocmfmlcdidldlmnk"&gt;https://microsoftedge.microsoft.com/addons/detail/spotify-player/odplfjpibjdajlmaocmfmlcdidldlmnk&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Firefox&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/spotify-player/"&gt;https://addons.mozilla.org/en-US/firefox/addon/spotify-player/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Source code&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/davidnguyen179/spotify-extension"&gt;https://github.com/davidnguyen179/spotify-extension&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Website&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://spotify-extension.netlify.app/"&gt;https://spotify-extension.netlify.app/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Boilerplate&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/davidnguyen179/web-extension-boilerplate"&gt;https://github.com/davidnguyen179/web-extension-boilerplate&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I really appreciate the community that helps me to improve this extension and friends who help me to test it out.&lt;/p&gt;

</description>
      <category>spotify</category>
      <category>typescript</category>
      <category>chromeextension</category>
      <category>spotifywebplayer</category>
    </item>
    <item>
      <title>Rewrite commit history</title>
      <dc:creator>Dzung Nguyen</dc:creator>
      <pubDate>Sun, 08 Sep 2019 07:54:39 +0000</pubDate>
      <link>https://dev.to/dzungnguyen179/rewrite-commit-history-45p3</link>
      <guid>https://dev.to/dzungnguyen179/rewrite-commit-history-45p3</guid>
      <description>&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;As an engineer, we like to keep things organized. Especially, when you are working on the project and the team is growing larger. That means there are a lot of engineers working on the same source code and a bunch of commits are made every day. Keeping the git history clean and linear makes it easier for all of the engineers to understand what is going on in the source code. Doing so requires using a few advanced git features. In this article we will learn how to perform 4 git tasks that I believe are essential to keeping your commit history minimal and concise before merging it with the main branch.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Squash &amp;amp; Reword&lt;/li&gt;
&lt;li&gt;Merge base &amp;amp; Reset&lt;/li&gt;
&lt;li&gt;Amend&lt;/li&gt;
&lt;li&gt;Push force&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before jumping to the detail. Let’s see why we need clean commit history and which scenario should we apply to our work.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why clean commit history?
&lt;/h1&gt;

&lt;p&gt;Having the clean commit history brings us 4 main benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;. A linear history is typically easier to follow. This is similar to how you want your code to be well structured and documented: whenever someone needs to deal with it later (code or history) it is very valuable to be able to quickly understand what is going on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improving code review efficiency&lt;/strong&gt;. If a topic branch is divided into linear, logical steps, it is much easier to review the changes between the PR and a target branch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When you need to modify the history at a later time&lt;/strong&gt;. For instance when reverting or cherry-picking a feature in whole or in part.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;. Unless you strive to keep your history linear when your team grows larger (e.g. hundreds of contributors), your history can become very bloated with cross branch merges, and it can be hard for all the contributors to keep track of what is going on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, beside the benefits there are some drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The clean commit history is only effective only if all members agree to apply it to their work.&lt;/li&gt;
&lt;li&gt;To do this requires some advanced git features, the learning curve costs you some time at first.&lt;/li&gt;
&lt;li&gt;And if you don’t know it well, it can cause you some troubles when you apply it to your project.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Scenario
&lt;/h1&gt;

&lt;p&gt;I was assigned the task to develop the React components called “List” and “List Item”. So here is what I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new branch called “features/add-list-list-item”
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; “features/add-list-list-item”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;I made a commit for adding the UI of the ListItem component.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; “add the ui of ListItem”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Then I found that my code was not very clean. So I refactored it.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; “refactor”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;And then, I found some issues and fixed them. Suddenly, I have to go home for some private business, then I decided to commit my work temporarily.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; “temp”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;OK! I completed the “ListItem” component.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; “completed the ListItem”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;I completed the “List” component and with the ListItem I committed above. Now I can make a final commit to mark that I finished my task.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; “finished task”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking back at the commit history, we see the history of the feature we are working on is lacks meaningful descriptions of changes and in general is messy.&lt;/p&gt;

&lt;h1&gt;
  
  
  Clean commit history
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Squash &amp;amp; Reword
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Squash&lt;/strong&gt;: combine commits into 1 commit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reword&lt;/strong&gt;: Edit the commit message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to do that, here is the steps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1 - Open the commit history&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1992%2F1%2AdYl9yK_dGMeCMOLbeJdPgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1992%2F1%2AdYl9yK_dGMeCMOLbeJdPgg.png" alt="git log --oneline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2 - Identify how many commits we need to squash and reword&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1992%2F1%2A5tnNides06EgXpO_zdg9yA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1992%2F1%2A5tnNides06EgXpO_zdg9yA.png" alt="git log --oneline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, we are going to squash 5 commits in the “red box” and reword the 5th commit message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3 - Rebase to the commit just before the list of commits that you want to squash and reword&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;3.1 - Rebase to commit&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this case, it is the sixth commit. Copy the hash string “7c63b5f” and rebase to 6th commit by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; 7c63b5f
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;3.2 - Select options to modify commits&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After running the command at previous step, it takes us to Vim screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F2460%2F1%2Ak5fc4EY_Tp0g0bb1wjHohA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F2460%2F1%2Ak5fc4EY_Tp0g0bb1wjHohA.png" alt="Select options to modify commits"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So here is what we are doing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We replace the “pick” with “s” to commits in the “red box” to squash.&lt;/li&gt;
&lt;li&gt;We replace the “pick” with “r” to commits in the “yellow box” to reword commit message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To modify Vim screen, you need to do 2 things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter the “Insert mode” by press “i” for editing.&lt;/li&gt;
&lt;li&gt;Enter the “Command mode” by press “esc” and press “:wq” to save the changes.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;r 1e857cc add the ui of ListItem
s cb0cc38 refactor
s 4a1d911 temp
s 00cde97 completed the ListItem
s 975b990 finished task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;3.3 - Reword commit message&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After modifying the commits, it takes us to the reword screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1492%2F1%2AQ646xpewLzd6jEEECeqa6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1492%2F1%2AQ646xpewLzd6jEEECeqa6g.png" alt="Reword commit message - before"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because we develop 2 components “List” &amp;amp; “List Item”. So the message should contains 2 components&lt;/p&gt;

&lt;p&gt;Change:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;add the ui of ListItem&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add List &amp;amp; ListItem components&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1456%2F1%2A7d_LryazE3vGEj8ncRIbiA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1456%2F1%2A7d_LryazE3vGEj8ncRIbiA.png" alt="Reword commit message - after"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then “:wq” (Write &amp;amp; Quit) Vim.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;3.4 - Squash commits&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After we done editing the commit message. It takes us to the second screen to squash commits.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1408%2F1%2AWh_52l6CgfyVVoN8om-Uwg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1408%2F1%2AWh_52l6CgfyVVoN8om-Uwg.png" alt="Squash commits - before"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Delete all lines in the “red box”.&lt;/li&gt;
&lt;li&gt;Keep the line in the “green box”. Because this is the final commit message reflects to our work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To delete lines in the “red box”.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move your cursor to that line and press “dd”.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1360%2F1%2AhZZkNKqvRuAHlOHuxIfUcQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1360%2F1%2AhZZkNKqvRuAHlOHuxIfUcQ.png" alt="Squash commits - after"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Then “:wq” (Write &amp;amp; Quit) Vim. Done!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;3.5 - Check if our work was successful or not&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1204%2F1%2Ac5EhxjWsQeOse9MHM6tmBg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1204%2F1%2Ac5EhxjWsQeOse9MHM6tmBg.png" alt="Checking"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we already combined 5 commits into 1 and reworded the commit message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Merge base &amp;amp; Reset
&lt;/h2&gt;

&lt;p&gt;After squashing commits, I create a PR (Pull Request or Merge Request) and add reviewers. And they give me feedback.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What do you think about splitting the commit into 2 commits? Because 2 components should correspond to 2 commits. One for ListItem component, the other for List component.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our mission now is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Splitting the squashed commit into 2 different commits.&lt;/li&gt;
&lt;li&gt;Each commit needs to have its own commit message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, this section uses the second technique to re-commit and it requires a few steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using “&lt;strong&gt;git merge-base  &lt;/strong&gt;” to get the common ancestors between the main branch and feature branch. The output of this is a hash string represent the commit.&lt;/li&gt;
&lt;li&gt;Using “&lt;strong&gt;git reset &lt;/strong&gt;” to go back when we haven’t committed anything related to List &amp;amp; ListItem components.&lt;/li&gt;
&lt;li&gt;Using “&lt;strong&gt;git add &lt;/strong&gt;” to add files which belong to “&lt;strong&gt;List&lt;/strong&gt;” component.&lt;/li&gt;
&lt;li&gt;Commit the “&lt;strong&gt;List&lt;/strong&gt;” component with the message “Add List component”.&lt;/li&gt;
&lt;li&gt;Using “git add ” to add files which belong to “ListItem” component.&lt;/li&gt;
&lt;li&gt;Commit the “&lt;strong&gt;ListItem&lt;/strong&gt;” component with the message “Add ListItem component”.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Using merge-base&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first thing we need to do is find the most common parts between the main branch and feature branch by running the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git merge-base master features/add-list-list-item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the output is the hash string points to the commit has the most common parts between 2 branches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;7c63b5ffc4ba24581b624e298dd15a02d52bf2a7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you copy this hash string before moving to the next step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reset commit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this step, we use the “git reset ” with the hash string from the previous step to go back to the moment before we made any commits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reset 7c63b5ffc4ba24581b624e298dd15a02d52bf2a7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F2844%2F1%2A6zpUrQynDEv215vv0x1u1Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F2844%2F1%2A6zpUrQynDEv215vv0x1u1Q.png" alt="Reset commit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the “orange box”, our files were back to the original state. Now we can use “git add ” to shape our commit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finish move&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So we will create 2 commits which correspond to 2 components “List” &amp;amp; “ListItem”.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;List: “Add List component”
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add src/components/list/index.js
git add src/components/list/style.css
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add List component"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;List Item: “Add List Item component”
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add src/components/list-item/index.js
git add src/components/list-item/style.css
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add List Item component"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done! Now to check whether or not we successfully re-shaped our commit. Just open the git commit history.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F2428%2F1%2AHsFCCixf0u_3Qba9_bVtBQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F2428%2F1%2AHsFCCixf0u_3Qba9_bVtBQ.png" alt="Finish move"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Amend
&lt;/h2&gt;

&lt;p&gt;After we shaped our commits. Suddenly, we forgot we haven’t update document. So we went back and updated the document and this one is just a small change. You will ask yourself the question?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is there anyway that I commit and don’t have to shape the commits again?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes, we have. It’s &lt;code&gt;git commit --amend&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What is git &lt;code&gt;commit --amend&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;The git commit --amend command is a convenient way to modify the most recent commit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How we use that?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We updated the document of the source code and commit with the &lt;code&gt;--amend&lt;/code&gt; flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;--amend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It takes you to Vim screen like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F2216%2F1%2AiPn0JkwoGViG8oQaCI08Ug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F2216%2F1%2AiPn0JkwoGViG8oQaCI08Ug.png" alt="amend"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then “:wq” (Write &amp;amp; Quit) Vim. Done!&lt;/p&gt;

&lt;p&gt;Now your changes were included in the last commit “Add List Item component”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Push force
&lt;/h2&gt;

&lt;p&gt;After we finished everything and now we have the nice commits structure. The last thing we need to do is “push” code to remote branch.&lt;/p&gt;

&lt;p&gt;If your branch is already in “&lt;strong&gt;remote branch&lt;/strong&gt;” and you just rewrite commit history. Therefore, you need to override it in the “remote branch”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Otherwise&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;--set-upstream&lt;/span&gt; origin features/add-list-list-item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Having the clean git history in your project is important. Especially, when you are working in the large team (≥ 20 contributors) in which everyday there is a bunch of commits are made. It helps you easy to catch up what’s going on, easy to revert and makes your life easier. But it comes with a price, if you apply it without any experience in the real project, it can cause you some trouble.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure you have tried it in your personal projects multiple times before applying it to the real project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase" rel="noopener noreferrer"&gt;https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.atlassian.com/git/tutorials/rewriting-history" rel="noopener noreferrer"&gt;https://www.atlassian.com/git/tutorials/rewriting-history&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>softwaredevelopment</category>
      <category>softwareengineer</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>NextJS deployment pipeline on S3 with Gitlab-CI</title>
      <dc:creator>Dzung Nguyen</dc:creator>
      <pubDate>Sat, 27 Apr 2019 01:50:23 +0000</pubDate>
      <link>https://dev.to/dzungnguyen179/nextjs-deployment-pipeline-on-s3-with-gitlab-ci-59en</link>
      <guid>https://dev.to/dzungnguyen179/nextjs-deployment-pipeline-on-s3-with-gitlab-ci-59en</guid>
      <description>&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;NextJS was released in 2016. Since then it has become one of the largest frameworks that support Server-side Rendering (SSR) with ReactJS &amp;amp; NodeJS. Being one of the first companies in Vietnam which have applied NextJS to develop products, we have encountered interesting challenges and learned throughout development to deployment processes. In today’s topic, I am going to share about how we dealt with the deployment step which helped us achieve 2 big milestones.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web team and SRE (Site Reliability Engineering) team work independently.&lt;/li&gt;
&lt;li&gt;Only one step to production.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Problem
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Mapping URL to static resources.
&lt;/h2&gt;

&lt;p&gt;After setting up a brand new project, developers jump into setting up the deployment environment based on the SRE rules to have a smooth workflow. Here are what we usually need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identify the available IP &amp;amp; port.&lt;/li&gt;
&lt;li&gt;Register the service with the available IP &amp;amp; port.&lt;/li&gt;
&lt;li&gt;Ask for the domain to map to the service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a web application, some extra items need to be handled. In order to go live, you need to specify some static resources and assets such as CSS files, JS files and images… So we need to list out every resource with a specific URL and then work with SRE team to map with the IP &amp;amp; port.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For example:&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdblio631bn3i76shhq3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdblio631bn3i76shhq3.png" alt="GitHub Logo" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A manual approach to do this is simple and easy to setup. However, there would be challenges as follow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the page has a lot of resources. We need to manually list out each resource with a specific domain. It takes a lot of time.&lt;/li&gt;
&lt;li&gt;And because we have a lot of services and small web apps. Consequently, the mapping config file from the SRE team becomes huge.&lt;/li&gt;
&lt;li&gt;Sometimes the mapping config file has conflicts between services, for example, the other team has registered the URL to their own resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Depends on SRE team
&lt;/h2&gt;

&lt;p&gt;There were a lot of services of Chợ Tốt which depend on the SRE team. Every time we start a new web app, we need to come to the SRE desk and ask for mapping URLs to static resources and when the configuration becomes more complicated such as this URL was taken by another web app and we did some “hack” to make it work. Consequently, it leads to creating some bugs of other web apps. Then we revert back to the origin to find another solution.&lt;/p&gt;



&lt;p&gt;For those reasons, the Web team &amp;amp; SRE team come to the solution which helps the automation CI/CD pipeline of the whole system.&lt;/p&gt;
&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flgpkh7k2zofzkqsx2kqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flgpkh7k2zofzkqsx2kqw.png" alt="pipeline flow" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the code is merged to the specific branch (master or staging or release). The CI/CD flow will be triggered to execute. The CI/CD has 3 stages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dockerize&lt;/strong&gt;&lt;br&gt;
Converting an application to run within a Docker container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Uploading static resources to S3&lt;/strong&gt;&lt;br&gt;
After dockerizing the web app, we do some post processes, then start uploading the whole build directory to S3.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;S3 here is actually Chợ Tốt server and we apply the interface of AWS S3. So uploading static resources to S3 means uploading to our own server.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment&lt;/strong&gt;&lt;br&gt;
Activating the web application to run on the production environment.&lt;/p&gt;
&lt;h1&gt;
  
  
  Hands-on
&lt;/h1&gt;

&lt;p&gt;Below is the structure of the project. You could find it at &lt;a href="https://github.com/ChoTotOSS/cna" rel="noopener noreferrer"&gt;cna&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;my-app
├── deployment/
 └── post-build/
 └──── index.js
 └── s3/
 └──── index.js
├── app/
 └── …
 └── next.config.js
 └── …
├── package.json

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this section, I’ll cover 4 points.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bucket name&lt;/li&gt;
&lt;li&gt;Credential&lt;/li&gt;
&lt;li&gt;Configs&lt;/li&gt;
&lt;li&gt;Deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bucket name
&lt;/h2&gt;

&lt;p&gt;The first thing we do is to define a good convention name for the S3’s bucket. To do that, we manually create by using commands of AWS S3 SDK. The bucket name is the combination of service name and environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;SERVICE_NAME&amp;gt;_&amp;lt;ENVIRONMENT&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;For example 1:&lt;/em&gt;&lt;br&gt;
The service name “chotot-vehicle”. And the bucket name is&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;staging:&lt;/strong&gt; CHOTOT_VEHICLE_STAGING&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;production:&lt;/strong&gt; CHOTOT_VEHICLE_PRODUCTION&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;For example 2:&lt;/em&gt;&lt;br&gt;
The service name “chotot-property”. And the bucket name is&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;staging:&lt;/strong&gt; CHOTOT_PROPERTY_STAGING&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;production:&lt;/strong&gt; CHOTOT_PROPERTY_PRODUCTION&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Credential
&lt;/h2&gt;

&lt;p&gt;We make use of Gitlab via “Secret Variables” feature which provides the setting allows adding “Credential Information” as the environment variables.(I believe other CI/CD has the same feature such as &lt;a href="https://travis-ci.org/" rel="noopener noreferrer"&gt;TravisCI&lt;/a&gt;, &lt;a href="https://circleci.com/" rel="noopener noreferrer"&gt;CircleCI&lt;/a&gt;, …).&lt;/p&gt;

&lt;p&gt;By doing this way, we follow the &lt;a href="https://en.wikipedia.org/wiki/Separation_of_concerns" rel="noopener noreferrer"&gt;Separation of Concerns (SoC)&lt;/a&gt; design principle. The development does not have to care about the deployment or manage the credential.&lt;/p&gt;
&lt;h2&gt;
  
  
  Configs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;.gitlab-ci.yml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dockerize&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;s3&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
&lt;span class="na"&gt;dockerize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dockerize&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;DOCKERIZE_DO_SOMETHING&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;s3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;s3&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;yarn install&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;yarn build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=staging CDN_HOST_BUCKET=$CDN_HOST_BUCKET CDN_ACCESS_KEY_ID=$CDN_ACCESS_KEY_ID CDN_SECRET_ACCESS_KEY=$CDN_SECRET_ACCESS_KEY yarn s3:upload&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=production CDN_HOST_BUCKET=$CDN_HOST_BUCKET CDN_ACCESS_KEY_ID=$CDN_ACCESS_KEY_ID CDN_SECRET_ACCESS_KEY=$CDN_SECRET_ACCESS_KEY yarn s3:upload&lt;/span&gt;
&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;DEPLOYMENT_SCRIPTS&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;next.config.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;assetPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;staging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;assetPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://static.com/CHOTOT_VEHICLE_STAGING/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;assetPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://static.com/CHOTOT_VEHICLE_PRODUCTION/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;assetPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assetPrefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;generateBuildId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After building NextJS web app, it has the directory called “.next” and the structure of files is different from the URLs access to the static resources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewcd2cf11jbyfxyd0s9o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewcd2cf11jbyfxyd0s9o.png" alt="build directory structure" width="453" height="721"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8qxlquu5soa5nnvrwa7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8qxlquu5soa5nnvrwa7.png" alt="url structure" width="777" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see there are 2 different paths.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;.next/bundles/pages/index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;versus&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/_next/build/page/index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So if we upload the whole built directory to S3 and run our web application. It is absolutely not working.&lt;/p&gt;

&lt;p&gt;** Solution&lt;/p&gt;

&lt;p&gt;Because of the deployment is separated from the development stage. So that we add one more stage before uploading built directory to S3 called “post-build”.&lt;/p&gt;

&lt;p&gt;The “post-build” stage takes care of re-arranging the structure of files to match the structure of URLs which point to the files.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For example:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3vpvd7mdr2ob2f7s7n3a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3vpvd7mdr2ob2f7s7n3a.png" alt="build-and-postbuild" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The post-build script&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To create the post build, we created a small script which allow to re-structure the built directory. Each major changes from NextJS which created a new structure of built files. For this reason, each of “post-build” script need to adapt with NextJS major version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;post-build.js - nextjs 6&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;mv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dirs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/.next/_next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/.next/_next/build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/.next/_next/build/page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/.next/_next/static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PAGE_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;old&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/.next/bundles/pages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;new&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/.next/_next/build/page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;STATIC_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;old&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/.next/static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;new&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/.next/_next/static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// create dir&lt;/span&gt;
&lt;span class="nx"&gt;dirs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// move files&lt;/span&gt;
&lt;span class="nf"&gt;mv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PAGE_PATH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PAGE_PATH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mkdirp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;mv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STATIC_PATH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;STATIC_PATH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mkdirp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;post-build.js - nextjs 7&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;mv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dirs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/.next/_next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/.next/_next/static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;STATIC_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;old&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/.next/static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;new&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/.next/_next/static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// create dir&lt;/span&gt;
&lt;span class="nx"&gt;dirs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;mv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STATIC_PATH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;STATIC_PATH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mkdirp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;post-build.js - nextjs 8&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;mv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dirs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.next/_next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.next/_next/static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;STATIC_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;old&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.next/static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;new&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.next/_next/static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// create dir&lt;/span&gt;
&lt;span class="nx"&gt;dirs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;mv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STATIC_PATH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;STATIC_PATH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mkdirp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Uploading to S3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After re-structuring the built files. Now all we need is some code to upload the whole build directory to S3. To to this, we created a small package called “&lt;a href="https://www.npmjs.com/package/s3-uploading" rel="noopener noreferrer"&gt;s3-uploading&lt;/a&gt;” which helps us to make it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./package.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Uploader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3-uploading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;staging&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// CHOTOT_VEHICLE_PRODUCTION/1.0.1&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;BUCKET_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;YOUR_BUCKET_NAME&amp;gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;accessKeyId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CDN_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;secretAccessKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CDN_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CDN_HOST_BUCKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ACL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public-read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;sslEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../app/.next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// path to built directory&lt;/span&gt;
    &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BUCKET_PATH&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uploader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Register scripts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One last thing we need to do is registering the scripts to execute the “uploading static resources to s3” step to package.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"s3:upload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node ./deployment/s3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node ./server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next build app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postbuild"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node ./deployment/post-build"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Result
&lt;/h1&gt;

&lt;p&gt;Here are the results of staging and production environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ol2xram9caoahpum7cj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ol2xram9caoahpum7cj.png" alt="staging" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcrfkpe43nms9znx1hbq7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcrfkpe43nms9znx1hbq7.png" alt="production" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we manage the static resources based on the version from “package.json”. We follow Semantic versioning, more detail &lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. In each release, we update the version and then upload them to S3.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;With the optimization above, we cut down from n (n &amp;gt; 1) steps of the deployment into 1 step. It brings some of the benefits.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speeding up the development time.&lt;/li&gt;
&lt;li&gt;Less depending on the other team.&lt;/li&gt;
&lt;li&gt;Caching of static resource versioning is well taken cared of (Because we store all static resources based on the version).&lt;/li&gt;
&lt;li&gt;Fully control by the web team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re interested in it, make sure you check out our repos.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ChoTotOSS/cna" rel="noopener noreferrer"&gt;https://github.com/ChoTotOSS/cna&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ChoTotOSS/cna" rel="noopener noreferrer"&gt;https://github.com/davidnguyen179/s3-upload&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>awss3</category>
      <category>cicd</category>
    </item>
    <item>
      <title>How we built the universal “Header &amp; Footer” using React</title>
      <dc:creator>Dzung Nguyen</dc:creator>
      <pubDate>Fri, 01 Feb 2019 14:14:33 +0000</pubDate>
      <link>https://dev.to/dzungnguyen179/how-we-built-the-header--footer-21gp</link>
      <guid>https://dev.to/dzungnguyen179/how-we-built-the-header--footer-21gp</guid>
      <description>&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;In 2016, &lt;a href="https://www.chotot.com/" rel="noopener noreferrer"&gt;Chợ Tốt&lt;/a&gt; rebuilt frontend web application using React &amp;amp; Redux for business expansion. Likewise, we also decided to step by step migrate current services to Microservices Architecture to scale up. To boost the speed of our web app, we split our business into small chunks and each one is an application. Although doing this way reduces the complexity of the business, we faced some challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; many web apps mean the more work to keep consistency across product features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusability:&lt;/strong&gt; many web apps mean we need a way to organize and share common components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One particular feature on our website that has all these challenges is the “Header&amp;amp; Footer”. Typically, the “Header &amp;amp; Footer” is used by all products at Chợ Tốt and it contains links to important pages that potential users will often visit before making a purchase or inquiry.&lt;/p&gt;

&lt;p&gt;This topic talks about 3 main points of how we built the “Header &amp;amp; Footer”:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture&lt;/li&gt;
&lt;li&gt;CSS&lt;/li&gt;
&lt;li&gt;Build process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before deep dive into the detail, let’s take a look at the principles we keep in mind when we develop this component.&lt;/p&gt;

&lt;h1&gt;
  
  
  Principles
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Usability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We keep in mind the “Simplicity &amp;amp; Efficiency” of the components’ interface. They also help developers integrate easily.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple“ — Steve Jobs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let’s look at the example of 2 components code as shown:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2ALTsFGDAnw4FWFVgLefOvOQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2ALTsFGDAnw4FWFVgLefOvOQ.jpeg" title="Code example" alt="Code example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s easy to see that if we want to use the component on the left side, we have to read documents carefully to understand the meaning of each prop and what if there is no document?. Developers often dive into the code to see how it works and makes assumptions.&lt;/p&gt;

&lt;p&gt;On the other hand, the right side there are only 3 props they need to care about and the name of properties are declarative. With that even though the developers don’t read the document, they still understand it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A library is like a product of developers. If it has a good UX (How easy to use it), other developers will be happy to use it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extensibility &amp;amp; Testability&lt;/strong&gt;&lt;br&gt;
With the business expansion, there are a lot of features integrated into the “app-wrapper”. We follow the “Single Responsibility Principle” to design the code base to make it easy to extend and test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Less depending on libraries.&lt;/strong&gt;&lt;br&gt;
Using many libraries to develop is unnecessary. The more libraries we use, the bigger size of JS file is. It inadvertently slows down the web page loading. Because Chợ Tốt products reply on React &amp;amp; Redux, we decided to keep only those libraries to develop “app-wrapper”.&lt;/p&gt;
&lt;h1&gt;
  
  
  I. Architecture
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AVUbTm3nuTTeF6Ptjrma6Pw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AVUbTm3nuTTeF6Ptjrma6Pw.png" title="Architecture" alt="Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app-wrapper divides into 2 zones&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Component&lt;/li&gt;
&lt;li&gt;Extension&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  1.1. What is the Component zone?
&lt;/h2&gt;

&lt;p&gt;The component zone contains web components need to render the Header &amp;amp; Footer such as:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A1WmIeGbKrdkAnuhn7hDT5w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A1WmIeGbKrdkAnuhn7hDT5w.jpeg" title="What is the Component zone?" alt="What is the Component zone?"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  1.1a. Problem
&lt;/h3&gt;

&lt;p&gt;The Microservices Architecture is good for reducing the complexity and unnecessary code of the particular feature under construction. However, with many new features are continually released every 1–2 months and each one has its own “entry point” when we release a new feature, we need to add “entry point” to the “app-wrapper” and publish it with a new version. Then we go to each project to upgrade the “app-wrapper” in order to have an entry point link to this feature.&lt;/p&gt;

&lt;p&gt;Additionally, we have a lot of web applications and we have to make sure all of them have the latest version of app-wrapper. What happens if we miss one? It could affect user experience.&lt;/p&gt;
&lt;h3&gt;
  
  
  1.1b. Solution
&lt;/h3&gt;

&lt;p&gt;Because of these reasons, we decided to develop an API to manage entry points, the “app-wrapper” makes a request to fetch a list of menu items from the server and render.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A53pphwKU8u8l67GYLyjvmA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A53pphwKU8u8l67GYLyjvmA.png" title="Sequence diagram" alt="Sequence diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By doing this way, when we have a new entry point, we only update the entry point at API endpoint and do it once.&lt;/p&gt;
&lt;h2&gt;
  
  
  1.2. What is the Extension zone?
&lt;/h2&gt;

&lt;p&gt;The “app-wrapper” has some social features such as &lt;strong&gt;“Receiving Chat’s Notification”, “Displaying Announcements”&lt;/strong&gt;. Those features require a lot of logic and big libraries such as Socket I/O. If we put all the code inside the “app-wrapper”, here what we are going to deal with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The code base is going to be huge.&lt;/li&gt;
&lt;li&gt;It hurts “Single Responsibility Principle”. Since the “app-wrapper” take care of displaying Header &amp;amp; Footer. It doesn’t need to take care of other business.&lt;/li&gt;
&lt;li&gt;It unnecessarily becomes more complex.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  1.2a. Solution
&lt;/h3&gt;

&lt;p&gt;We develop an area called “Extension” zone which allows loading asynchronously the third party services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A5oWaI9WxTiDIxHkXoLk8bQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A5oWaI9WxTiDIxHkXoLk8bQ.png" title="Extension architecture" alt="Extension architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For example:&lt;/em&gt;&lt;br&gt;
&lt;em&gt;We got the CDN links to services “Receiving Chat Notification” &amp;amp; “Receiving Announcements” (each service is a specific project and the output is a CDN link). Then we only need to register the link to “Extension” zone and let the Extension do the rest.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By doing this way, we achieve some benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Delegating all the logic of third-party services to CDN links helps to separate the logic.&lt;/li&gt;
&lt;li&gt;Reducing the size of the main JS file.&lt;/li&gt;
&lt;li&gt;Simplifying code base which helps other engineers easy to improve.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  II. CSS
&lt;/h1&gt;

&lt;p&gt;The “app-wrapper” contains the styles itself. Choosing a way to manage CSS is one of the hardest problems. There are 2 approaches:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS-in-JS&lt;/strong&gt;&lt;br&gt;
JS exports CSS to a JS module. This means we could import CSS directly to JS code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AZUc3qz2HMYOjiyKafq2mWQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AZUc3qz2HMYOjiyKafq2mWQ.png" title="CSS-in-JS" alt="CSS-in-JS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS file&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the original method. All CSS is bundled to CSS file (style.css).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AY0Cb4386nPbRNY_grcN4jA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AY0Cb4386nPbRNY_grcN4jA.png" title="CSS file" alt="CSS file"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2.1. Approach
&lt;/h2&gt;

&lt;p&gt;Since all products at Chợ Tốt use JS to develop and the “app-wrapper” is a library which needs to provide less configuration for developers to integrate to main apps. For this reason, we decided to choose “CSS-in-JS” approach to manage styles of “app-wrapper”.&lt;/p&gt;

&lt;p&gt;There are some libraries help to apply “CSS-in-JS” approach such as “styled-components”, “JSS”,… However, we have various teams and each team has its own style. Some use “CSS-in-JS”, some use “CSS file” to develop web apps. So the question is “Is there any method that could fit all?”. And we came with 1 solution that instead of using CSS-in-JS frameworks, we choose “&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals" rel="noopener noreferrer"&gt;Template strings&lt;/a&gt;” feature of ES6 to develop CSS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2ALlc4V2XeNc5AjqwGw6TZCQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2ALlc4V2XeNc5AjqwGw6TZCQ.png" title="Template strings" alt="Template strings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After using this approach. Everything works pretty well. However, we encountered 2 big problems in the production environment.&lt;/p&gt;
&lt;h2&gt;
  
  
  2.2. Problem
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CSS is not minified.&lt;/li&gt;
&lt;li&gt;CSS does not contain prefixes for old browsers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2At_GpRa50Mkef_ZE0zfpSKw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2At_GpRa50Mkef_ZE0zfpSKw.png" title="CSS is not minified &amp;amp; not contain prefixes" alt="CSS is not minified &amp;amp; not contain prefixes"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2.3. Solution
&lt;/h2&gt;

&lt;p&gt;After running the build command to compile ES6 to ES5, we run another script to add prefixes &amp;amp; minify the CSS.&lt;/p&gt;

&lt;p&gt;We chose &lt;a href="https://gulpjs.com/" rel="noopener noreferrer"&gt;Gulp&lt;/a&gt; to customize the build process by adding the post-build stage with 2 tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minifying&lt;/li&gt;
&lt;li&gt;Autoprefix&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A4tHxkCFEuC4A7lfUJrVsIg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A4tHxkCFEuC4A7lfUJrVsIg.png" title="scripts" alt="scripts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It means after we ran the build command successfully&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The post-build command is automatically executed. Below is the result applied this method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AcSgmGi2dfka1GWt3OP8-sg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AcSgmGi2dfka1GWt3OP8-sg.png" title="Final CSS" alt="Final CSS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  III. Build process
&lt;/h1&gt;

&lt;p&gt;The build process is the way we convert JS code from ES6 to ES5 by using &lt;a href="https://babeljs.io/docs/en/babel-cli" rel="noopener noreferrer"&gt;Babel CLI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A-YZ5xxq8lzP-Yb9GMMEZTw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A-YZ5xxq8lzP-Yb9GMMEZTw.png" title="Build process" alt="Build process"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The build process has 2 stages.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stage 1 (build): It uses babel CLI to compile the ES6 code to ES5 code.&lt;/li&gt;
&lt;li&gt;Stage 2 (postbuild): It runs gulp tasks to minify &amp;amp; adds prefixes to CSS string from the build directory of stage 1.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After we finish the build process, we version the package and publish to private npm registry. All the projects only need to install a newer version of the package and enjoy.&lt;/p&gt;

&lt;h1&gt;
  
  
  Usage
&lt;/h1&gt;

&lt;p&gt;We have just described the detail of “How we built the Header &amp;amp; Footer”. Now let’s have a quick look at the usage of the app-wrapper component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A2JZ2Vn8N7fFFet0jU8O-EQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A2JZ2Vn8N7fFFet0jU8O-EQ.png" title="Usage 1" alt="Usage 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;with next.js&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AJNM2ABOo_ijL-hEbimPyPw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AJNM2ABOo_ijL-hEbimPyPw.png" title="Usage 2" alt="Usage 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mobile demo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A8-2AtJ9DlqcOWS8spaBEhg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A8-2AtJ9DlqcOWS8spaBEhg.gif" title="Mobile demo" alt="Mobile demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Desktop demo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AFiCyg4tz6K3gjenLHnY02Q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AFiCyg4tz6K3gjenLHnY02Q.gif" title="Desktop demo" alt="Desktop demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Currently, the app-wrapper component is used by all the Chợ Tốt’s products.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.chotot.com/" rel="noopener noreferrer"&gt;https://www.chotot.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://xe.chotot.com/" rel="noopener noreferrer"&gt;https://xe.chotot.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nha.chotot.com/" rel="noopener noreferrer"&gt;https://nha.chotot.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and more…&lt;/p&gt;

&lt;p&gt;We solved the 2 problems mentioned at the beginning of the post: &lt;strong&gt;“Consistency &amp;amp; Reusability”&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Besides that, we could bring the “app-wrapper” to the next level to become a common library.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apply the Context API which allows easy to change a theme such as color, icon, logo, … based on the business.&lt;/li&gt;
&lt;li&gt;Integrate CI/CD for testing, deployment, …&lt;/li&gt;
&lt;li&gt;Consider integrating strong type system such as &lt;a href="https://flow.org/" rel="noopener noreferrer"&gt;Flow Type&lt;/a&gt;, &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Introducing React Paginating 🎉🎉🎉</title>
      <dc:creator>Dzung Nguyen</dc:creator>
      <pubDate>Wed, 07 Feb 2018 15:23:17 +0000</pubDate>
      <link>https://dev.to/dzungnguyen179/introducing-react-paginating---1126</link>
      <guid>https://dev.to/dzungnguyen179/introducing-react-paginating---1126</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/ChoTotOSS/react-paginating" rel="noopener noreferrer"&gt;React Paginating&lt;/a&gt; component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A_O4M_FFMdoj3VkqZ6EMMAQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A_O4M_FFMdoj3VkqZ6EMMAQ.gif" title="gif react-paginating demo" alt="gif react-paginating demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are some popular components which help us to solve pagination problem such as &lt;a href="https://github.com/AdeleD/react-paginate" rel="noopener noreferrer"&gt;react-paginate&lt;/a&gt;, &lt;a href="https://github.com/AZaviruha/pager" rel="noopener noreferrer"&gt;react-pager&lt;/a&gt;, … Now there is another one. It’s called &lt;a href="https://github.com/ChoTotOSS/react-paginating" rel="noopener noreferrer"&gt;react-paginating&lt;/a&gt; with a different approach.&lt;/p&gt;

&lt;h1&gt;
  
  
  How “react-paginating” is different
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;“react-paginating”&lt;/strong&gt; uses &lt;a href="https://reactjs.org/docs/render-props.html" rel="noopener noreferrer"&gt;Render Props&lt;/a&gt; pattern which allows a component to publish any variables, states or functions to the outside as input params of a function which is going to be used for handling logic and rendering the UI.&lt;/p&gt;

&lt;p&gt;Here are some differences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input props.&lt;/li&gt;
&lt;li&gt;Controlled props.&lt;/li&gt;
&lt;li&gt;Child callback functions.&lt;/li&gt;
&lt;li&gt;Flexible UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Input props
&lt;/h2&gt;

&lt;p&gt;We minimize the number of props which you pass to “react-paginating” for some several reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make code more readable.&lt;/li&gt;
&lt;li&gt;Easy to remember the props.&lt;/li&gt;
&lt;li&gt;Not taking too much time to read a document.&lt;/li&gt;
&lt;li&gt;Easy to use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a list of input props:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;total&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The total records of your data. Your API should include it&lt;/p&gt;

&lt;p&gt;I.e:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"foo"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;limit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How many pages you want to have based on a limit. The formula to calculate totalPages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalPages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;pageCount&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How many pages you want to display.&lt;/p&gt;

&lt;p&gt;I.e:&lt;/p&gt;

&lt;p&gt;pageCount = 5&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A_peOMEb0O-zkS1AZ9VoU3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A_peOMEb0O-zkS1AZ9VoU3w.png" title="with pageCount = 5" alt="with pageCount = 5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;pageCount = 9&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AJtcj5soI7RwOGH9RK6d2Yg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AJtcj5soI7RwOGH9RK6d2Yg.png" title="with pageCount = 9" alt="with pageCount = 9"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;currentPage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The page currently you are visiting. You can pass it from your &lt;strong&gt;“query string”&lt;/strong&gt; or &lt;strong&gt;“state”&lt;/strong&gt;. You can visit the example &lt;a href="https://github.com/ChoTotOSS/react-paginating/tree/master/examples" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Controlled props
&lt;/h2&gt;

&lt;p&gt;After receiving input props. The component calculates and publishes props which allow controlling UI. Here is a list of public props:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pages&lt;/li&gt;
&lt;li&gt;currentPage&lt;/li&gt;
&lt;li&gt;previousPage&lt;/li&gt;
&lt;li&gt;nextPage&lt;/li&gt;
&lt;li&gt;totalPages&lt;/li&gt;
&lt;li&gt;hasNextPage&lt;/li&gt;
&lt;li&gt;hasPreviousPage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is how it looks like in code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Pagination&lt;/span&gt; &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;pageCount&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pageCount&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;currentPage&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;currentPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;hasNextPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;hasPreviousPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;previousPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;nextPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;totalPages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;getPageItemProps&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/?page=1"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;first&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hasPreviousPage&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;previousPage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#fdce09&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hasNextPage&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;nextPage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;totalPages&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;last&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Pagination&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Child callback functions
&lt;/h2&gt;

&lt;p&gt;If you use paging with state and has no update on your query string. You can use this callback function pass to your control.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
      &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#fdce09&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nf"&gt;getPageItemProps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;pageValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;onPageChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handlePageChange&lt;/span&gt;
      &lt;span class="p"&gt;})}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Flexible UI
&lt;/h2&gt;

&lt;p&gt;By using Function as Child Components pattern. We can completely control UI component. Take a look:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;
      &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#fdce09&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CustomAnchor&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./component/CustomAnchor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CustomAnchor&lt;/span&gt;
      &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#fdce09&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/CustomAnchor&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above shows that we can create  component and then replace &lt;a&gt;&lt;/a&gt;. After that, you might put your  somewhere on your “&lt;a href="https://github.com/storybooks/storybook" rel="noopener noreferrer"&gt;storybook&lt;/a&gt;” or components manager.&lt;/p&gt;

&lt;h1&gt;
  
  
  Demo
&lt;/h1&gt;

&lt;p&gt;You can check a basic demo: &lt;a href="https://codesandbox.io/s/z2rr7z23ol" rel="noopener noreferrer"&gt;https://codesandbox.io/s/z2rr7z23ol&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;If you see it is useful for you. Please give react-paginating &lt;a href="https://github.com/ChoTotOSS/react-paginating/stargazers" rel="noopener noreferrer"&gt;a star 🌟&lt;/a&gt;, &lt;a href="https://github.com/ChoTotOSS/react-paginating/watchers" rel="noopener noreferrer"&gt;a watch 👀&lt;/a&gt;, and &lt;a href="https://codesandbox.io/s/z2rr7z23ol" rel="noopener noreferrer"&gt;a try 😎&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Or if you see any issues or improvements. &lt;a href="https://github.com/ChoTotOSS/react-paginating/pulls" rel="noopener noreferrer"&gt;PR is welcomed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The original article is &lt;a href="https://medium.com/@nndung179/introducing-react-paginating-9128f30f1f6b" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;

</description>
      <category>react</category>
      <category>pagination</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>next.js at Chotot</title>
      <dc:creator>Dzung Nguyen</dc:creator>
      <pubDate>Tue, 30 Jan 2018 11:18:25 +0000</pubDate>
      <link>https://dev.to/dzungnguyen179/nextjs-at-chotot-7h0</link>
      <guid>https://dev.to/dzungnguyen179/nextjs-at-chotot-7h0</guid>
      <description>&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;Every day, &lt;a href="https://www.chotot.com"&gt;Chợ tốt&lt;/a&gt; (Chotot) receives over 1 million visits cross platforms, most of the traffic comes from mobile devices. It is really important for us to develop products that can run across devices. Last year, we switched to a new stack to rebuild our products.&lt;/p&gt;

&lt;p&gt;The technologies that we chose for our new stack are: &lt;a href="https://reactjs.org"&gt;React&lt;/a&gt;, &lt;a href="https://redux.js.org"&gt;Redux&lt;/a&gt; &amp;amp; &lt;a href="https://nodejs.org/en/"&gt;NodeJS&lt;/a&gt; to build the new web app. React makes it easy to build web components that can be reused in other products. Redux is the main channel communicating between the Back End &amp;amp; Front End. NodeJS builds a web server. To support SEO with this stack, we implement the “&lt;a href="https://www.smashingmagazine.com/2016/03/server-side-rendering-react-node-express/"&gt;Universal Web Application&lt;/a&gt;” approach.&lt;/p&gt;

&lt;h1&gt;
  
  
  First boilerplate
&lt;/h1&gt;

&lt;p&gt;Base on a starter boilerplate put together by &lt;a href="https://github.com/erikras"&gt;erikras&lt;/a&gt; (link &lt;a href="https://github.com/erikras/react-redux-universal-hot-example"&gt;here&lt;/a&gt;) to experiment with our new web stack. However, we encountered problems in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  problem
&lt;/h2&gt;

&lt;p&gt;In production, if the traffic is high, the web server will stop responding to the client. At first, we optimized our codebase but the result was still the same. We resolved to use client-side rendering instead of server-side rendering. But the challenge is if we turn off server rendering, SEO will be affected.&lt;/p&gt;

&lt;h2&gt;
  
  
  solution 1
&lt;/h2&gt;

&lt;p&gt;Search engines now support Javascript in their crawlers (check here for more detail). Our first solution was to delegate the rendering page to client-side. Here is our analysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SEO was affected negatively&lt;/li&gt;
&lt;li&gt;Our ranking dropped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The crawlers were still indexing but it was slower than using server-side rendering. So delegating all missions to client-side did not work for us.&lt;/p&gt;

&lt;h2&gt;
  
  
  solution 2
&lt;/h2&gt;

&lt;p&gt;The next solution was to split the project into 2 and deploy it to 2 different servers. One serves users with client-side rendering. Another one serves crawlers bot from Google, Facebook, … with server-side rendering.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--93CAm7Fl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AqVApQ-95VJPJMmCEw7L3JQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--93CAm7Fl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AqVApQ-95VJPJMmCEw7L3JQ.png" alt="Solution 2" title="Solution 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This solution worked fine. However, we were also looking for another boilerplate to replace it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why did we want to change?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When deploying code changes we had to deploy the new version to 2 different servers.&lt;/li&gt;
&lt;li&gt;The boilerplate was out of date.&lt;/li&gt;
&lt;li&gt;The time to rebuild code at development was too slow. It took more than 10 seconds to rebuild every single change.&lt;/li&gt;
&lt;li&gt;We wanted to apply new tools to have good experience for Engineers and good performance for products as well: webpack 2 with many improvements like “&lt;a href="https://webpack.js.org/guides/tree-shaking/"&gt;Tree shaking&lt;/a&gt;”, “&lt;a href="http://thejameskyle.com/react-loadable.html"&gt;dynamic import&lt;/a&gt;”...&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  next.js 2 the rescuer
&lt;/h1&gt;

&lt;p&gt;After looking around some repos, we considered next.js as a potential replacement for several reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports server rendering natively.&lt;/li&gt;
&lt;li&gt;There are many small examples on integrations between next.js and other libraries or technologies (check them out &lt;a href="https://github.com/zeit/next.js/tree/master/examples"&gt;here&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;The documentation is very clean and up-to-date.&lt;/li&gt;
&lt;li&gt;next.js takes care of all basic configs. Allowing to extend configs of webpack or babel…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will talk about the way we applied next.js in our products including some issues and solutions. I will provide the sample at the end of this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  redux
&lt;/h2&gt;

&lt;p&gt;We chose redux to manage application states. next.js provides a &lt;a href="https://github.com/kirill-konshin/next-redux-wrapper"&gt;redux wrapper&lt;/a&gt; to help integrate with it easier and more consistent (You can visit &lt;a href="https://github.com/zeit/next.js/tree/master/examples/with-redux"&gt;here&lt;/a&gt; to see example)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;withRedux&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-redux-wrapper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ExamplePage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;withRedux&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;newsListing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newsListing&lt;/span&gt;
&lt;span class="p"&gt;}))(&lt;/span&gt;&lt;span class="nx"&gt;ExamplePage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we can see that Redux was wrapped by “next-redux-wrapper” as a &lt;a href="https://reactjs.org/docs/higher-order-components.html"&gt;Higher Order Component&lt;/a&gt;. To use redux, we have to wrap our component with the function ‘withRedux’.&lt;/p&gt;

&lt;h2&gt;
  
  
  routing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;“next.js”&lt;/strong&gt; provides a very clean directory structure. There is a special directory “pages”. When you put all your React components into that one, next.js automatically executes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;code splitting&lt;/li&gt;
&lt;li&gt;routing&lt;/li&gt;
&lt;li&gt;hot code reloading and universal (server-side and client-side) rendering.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You just don’t have to worry about configurations of all that stuff, next.js will manage them.&lt;/p&gt;

&lt;p&gt;We created 2 directories to place our React component. The first one is pages directory. The second one is the components directory.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;pages:&lt;/strong&gt; we use it for containers in redux.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;components:&lt;/strong&gt; to store stateful &amp;amp; stateless component in react.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  static resources
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;next.js&lt;/strong&gt; also provides a static directory to serve static resources for the web application. All you have to do is place all resources like images, fonts, stylesheets, … into the ‘static’ directory. Then just use it as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8uctqWAc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2Aq7ApZv_Ch3jG9LsClb_rkA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8uctqWAc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2Aq7ApZv_Ch3jG9LsClb_rkA.png" alt="static directory" title="static directory"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;image&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;'/static/img/logo.png'&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;css&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;'stylesheet'&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;'/static/css/app.css'&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  import modules
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CSSTag&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../../components/CSSTag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your module contains many nested directories, this option is going to be complicated. There are many ways to solve this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alias config of webpack&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can use the &lt;a href="https://webpack.js.org/configuration/resolve/#resolve-alias"&gt;alias feature&lt;/a&gt; of webpack to define alias names for your modules (You can check out how to extend webpack config in next.js here). And then just import it as follows:&lt;/p&gt;

&lt;p&gt;next.config.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;components_example&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and use it like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CSSTag&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;components_example/CSSTag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But every time you add a new directory as a module container, you have to define it in your webpack config.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add NODE_PATH to commands&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can set NODE_PATH into our commands in package.json like:&lt;/p&gt;

&lt;p&gt;package.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NODE_PATH=./ next"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By setting NODE_PATH, our current position is now at the root directory when we run command “npm run dev”. We can import as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CSSTag&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;components/CSSTag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, this will complicate our commands and if the commands require root path, NODE_PATH needs to be added.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;babel plugins&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We resolved this by using babel plugin provided by next.js. “&lt;a href="https://www.npmjs.com/package/babel-plugin-root-import"&gt;babel-plugin-root-import&lt;/a&gt;” allows us to configure our root path with specified characters in .babelrc (You can learn how to customize babel config &lt;a href="https://github.com/zeit/next.js#customizing-babel-config"&gt;here&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"presets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"next/babel"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"babel-plugin-root-import"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"rootPathPrefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The root path is “@”. So you can import a module at components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CSSTag&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/CSSTag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CSS development&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To develop CSS we use the pre-processor &lt;a href="http://sass-lang.com"&gt;Sass&lt;/a&gt; with SCSS syntax. Sass provides many functionalities (check them out &lt;a href="http://sass-lang.com/guide"&gt;here&lt;/a&gt;). It allows us to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;write functions (@mixin)&lt;/li&gt;
&lt;li&gt;define variables&lt;/li&gt;
&lt;li&gt;call a function (&lt;a class="mentioned-user" href="https://dev.to/include"&gt;@include&lt;/a&gt;
)&lt;/li&gt;
&lt;li&gt;We can write CSS with module scope&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To integrate SCSS with next.js, we also referenced this &lt;a href="https://github.com/zeit/next.js/tree/master/examples/with-global-stylesheet"&gt;example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;/styles/index.scss&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.indexPage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.cardItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;/pages/index.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;withRedux&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-redux-wrapper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// style&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/styles/index.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;IndexPage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;indexPage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="nx"&gt;am&lt;/span&gt; &lt;span class="nx"&gt;Index&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="o"&gt;!!!&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="nx"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;withRedux&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;newsListing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newsListing&lt;/span&gt;
&lt;span class="p"&gt;}))(&lt;/span&gt;&lt;span class="nx"&gt;IndexPage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In production mode, when you browse your site and use &lt;strong&gt;“View Page Source”&lt;/strong&gt; you will see styles are not minified in the HTML document. If our styles are large, that means the time to ship your page to the client is going to increase.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ttYmRUbm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2A41bdhnJ61XBQB2OaWvmAjA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ttYmRUbm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2A41bdhnJ61XBQB2OaWvmAjA.png" alt="page source" title="page source"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;solution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We use &lt;a href="https://gulpjs.com"&gt;gulp&lt;/a&gt; and &lt;a href="https://github.com/postcss/postcss-cli"&gt;postCSS&lt;/a&gt; CLI to manage CSS in production mode. The output of this step will produce an app.css file which includes all minified styles used in our web application.&lt;/p&gt;

&lt;p&gt;The idea is each component will have a style file (*.scss). We divided the way to develop CSS with 2 environments.&lt;/p&gt;

&lt;p&gt;** development**&lt;/p&gt;

&lt;p&gt;We created a stateless component called CSSTag to manage CSS at development.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Note&lt;/span&gt;
&lt;span class="c1"&gt;// this component will only work for ENV = development&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;CSSTag&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="nx"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;CSSTag&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and we can use it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/styles/Example.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CSSTag&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CSSTag&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/CSSTag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// style&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/styles/Example.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Example&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;Example&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CSSTag&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Example&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** production**&lt;/p&gt;

&lt;p&gt;We created &lt;strong&gt;‘app.scss’&lt;/strong&gt; which includes all styles of the web application, then we used &lt;strong&gt;gulp&lt;/strong&gt; to build final CSS based on &lt;strong&gt;‘app.scss’&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The final CSS has to meet some rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;contains all styles of web application&lt;/li&gt;
&lt;li&gt;auto-prefix&lt;/li&gt;
&lt;li&gt;minified&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;app.scss&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="c1"&gt;// components&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;"./variables"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;"./ultilities"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;"./global.scss"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;"./components/ToolBar"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// pages&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;"./index.scss"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;gulpfile.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-sass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minifyCSS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-csso&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./styles/**/app.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sass&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minifyCSS&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./static/css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;autoprefix with postCSS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The last step to produce final CSS is auto-prefix. We are using &lt;a href="https://github.com/postcss/postcss-cli"&gt;postCSS CLI&lt;/a&gt; to auto-prefix final CSS after gulp bundled it. Then includes final CSS to our document via “_document.js” (you can check out &lt;a href="https://github.com/zeit/next.js/#custom-document"&gt;here&lt;/a&gt; to know how to use extend document)&lt;/p&gt;

&lt;p&gt;Here is the diagram that shows the way we manage CSS in production mode:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G36XsAIK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2A0585i_utNTYz-bYO0VaYZQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G36XsAIK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2A0585i_utNTYz-bYO0VaYZQ.png" alt="production CSS building with gulp" title="production CSS building with gulp"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Result
&lt;/h1&gt;

&lt;p&gt;After completed a project with “next.js”, we used &lt;a href="https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk"&gt;lighthouse&lt;/a&gt; to audit our web page. Here is a result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VEsdpq62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2Ac8ZAblSWnxG2lerweQWlaA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VEsdpq62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2Ac8ZAblSWnxG2lerweQWlaA.jpeg" alt="new lighthouse" title="new lighthouse"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a result of the old one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AdayivlO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AUMW4ExtkVDy6wgN-mz_bXg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AdayivlO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AUMW4ExtkVDy6wgN-mz_bXg.png" alt="old lighthouse" title="old lighthouse"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see here the &lt;a href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/"&gt;Critical Rendering Path&lt;/a&gt; of the first result we only need 1.5s for first meaningful paint while the second result is 9.5s. We improved a lot of performance with next.js.&lt;/p&gt;

&lt;h1&gt;
  
  
  Demo
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Here is a full demo&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/davidnguyen179/nextjs-full-demo"&gt;https://github.com/davidnguyen179/nextjs-full-demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What’s next?
&lt;/h1&gt;

&lt;p&gt;Next.js gives us a lot of benefits so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance&lt;/li&gt;
&lt;li&gt;Lightweight&lt;/li&gt;
&lt;li&gt;Easy to use&lt;/li&gt;
&lt;li&gt;Well document&lt;/li&gt;
&lt;li&gt;Strong support from the community&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the new feature of next.js 3, we are so excited to apply &lt;strong&gt;“dynamic import”&lt;/strong&gt; into our product to speed up the performance.&lt;/p&gt;

</description>
      <category>react</category>
      <category>redux</category>
      <category>nextjs</category>
      <category>webperf</category>
    </item>
    <item>
      <title>next.js multiple environment builds</title>
      <dc:creator>Dzung Nguyen</dc:creator>
      <pubDate>Mon, 29 Jan 2018 13:39:14 +0000</pubDate>
      <link>https://dev.to/dzungnguyen179/nextjs-multiple-environment-builds-4hef</link>
      <guid>https://dev.to/dzungnguyen179/nextjs-multiple-environment-builds-4hef</guid>
      <description>&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/zeit/next.js/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; is a minimalistic framework for the universal web application using &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;ReactJS&lt;/a&gt;. It was open-sourced 25th October 2016. The company behind Next is &lt;a href="https://zeit.co/" rel="noopener noreferrer"&gt;ZEIT&lt;/a&gt;. It has huge contributors out there to maintain and improve. Next provides easy interfaces for web development and has some advantages such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports server rendering natively.&lt;/li&gt;
&lt;li&gt;There are many small examples of integrations between next.js and other libraries or technologies (check them out here).&lt;/li&gt;
&lt;li&gt;The documentation is very clean and up-to-date.&lt;/li&gt;
&lt;li&gt;Next takes care of all basic configs. Allowing to extend configs of webpack or babel…&lt;/li&gt;
&lt;li&gt;It has a huge community to support when we got issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recently, we have used next.js for some experiment projects in our company (You can check &lt;a href="https://codeburst.io/next-js-at-chotot-ca9c1520f436" rel="noopener noreferrer"&gt;here&lt;/a&gt; to know why we chose next.js). During development, we met a problem with multiple env builds.&lt;/p&gt;

&lt;h1&gt;
  
  
  next build — development vs production
&lt;/h1&gt;

&lt;h2&gt;
  
  
  development
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Next only builds a page that you are visiting.&lt;/li&gt;
&lt;li&gt;Every single changed, Next rebuilds your web app into “.next” directory, but only a page that you are visiting for speed up development.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For example:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our web app has 6 pages: home (index.js), create new (action.js), listing (listing.js) register &amp;amp; login (auth.js), list of accounts (accounts.js), detail account (detail_account.js).&lt;/li&gt;
&lt;li&gt;When visiting “home” page, Next will bundle everything belongs to “home” page (index.js).&lt;/li&gt;
&lt;li&gt;Similarly with “create new” page, Next bundles everything belongs to “create new” page (action.js) into “.next” directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AIIR-nu76WmDWbIw2." class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AIIR-nu76WmDWbIw2." title="Development" alt="development"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  production
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Next bundles everything belongs to our web app into “.next” directory.&lt;/li&gt;
&lt;li&gt;When you visit a page, next will not rebuild again because it already built in “.next” directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AiZ1gcg7x4tFG4peM." class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AiZ1gcg7x4tFG4peM." title="Production" alt="production"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Scenario
&lt;/h1&gt;

&lt;p&gt;In our process, we divided a development environment (env) into 3 parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Development:&lt;/strong&gt; for Engineers to develop features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Staging:&lt;/strong&gt; for Quality Assurance (QA) to test features before it comes to real production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production:&lt;/strong&gt; for Users to use features.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each env uses different configs, API endpoints, resources (CPU, RAM, …). But the staging and production have to be as similar as possible.&lt;/p&gt;

&lt;p&gt;Below is our package.json scripts to manage to build and run of our web app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"start:development"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"start:staging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NODE_ENV=staging node server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"start:production"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NODE_ENV=production node server.js"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have 4 commands. In each environment, we will run with order:&lt;br&gt;
&lt;strong&gt;development&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;npm start&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;staging&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;npm run build&lt;/li&gt;
&lt;li&gt;npm run start:staging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;production&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;npm run build&lt;/li&gt;
&lt;li&gt;npm run start:production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After running commands above, we have the &lt;strong&gt;NODE_ENV&lt;/strong&gt;, then we can get configs of that &lt;strong&gt;NODE_ENV&lt;/strong&gt; to serve our stuff.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;configs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.staging.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;staging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.staging.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.production.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;configs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Problem
&lt;/h1&gt;

&lt;p&gt;While development &amp;amp; production work well. We met a problem at “staging” env. Here is what happened when we build &amp;amp; run our web app in staging env:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;npm run build:&lt;/strong&gt; Next bundles everything (page, resource, …) into “.next” directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm run start:staging:&lt;/strong&gt; Next detects &lt;strong&gt;NODE_ENV&lt;/strong&gt; is not production. It automatically rebuilds our web app with development env everytime you visit a page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means in staging env, our web app is treated as development env. So when you visit a page, Next takes time to rebuild it again. It affects our performance and productivity of the team in staging env.&lt;/p&gt;

&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;We found out that Next only support 2 env: development &amp;amp; production in “run command”. So if you pass NODE_ENV=production to “run command”, Next will not treat your app as development env.&lt;/p&gt;

&lt;p&gt;So here are new “run commands” in &lt;strong&gt;package.json&lt;/strong&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"start:development"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"start:staging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NODE_ENV=production ENV=staging node server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"start:production"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NODE_ENV=production ENV=production node server.js"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In staging &amp;amp; production run commands, we pass &lt;strong&gt;NODE_ENV=production&lt;/strong&gt; to notify Next that we want to build our web app in production mode. We also pass another argument called &lt;strong&gt;ENV&lt;/strong&gt; to determine the environment value to load env resources from “config.js”.&lt;/p&gt;

&lt;p&gt;In config files, we changed to use &lt;strong&gt;ENV&lt;/strong&gt; instead of &lt;strong&gt;NODE_ENV&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ENV&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;configs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.staging.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;staging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.staging.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.production.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;configs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This solution works well for our projects using Next. Of course, there are many solutions out there. If you have a better solution, you can give me the feedbacks.&lt;/p&gt;

&lt;p&gt;Thank you very much!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>environment</category>
      <category>build</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
