<?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: Mikhail Kedzel</title>
    <description>The latest articles on DEV Community by Mikhail Kedzel (@bearrrrr).</description>
    <link>https://dev.to/bearrrrr</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%2F181492%2F7335aaa0-0a85-4b1f-a478-da34c82177e1.jpeg</url>
      <title>DEV Community: Mikhail Kedzel</title>
      <link>https://dev.to/bearrrrr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bearrrrr"/>
    <language>en</language>
    <item>
      <title>Creating a blockchain based digital passport</title>
      <dc:creator>Mikhail Kedzel</dc:creator>
      <pubDate>Mon, 07 Aug 2023 02:10:14 +0000</pubDate>
      <link>https://dev.to/miki-digital/creating-a-blockchain-based-digital-passport-7cg</link>
      <guid>https://dev.to/miki-digital/creating-a-blockchain-based-digital-passport-7cg</guid>
      <description>&lt;h2&gt;
  
  
  Our client
&lt;/h2&gt;

&lt;p&gt;Proof of Meet(POM) is what started as a hackathon project and grew into a full-scale startup. We worked with the client from the beginning, supporting them at every step with savvy developers. Our expertise went way beyond just code, as we saw the business value as well and were able to connect that to tech.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project description
&lt;/h2&gt;

&lt;p&gt;POM is a Polygon blockchain-based digital passport (a DID wallet), used to share credentials, such as identity and employment history.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--edYVQfao--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3840/1%2A7_lN4ah1AYnUqn9fRHcfAQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--edYVQfao--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3840/1%2A7_lN4ah1AYnUqn9fRHcfAQ.jpeg" alt="Polygon design" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cJdkDMNz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3840/1%2AbbWJXnG_o4F5SNV_7JhM2w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cJdkDMNz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3840/1%2AbbWJXnG_o4F5SNV_7JhM2w.jpeg" alt="POM interface/concept" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Working in a tight timeframe, we had to pick the right tools to develop bug-free code while being extremely agile. The frontend stack was simple yet efficient — TypeScript &amp;amp; NextJs. This allowed us not to spend any time configuring the boilerplate and get straight to work. At first, we didn’t have a designer, so our team used Tailwind — a performant CSS framework for the web, which also has a component library(TailwindUI).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7jsYnsFC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2432/0%2AtFOJtRR7sHHp_rTP.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7jsYnsFC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2432/0%2AtFOJtRR7sHHp_rTP.jpg" alt="TailwindUI logo" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As our Decentralized Identity(DID) provider, we used PolygonId, which enables you to build trusted and secure relationships between users and dApps, following the principles of self-sovereign identity and privacy by default. PolygonId allows users to use zero-knowledge proofs to interact with smart contracts, solving the "trust " problem in web3.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gbJAIb4i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4048/1%2AiJg4nEPQfFAXyTW6kS_vqQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gbJAIb4i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4048/1%2AiJg4nEPQfFAXyTW6kS_vqQ.png" alt="PolygonId logo" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As POM is scaling, we’re continuing to support it and growing our development team with them. Attracting skilled talent is extremely hard for a startup, but at MiKi, we can add up to 5 talented developers to the team in a matter of 4 days.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;Working together, we created a stunning MVP for POM, which won multiple hackathons and got the attention of investors. We won EthSeoul2023, the Polygon DevX hackathon, and more.&lt;br&gt;
In the future, we plan to support POM even more and help them develop awesome functionality.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>mobile</category>
      <category>react</category>
    </item>
    <item>
      <title>How to build the largest web3 community in Korea</title>
      <dc:creator>Mikhail Kedzel</dc:creator>
      <pubDate>Thu, 03 Aug 2023 01:35:02 +0000</pubDate>
      <link>https://dev.to/miki-digital/how-to-build-the-largest-web3-community-in-korea-1oco</link>
      <guid>https://dev.to/miki-digital/how-to-build-the-largest-web3-community-in-korea-1oco</guid>
      <description>&lt;h2&gt;
  
  
  How to build the largest web3 community in Korea
&lt;/h2&gt;

&lt;p&gt;Today we’re launching the first episode of &lt;strong&gt;MiKi Digital’s Web3 podcast&lt;/strong&gt;. And our guest is Jordan Smith, the founder of the largest web3 community in South Korea — SojuDAO. We had a great chat with him, talking about his journey, challenges, and plans for SojuDAO. Also, Jordan is currently working on a stealth startup that aims to disrupt the web3 professional social network industry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.miki.digital/podcasts"&gt;Tune into the podcast to learn more about it as well!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article will briefly summarize the podcast, condensing Jordan’s main points.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting into crypto
&lt;/h2&gt;

&lt;p&gt;After leaving university, Jordan worked for many big techs in Silicon Valley and Wall Street but always felt it wasn’t for him. Around 2017, he became interested in crypto and, in 2021, became full-time in crypto, working with a &lt;em&gt;little network&lt;/em&gt; called Terra. It was his first introduction to Korea’s vibrant crypto culture. The Terra crash didn’t discourage him but did quite the opposite.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“ *What it showed me is the power of Web3 and the power of community and in building something meaningful. While I was hurt financially, it actually just gave me a little bit more fire to bounce back and want to build something.&lt;/em&gt;” — Jordan*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oQt_TP2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2AHHgbrWoM5pPKzgsj" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oQt_TP2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2AHHgbrWoM5pPKzgsj" alt="The crash of Luna" width="598" height="797"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting SojuDAO
&lt;/h2&gt;

&lt;p&gt;Jordan moved to Korea in 2022 to live for a couple of months, and that’s when SojuDAO began. It started as a little group chat with Jordan and his friends, with the name being inspired by a famous Korean drink — Soju!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z3-5nuGZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2AQi5PcF2Egk5x5Tfy" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z3-5nuGZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2AQi5PcF2Egk5x5Tfy" alt="Soju — traditional Korean drink" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The community grew organically as Jordan introduced it to more people. Next, they hosted a social event, which was just a dinner. Over the year, community members were sponsoring other events, seeing the power in the community. The idea was received well in Korea since all the events are usually in professional settings, but &lt;strong&gt;SojuDAO creates relaxed events where people are better able to connect&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“ *From the feedback that I’ve gotten is our specialty that has come from throwing events consistently is that people are able to really build new relationships and forge new partnerships in these events.&lt;/em&gt;” — Jordan*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the first members of SojuDAO weren’t only foreigners, many Koreans appreciated the new way of organizing events. Talking about the future, Jordan says that while the roots of SojuDAO will remain in Korea, it will expand to other regions. In fact, SojuDAO already set up events in Tokyo, Hong Kong, and Paris. So SojuDAO will continue to evolve on a global landscape bringing more and more people together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kFzDmMJJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2Ak3Me-5t3Bj32IfMj" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kFzDmMJJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2Ak3Me-5t3Bj32IfMj" alt="SojuDao logo" width="400" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Changing Social Networking in Web3
&lt;/h2&gt;

&lt;p&gt;Our chat got really interesting when we started talking about the future of social networking in web3. Jordan is working on a &lt;strong&gt;secret startup to change the professional social network industry&lt;/strong&gt;. Jordan was open about his issues with existing platforms like LinkedIn. He shared his frustration with the platform’s move towards sales and away from building deep connections.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“ *I think that the reason why LinkedIn kind of sucks now is because of people like me have multiplied over the last four years. The former self, my former self. Like it’s a sales tool. It’s no longer a tool to like focus on your deep connections.&lt;/em&gt;” — Jordan*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s where &lt;strong&gt;POM(Proof of Meet)&lt;/strong&gt; comes in — a stealth-mode startup that Jordan is working on right now. It’ll enable people to have better social experiences. Jordan believes people are still lonelier than ever in a world where we have many ways to connect.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NcmVZRnK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3600/0%2A3hotz_7dj3lPeQ3E" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NcmVZRnK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3600/0%2A3hotz_7dj3lPeQ3E" alt="POM" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In web3, most people use Telegram to connect, but it lacks a lot of data about the person. So your connection can be easily forgotten. Jordan aims to build &lt;strong&gt;synergy between platforms like Telegram or Twitter, and POM&lt;/strong&gt; to make creating meaningful connections easier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“ *We’re not necessarily trying to get people to stop using Twitter or Telegram, but we want to enable people to use them better, to improve the relationships that mean something to them or give them an opportunity to find new relationships.&lt;/em&gt;” — Jordan*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The main point of POM is that it focuses on real-life connections. Since as Jordan said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“ *I think that may or may not be a contrarian opinion that most of the important relationships that you make are from in-person interaction.&lt;/em&gt;” — Jordan*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2EZagL8Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3600/0%2An1P6_8yN6DM-9t1F" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2EZagL8Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3600/0%2An1P6_8yN6DM-9t1F" alt="POM" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Overall thoughts on web3
&lt;/h2&gt;

&lt;p&gt;Regarding web3 trends, Jordan says that &lt;strong&gt;restaking and web3 socials can be the next big thing in web3.&lt;/strong&gt; As for the issues in web3, Jordan believes UX to be a major one. Since it’s still tough for people outside of the industry to get into web3 apps. You should always build apps with your users in mind.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“ *Most of the things are there to try to make a seamless experience, but we just have to build tools with the end user in mind.&lt;/em&gt;” — Jordan*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;P.S. &lt;em&gt;If you have any suggestions regarding the podcast or want to be the next guest feel free to &lt;a href="https://www.miki.digital/contact"&gt;contact us at our website&lt;/a&gt; or &lt;a href="https://calendly.com/miki-digital/15min"&gt;book a call&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Crafting the perfect token launchpad - technical description</title>
      <dc:creator>Mikhail Kedzel</dc:creator>
      <pubDate>Mon, 31 Jul 2023 10:11:38 +0000</pubDate>
      <link>https://dev.to/miki-digital/crafting-the-perfect-token-launchpad-technical-description-l1c</link>
      <guid>https://dev.to/miki-digital/crafting-the-perfect-token-launchpad-technical-description-l1c</guid>
      <description>&lt;p&gt;Recently, at &lt;a href="https://www.miki.digital/"&gt;MiKi&lt;/a&gt; we've created a token launchpad for one of our clients. The project is under NDA, so we can't tell you much. But still, we'll try our best to describe our approach when it comes to building a simple, yet impressive token launchpad on &lt;strong&gt;Ethereum blockchain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Our main requirements for a launchpad were&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Speed of development&lt;/strong&gt; - we had to meet tight deadlines&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Ease of future support&lt;/strong&gt; - the app had to be maintanable with clean, clear code&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Stability&lt;/strong&gt; - the app had to be fault-tolerant, we couldn't have even the slightest downtimes&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Blazing-fast loading&lt;/strong&gt; - if the app loads too long, it'll definitely frustrate our buyers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's discuss every part of the app, and what choices we made to meet all the requirements&lt;/p&gt;

&lt;p&gt;&lt;a id="org2a6ff00"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Frontend
&lt;/h2&gt;

&lt;p&gt;We picked NextJS as the framework, since it has huge user adoption, vast documentation and community support. In web3 as well, there are many libraries specifically built for NextJS or React(NextJs is built on top of React). For example, Moralis - a famous library to integrate Web3 into your app, has a lot of tutorials for specifically NextJS. As it's very easy to handle authentication there and intergate &lt;code&gt;next-auth&lt;/code&gt;(authentication library for NextJS) with Moralis.&lt;/p&gt;

&lt;p&gt;Compared to regular React, NextJS supports server-side rendering which makes your website load up to 5x times faster. For reference, here's the performance metrics for a typical React app&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qVGBmOod--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fae7rmm14p88vxks64sf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qVGBmOod--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fae7rmm14p88vxks64sf.png" alt="results for the CRA" width="730" height="1026"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here's the data for a NextJS app&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TzO1KhBo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6b9y6yghxn05tjsrvb7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TzO1KhBo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6b9y6yghxn05tjsrvb7.png" alt="results for the NextJS app" width="730" height="984"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Crazy difference, right?&lt;/p&gt;

&lt;p&gt;&lt;a id="org1d16ab5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Blockchain integration library
&lt;/h2&gt;

&lt;p&gt;We've picked the frontend framework, now we have to decide how to integrate our frontend with Ethereum blockchain and our smart contracts.&lt;/p&gt;

&lt;p&gt;Moralis is a great choice if you want to get going very fast, since it's a rather high level of abstraction. But it comes at a cost of limited customization. Even thought the deadlines were short, we still needed an extensible library which would allow future changes.&lt;/p&gt;

&lt;p&gt;We chose ethers - the tried and true library for interacting with Ethereum blockchain and it's ecosystem on the frontend. It's mostly used to intergate with wallets, so has first-class MetaMask support.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SXuhG81F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ygeko8hwq60eawykl7vo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SXuhG81F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ygeko8hwq60eawykl7vo.png" alt="Ethers logo" width="270" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A worthy metion is viem - we're using it on our current project and it's working flawlessly. Viem is still new, so using it might be harder than ethers, as there's less comunity support. But Viem addresses many flaws ethers had like type safety.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgbbc546c"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Doing it the React way
&lt;/h2&gt;

&lt;p&gt;We've also used &lt;code&gt;wagmi&lt;/code&gt; - a collection of React Hooks containing everything you need to start working with Ethereum. Wagmi works perfectly with ehters, as it uses ethers under the hook. While wagmi wraps some trivial functionality of ethers to provide you a simple interface, you'll still need to use ethers directly in some cases.&lt;/p&gt;

&lt;p&gt;If you want to read more about working with smart contract on the Frontend - check out our article where we go in depth and provide some code snippets &lt;a href="https://dev.to/miki-digital/working-with-smart-contract-on-the-frontend-3mem"&gt;https://dev.to/miki-digital/working-with-smart-contract-on-the-frontend-3mem&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id="org637bee6"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend
&lt;/h2&gt;

&lt;p&gt;We had to implement KYC so a backend was necessary. We could've just stored the KYC on the blockchain, but we weren't sure how large would it get in the future, so opted for a database MongoDB.&lt;/p&gt;

&lt;p&gt;As the BE framework - we still used NextJS. It has a minimalist, yet powerful way of writing serverless backend. You can easily run the backend locally, and deploying it is straight-forward as well thanks to vercel. Opossed to bigger providers like AWS, GCP and Azure, on Vercel you can deploy your whole app(backend and frontend) in a few minutes.&lt;/p&gt;

&lt;p&gt;The syntax is exteremely simple as well, you just need to declare a handler function for an api route, and handle the logic in there. For example, an API route for fetching balance of a smart contract from etherscan would look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default async function handle(req: NextApiRequest, res: NextApiResponse) {
  if(req.method === 'GET') {
    const resp = await fetch(`https://api.etherscan.io/api?module=account&amp;amp;action=balance&amp;amp;address=${process.env.NEXT_PUBLIC_CONTRACT_ADDRESS}&amp;amp;tag=latest&amp;amp;apikey=${process.env.ETHERSCAN_API_KEY}`);
    const json = await resp.json();
    res.json(json);
  } else {
    throw new Error(
      `The HTTP ${req.method} method is not supported at this route.`
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Using Serverless will help us save money, since Serveless only bills you for the number of requests, not the server uptime. Most of our audience were in Korea, so at night there was barely any traffic. Compared to a normal server, Serverless is also fully managed so you don't have to configure the infrastructure - Serverless scales up and down by itself, so you can forget about trying to guess the capacity of your server and allocate enough CPU/Memory/etc. for it.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgb15eba1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting to the database
&lt;/h2&gt;

&lt;p&gt;The default solution when it comes to MongoDB and NodeJS is using mongoose, but we believe there's a better choice - Prisma.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZzLAUl0J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zs87bzjnl3nxjnpupqrp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZzLAUl0J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zs87bzjnl3nxjnpupqrp.png" alt="Prisma logo" width="800" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Prisma is a next-generation Node.js and TypeScript ORM. While originally made for SQL, it supports MongoDB. The main difference is that Prisma has a custom syntax for schema and a separate file for them - schema.prisma. It has type-safety by default and a rich query builder as well. Functionality is similar to Mongoose; the only difference is that Prisma has Relation filters, while Mongoose doesn't have a dedicated API for it. This means that dealing with relations in Prisma is pretty simple, while you'll have to think of complicated queries in Mongoose. It's one of the most powerful features of Prisma since searching by relations is a must if you have complex data.&lt;/p&gt;

&lt;p&gt;For something like finding the user by address, a Prisma query is as simple is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const user = await prisma.user.findUnique({
  where: {
    address: req.query.address as string
  }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a id="org168cee7"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Smart contracts
&lt;/h2&gt;

&lt;p&gt;We developed a cascade of smart contracts:&lt;/p&gt;

&lt;h3&gt;
  
  
  Token:
&lt;/h3&gt;

&lt;p&gt;Customized ERC20 token with specific minting logic (used for vesting, exchange listings, and liquidity distribution, according to the project’s whitepaper) and Ownable feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Public Sale:
&lt;/h3&gt;

&lt;p&gt;Original contract with whitelist providing users the opportunity to buy a preset supply of tokens at preset prices. Users were divided into two groups based on their presence in the whitelist, which was implemented on-chain using Merke Tree.&lt;/p&gt;

&lt;h3&gt;
  
  
  NFT holders’ claim:
&lt;/h3&gt;

&lt;p&gt;The original smart contract implements the logic for NFT holders to be able to claim their NFTs and receive tokens. It was connected to the two already existing NFT collections and distributed tokens depending on NFT item rarity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Staking:
&lt;/h3&gt;

&lt;p&gt;Gives token and NFT holders an opportunity to stake (lock assets for a set period of time) their tokens and NFTs in 3 ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;bare tokens stake&lt;/strong&gt; - people just stake tokens and receive rewards based on their amount&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;single NFT stake&lt;/strong&gt; - users can stake tokens together with an NFT item from a single collection and receive increased rewards based on the rarity of their tokens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pair NFT staking&lt;/strong&gt; - holders can stake their tokens together with paired NFT items from different collections and receive raised rewards based on the degree of how their NFT items’ match each other and their own rarity&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Vesting:
&lt;/h3&gt;

&lt;p&gt;Original contract storing minted tokens and insuring them being distributed at specific timestamps and only to the prespecified contracts. Controls the token distribution and makes it transparent.&lt;/p&gt;

&lt;p&gt;Smart Contracts were written in &lt;em&gt;Solidity&lt;/em&gt; using &lt;em&gt;OpenZeppelin&lt;/em&gt; libraries and were deployed, verified and tested both on testnet and mainnet using Truffle Framework. Both unit and integration tests were written in Typescript and Javascript.&lt;/p&gt;




&lt;p&gt;That's it, let us know if you have any questions or suggestion for how we could improve the architecture.&lt;br&gt;
&lt;em&gt;Need web3 help? Feel free to &lt;a href="https://www.miki.digital/contact"&gt;contact us at our website&lt;/a&gt; or &lt;a href="https://calendly.com/miki-digital/15min"&gt;book a call&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>web3</category>
      <category>smartcontract</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Crafting the perfect token launchpad</title>
      <dc:creator>Mikhail Kedzel</dc:creator>
      <pubDate>Thu, 27 Jul 2023 09:44:42 +0000</pubDate>
      <link>https://dev.to/miki-digital/crafting-the-perfect-nft-launchpad-1jf1</link>
      <guid>https://dev.to/miki-digital/crafting-the-perfect-nft-launchpad-1jf1</guid>
      <description>&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Our client
&lt;/li&gt;
&lt;li&gt; Project description
&lt;/li&gt;
&lt;li&gt; The result
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a id="orge84dde2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Our client
&lt;/h2&gt;

&lt;p&gt;A startup wanting to launch a token came to us, after not having any success with the last technical team. The go-to-market date was close, so we had to fit tight deadlines, while still adhering to our strict standards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--53za6LJt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kp79l7c7qhyjq4t6e0gp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--53za6LJt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kp79l7c7qhyjq4t6e0gp.jpg" alt="Website picture" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id="org856b835"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project description 💻
&lt;/h2&gt;

&lt;p&gt;We had almost no time, but still had to build a scalable, blazing-fast and secure token launchpad. We picked the perfect toolset to allow for fast but error-free development like &lt;strong&gt;TypeScript&lt;/strong&gt; - a typed language for web development and &lt;strong&gt;Solidity&lt;/strong&gt; - the industry standard for writing smart contracts on Ethereum blockchain. To save the client money we also leveraged &lt;strong&gt;Serverless&lt;/strong&gt; - a cloud computing concept when you only pay for the number of invocations, not the server runtime. Since most of our users were in Korea, using Serverless helped us &lt;strong&gt;save about 80% on backend infrastructure costs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From day one we've been able to churn out features fast thanks to our world-class developers and smart technology choices. This allowed us to build a fault-tolerant and a cost-effiecient app. We wisely chosen our deployment provider - &lt;strong&gt;Vercel&lt;/strong&gt;, a leading cloud provider which built in analytics and speed insights. Which allowed us to monitor our website and backend performance in close to real time.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Frontend analytics&lt;/em&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g8OBTZho--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sheqgaribjpdoln6iirj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g8OBTZho--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sheqgaribjpdoln6iirj.png" alt="Frontend analytics" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Frontend speed insights&lt;/em&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7_HjwA_s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sm59hio9xf90k81viag2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7_HjwA_s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sm59hio9xf90k81viag2.png" alt="Frontend speed insights" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Due to our extensive expertise with auditing smart contracts, we wrote truly secure Solidity code, which was approved by Certik - leading security-focused ranking platform to analyze and monitor blockchain projects.&lt;/p&gt;

&lt;p&gt;During the public sale, our team worked round the clock to answer any questions users might have and fix urgent bugs. Thankfully, during launch no bugs were identified by users, so we can call it a success 💯&lt;/p&gt;

&lt;p&gt;&lt;a id="org0bf2d80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The result 🤝
&lt;/h2&gt;

&lt;p&gt;We've enabled our clients to launch the perfect launchpad and hit all the targets. Continuing to work in close colloboration with the client, now we're developing a NFT marketplace toghether!&lt;/p&gt;




&lt;p&gt;Need web3 help? &lt;a href="https://www.miki.digital/contact"&gt;Reach out to us!&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Stay in Tact with TON</title>
      <dc:creator>Mikhail Kedzel</dc:creator>
      <pubDate>Wed, 26 Jul 2023 07:21:20 +0000</pubDate>
      <link>https://dev.to/miki-digital/stay-in-tact-with-ton-4pg3</link>
      <guid>https://dev.to/miki-digital/stay-in-tact-with-ton-4pg3</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; FunC development is not fun at all!!
&lt;/li&gt;
&lt;li&gt; Tact - the savior of all FunC developers
&lt;/li&gt;
&lt;li&gt; Awesome tools for Tact development
&lt;/li&gt;
&lt;li&gt; Getting to the code
&lt;/li&gt;
&lt;li&gt; Special thanks
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a id="org4eda193"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article is a script of a talk we gave at TON Korea meetup telling the community about the newest tools for development on &lt;a href="https://ton.org/"&gt;TON&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, what's so special about TON compared to other blockchains? There are a couple of cool features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Easy integration with Telegram&lt;/li&gt;
&lt;li&gt;  Everything on-chain is a smart contract(even accounts and wallets)&lt;/li&gt;
&lt;li&gt;  Calls between contracts are asynchronous&lt;/li&gt;
&lt;li&gt;  Contract sharding is the main consensus&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These provides infinite scaling, predictable gas prices and cheap execution. But my personal favorite is that &lt;strong&gt;there is no need for a proxy, you can make your contracts mutable to fix mistakes and easily update them&lt;/strong&gt;. However, there's on big problem with TON.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgfd121a9"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://docs.ton.org/develop/func/overview"&gt;FunC&lt;/a&gt; development is not fun at all!!
&lt;/h2&gt;

&lt;p&gt;FunC is a very low-level language: you need to deal with TL-B schemas, TVM opcodes, and lots of hashing algorithms and ideally understand all of them. Furthermore, it has its own variable types: Cells and slices with which you have to deal regularly. Then it has the authentic syntax: functions and methods declaration vary significantly from the ones we are used to see, there are lots of syntax sugars. And my personal pain is the fact that there is only one method to deal with all the incoming messages.&lt;/p&gt;

&lt;p&gt;That makes contracts very messy. All this sets a very high entry threshold for devs. But recently a way to loosen the burden appeared.&lt;/p&gt;

&lt;p&gt;&lt;a id="org11b9121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://tact-lang.org/"&gt;Tact&lt;/a&gt; - the savior of all FunC developers
&lt;/h2&gt;

&lt;p&gt;A team of devs from TonWhales, Tonkeeper and Ton core teams created a new programming language: Tact. The first version was released in March and is regularly updated. TACT is expected to become the main language for TON smart contract development The main features are these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  it introduces Object-oriented programming elements giving the opportunity to recycle code structures&lt;/li&gt;
&lt;li&gt;  resembles Kotlin, Rust, Typescript, and Solidity in a way&lt;/li&gt;
&lt;li&gt;  has built-in methods like initializer&lt;/li&gt;
&lt;li&gt;  you don't have to deal with cells and slices&lt;/li&gt;
&lt;li&gt;  has ABI support, so you don’t need to use the client to access smart contracts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;TACT is all about real necessities for devs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id="org8085ddc"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Awesome tools for Tact development
&lt;/h2&gt;

&lt;p&gt;I use it toghether with the &lt;a href="https://github.com/ton-org/blueprint"&gt;blueprint framework&lt;/a&gt;, which provides easy creation, compilation, and deployment for smart contracts. The blueprint framework has a testing suite - &lt;a href="https://github.com/ton-org/sandbox"&gt;Sandbox&lt;/a&gt;, which makes testing comfortable and smooth. Another cool tool is &lt;a href="https://github.com/ton-connect"&gt;Ton connect&lt;/a&gt; which supports wallets like Tonkeeper, OpenMask, TonHub, etc., and makes payment processing a piece of cake.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgf982e4b"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting to the code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://youtu.be/TqX8qgwoDl8"&gt;&lt;em&gt;We also recorded a video walkthrough of the code&lt;/em&gt;&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To quickly get started let's use the blueprint framework, it'll scaffold the project with npm.&lt;br&gt;
&lt;code&gt;npm create ton@latest&lt;/code&gt;&lt;br&gt;
After this command it'll prompt you to specify your project name, first contract name, and a template - choose "An empty contract (TACT)" here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---Pmq4IWA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ww2lq2byc2mour5jm6l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---Pmq4IWA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ww2lq2byc2mour5jm6l.png" alt="Command line screenshot" width="398" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the project directory, under &lt;code&gt;contracts/imports&lt;/code&gt; is our first smart contract - &lt;code&gt;balance.tact&lt;/code&gt;. Let's write some code now&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "@stdlib/deploy";
import "@stdlib/ownable";

message Withdraw{
    amount : Int as coins;
}

contract Balance with Deployable, Ownable {

    balance: Int as uint256 = 0;
    owner: Address;

    init() {
        // sender() is a built-in function which reads the sender of the message
        self.owner = sender();
    }

    // Deposit TON to our smart contract
    receive("Deposit"){
        // context() returns data of the incoming message: sender, value, type(bounced, not bounced) and its raw representation
        self.balance = self.balance + context().value;
    }

    receive(msg: Withdraw){
        // A built-in method to check that the message is sent by the owner of the contract
        self.requireOwner();
        require(msg.amount &amp;lt; self.balance , "Too much!");
        self.balance = self.balance - msg.amount;
        send(SendParameters{
            to: sender(),
            value: msg.amount,
            mode: SendIgnoreErrors,
            body: "Get your tokens!".asComment()
        });
    }

    get fun balance(): Int{
        return self.balance;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Build your smart contract with this command &lt;code&gt;npx blueprint build&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;You should see a couple of files appear under &lt;code&gt;build/Balance&lt;/code&gt; directory. &lt;strong&gt;The most interesting being the compiled FunC code&lt;/strong&gt; - &lt;code&gt;tact_Balance.code.fc&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Looking at it further, you might noticed that it's not that Gas efficient. In other words, if you were to write the same thing in FunC you'd probably save 20% on gas costs, but because Gas is so cheap on TON, it's not an issue.&lt;/p&gt;

&lt;p&gt;Also, Tact plans to compile code straight to &lt;a href="https://docs.ton.org/develop/fift/overview"&gt;fift&lt;/a&gt; - an exteremely low-level langauge for the TON Virtual Machine and TON Blockchain. This might lead to Tact being on par, if not more gas-efficient than FunC. &lt;strong&gt;Exciting times are ahead for Tact&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id="orgbb2496b"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Special thanks
&lt;/h2&gt;

&lt;p&gt;Thanks to the lead Blockchain Developer at MiKi Digital - &lt;a href="https://www.linkedin.com/in/vladislav-lenskii-393697237/"&gt;Vladislav Lenskiy&lt;/a&gt; for preparing this awesome talk.&lt;br&gt;
Thanks to &lt;a href="https://www.linkedin.com/in/hyunjoo-kang/"&gt;Lucy Kang&lt;/a&gt; for hosting the event, and helping drive the adoption of TON in Korea.&lt;br&gt;
And a very warm thank you to the team behind Tact language - Steve Korshakov, Tal Kol, Oleg Andreev, Kirill Emelyanenko, Kirill Maev, and others from Tonkeeper, TON Whales, TON core, etc.&lt;/p&gt;

&lt;p&gt;P.S. If you need any web3 help feel free to &lt;a href="https://www.miki.digital/contact"&gt;reach out to us at at our website&lt;/a&gt; or &lt;a href="https://calendly.com/miki-digital/15min"&gt;book a call&lt;/a&gt;&lt;/p&gt;

</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>cryptocurrency</category>
      <category>programming</category>
    </item>
    <item>
      <title>Working with smart contract on the Frontend</title>
      <dc:creator>Mikhail Kedzel</dc:creator>
      <pubDate>Tue, 04 Jul 2023 09:00:00 +0000</pubDate>
      <link>https://dev.to/miki-digital/working-with-smart-contract-on-the-frontend-3mem</link>
      <guid>https://dev.to/miki-digital/working-with-smart-contract-on-the-frontend-3mem</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Working with smart conrtacts on the Frontend
&lt;/li&gt;
&lt;li&gt; Connecting to a wallet
&lt;/li&gt;
&lt;li&gt; Better UX for mobile users
&lt;/li&gt;
&lt;li&gt; Connecting to the smart contract
&lt;/li&gt;
&lt;li&gt; Exporting all the logic into a hook
&lt;/li&gt;
&lt;li&gt; Caveats
&lt;/li&gt;
&lt;li&gt; Thank you for reading
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a id="org1bbf0bf"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with smart conrtacts on the Frontend
&lt;/h2&gt;

&lt;p&gt;Hello fellow web3 enthusiasts, in this article, we'll explore how to integrate smart contracts on the frontend using &lt;code&gt;ethers&lt;/code&gt; &lt;a href="https://docs.ethers.org/v6/"&gt;a library for interacting with Ethereum and its ecosystem&lt;/a&gt;. Its often used to connect your decentralized app(dapp) to MetaMask wallet, and interact with Smart Contracts on Ethereum blockchain.&lt;/p&gt;

&lt;p&gt;&lt;a id="orga2c5443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting to a wallet
&lt;/h2&gt;

&lt;p&gt;ethers provides an extremely simple API to connect to a wallet&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (window.ethereum) {
  const accounts = await window.ethereum.request({
    method: "eth_requestAccounts",
  });
  const account = accounts[0];

  setIsWalletConnected(true);
  setCurrentAccount(account);

  console.log("Connected Wallet:", account);
} else {
  alert("Connect your Ethereum Wallet");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are using TypeScript you'll get an error that property &lt;code&gt;ethereum&lt;/code&gt; doesn't exist on &lt;code&gt;window&lt;/code&gt;. To fix it create a &lt;code&gt;react-app-env.d.ts&lt;/code&gt; in your root directory and paste the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*/* &amp;lt;reference types="react-scripts" /&amp;gt;

interface Window {
    ethereum: any
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only caveat is that it won't work on mobile browsers, since there's no way to install the &lt;a href="https://metamask.io/"&gt;Metamask extension&lt;/a&gt; on there. You'll need to use the browser inside metamask app on mobile. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ymVkYm3c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kn3yhub791y80addh4x2.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ymVkYm3c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kn3yhub791y80addh4x2.jpeg" alt="Metamask in app browser" width="800" height="1565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id="orgf2ca362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Better UX for mobile users
&lt;/h2&gt;

&lt;p&gt;Some mobile users might be confused if they'll open your open outside metamask. Thankfully, MetaMask has a &lt;a href="https://metamask.github.io/metamask-deeplinks/"&gt;deeplink generator&lt;/a&gt; which you can use to redirect mobile users to the app. Before the user open a page which requires MetaMask, you can check whether he's on mobile and redirect him if needed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href={\`${
        !window.ethereum ? `https://metamask.app.link/dapp/${process.env.NEXT_PUBLIC_APP_URL}\` : ''
}pagesWith/metamask\`}&amp;gt;Go to page&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="org8efa526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting to the smart contract
&lt;/h2&gt;

&lt;p&gt;You'll need your smart contract's ABI stored somewhere on the FE, along with the contract address and the amount you want to send.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { BrowserProvider, Contract, parseEther } from 'ethers';

const provider = new BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const smartContract = new Contract(
  contractAddress,
  contractABI,
  signer
);

if (isWalletConnected) {
  const valueToSend = parseEther(amount); */ Value to send in Ether
  const methodName = 'publicSale'; /* Replace with your payable method name

  const transaction = await smartContract.connect(signer)[methodName]({
  value: valueToSend
});

  const receipt = await transaction.wait();
  console.log('Transaction hash:', transaction.hash);
  console.log(receipt);
  return transaction;
} else {
  alert("Connect your wallet first to request PAC tokens.");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code also checks if your wallet is connected first, before making the transaction. One of the cool features is ethers picks up the chain you are using automatically, so there's no need for additional config.&lt;/p&gt;

&lt;p&gt;&lt;a id="org0d154c2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Exporting all the logic into a hook
&lt;/h2&gt;

&lt;p&gt;Now, let's make our code a bit more suitable for React. All those separate functions are great, but using them in a React component can be a hassle. So let's encalpsulate everything into a hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
    useEffect,
    useState
} from "react";
import {
    abi
} from '@/mock/abi';
import {
    BrowserProvider,
    Contract,
    parseEther
} from 'ethers';

export default function useMetamaskSdk() {
    const [isWalletConnected, setIsWalletConnected] = useState(false);
    const [currentAccount, setCurrentAccount] = useState(null);

    const contractAddress: string = process.env.NEXT_PUBLIC_CONTRACT_ADDRESS // It 's better to store sensetive data like that in .env
    const contractABI = abi.abi; // Your abi, make sure to point to the Abi object itself.

    const checkIfWalletIsConnected = async () =&amp;gt; {
        try {
            if (window.ethereum) {
                const accounts = await window.ethereum.request({
                    method: "eth&amp;lt;sub&amp;gt;requestAccounts&amp;lt;/sub&amp;gt;",
                });
                const account = accounts[0];

                setIsWalletConnected(true);
                setCurrentAccount(account);

                console.log("Connected Wallet:", account);
            } else {
                alert("Connect your Ethereum Wallet");
            }
        } catch (error) {
            console.log(error);
        }
    };

    // Amount - Ether value e.g 0.003
    const requestToken = async (amount: string) =&amp;gt; {
        try {
            const provider = new BrowserProvider(window.ethereum);
            const signer = await provider.getSigner();
            const smartContract = new Contract(
                contractAddress,
                contractABI,
                signer
            );

            if (isWalletConnected) {
                const valueToSend = parseEther(amount);*/
                Value to send in Ether
                const methodName = 'publicSale'; // Replace with your payable method name

                const transaction = await smartContract.connect(signer).[methodName]({
                    value: valueToSend
                });

                const receipt = await transaction.wait();
                console.log('Transaction hash:', transaction.hash);
                console.log(receipt);
                return transaction;
            } else {
                alert("Connect your wallet first to request PAC tokens.");
            }
        } catch (error) {
            console.log(error);
        }
    };

    // Connecting the wallet on the first render
    useEffect(() =&amp;gt; {
        checkIfWalletIsConnected();
    }, []);

    return {
        requestToken,
        checkIfWalletIsConnected,
        isWalletConnected,
        currentAccount
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="org64adb7e"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;There's a couple of downsides to using ethers instead of &lt;a href="https://docs.moralis.io/"&gt;Moralis&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Mobile experience suffers a bit, since users have to go through MetaMask browser instead of their preferred one. With Moralis, you can &lt;a href="https://docs.moralis.io/authentication-api/evm/how-to-sign-in-with-walletconnect"&gt;use WalletConnect&lt;/a&gt; which recently started supporting MetaMask, so you can do it all in your browser.&lt;/li&gt;
&lt;li&gt;  Poor wallet support. When using WalletConnect instead of ethers, you have a much wider choice of wallets. Even thought MetaMask is used by 80-90% of users, you can grow your user base by offering more wallet options.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moralis isn't the silver bullet as well, since compared to ethers its API isn't that powerful. So you need to weigh the upsides and downsides of both. We'll cover using Moralis in our next article, so you could compare it with ethers and decide easily.  &lt;/p&gt;

&lt;p&gt;&lt;a id="org14c2822"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Thank you for reading
&lt;/h2&gt;

&lt;p&gt;If you have any questions or suggestions, feel free to leave them in the comments!&lt;/p&gt;




&lt;p&gt;At MiKi we help businesses make stunning websites with a blazing-fast and cost-efficient cloud backend.&lt;br&gt;
Interested?&lt;br&gt;
Feel free to give us a call at +447588739366, book a meeting at &lt;a href="https://lnkd.in/gGmfJu8z"&gt;https://lnkd.in/gGmfJu8z&lt;/a&gt; or feel out the contact form at our website &lt;a href="https://www.miki.digital/contact"&gt;https://www.miki.digital/contact&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>4 Lessons learned from using NextJS 13 in production</title>
      <dc:creator>Mikhail Kedzel</dc:creator>
      <pubDate>Thu, 29 Jun 2023 16:33:08 +0000</pubDate>
      <link>https://dev.to/miki-digital/4-lessons-learned-from-using-nextjs-13-in-production-4ff6</link>
      <guid>https://dev.to/miki-digital/4-lessons-learned-from-using-nextjs-13-in-production-4ff6</guid>
      <description>&lt;p&gt;We’ve recently rebuilt our website with &lt;a href="https://beta.nextjs.org/docs/routing/fundamentals"&gt;NextJS V13 app directory&lt;/a&gt;, and what a journey it was! As app directory is(at the time of writing this article) in beta, it wasn’t all smooth sailing, but once we got the hang of it - our website speed improved by quite a lot. To help other developers starting with NextJS 13, we’ve compiled a list of 10 of the most important lessons we learned. You can use those as mental guidelines for writing performance NextJS 13 code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read all the available documentation before writing any code.
&lt;/h2&gt;

&lt;p&gt;Often when we see a cool new feature, we want to build something with it right away, hoping to learn it in the process. If the deadlines are tight, it seems even more viable.&lt;/p&gt;

&lt;p&gt;But NextJS 13 introduces many new concepts, which are pretty high-level, so the biggest recommendation is to read ALL of the available documentation before writing any code. And then reread this documentation as needed. Here are some of our favorite sources(in the order that we’d recommend reading them)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html"&gt;React documentation on Server Components(used be NextJS 13 under the hood)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/potetotes/status/1341141198258524163"&gt;Difference between SSR and React Server Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/sophiebits/status/1341098388062756867"&gt;Main takeaways of React Server Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://beta.nextjs.org/docs/getting-started"&gt;NextJS Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://news.ycombinator.com/item?id=25497065"&gt;HackerNews&lt;/a&gt;(Dan Abramov answered some of the comments!)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Minimize the amount of client components
&lt;/h2&gt;

&lt;p&gt;In general, less client components - more performance. Before creating a new page, we suggest making a high-level overview of what that page will look like.&lt;/p&gt;

&lt;p&gt;For example, you want to build a simple “Contact Us” form with a react-hook-form and some Captcha library. The Captcha library's provider component requires you to write ‘use client’. The simplest way of creating that page would be &lt;/p&gt;

&lt;p&gt;&lt;em&gt;page.tsx&lt;/em&gt;&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&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="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="nc"&gt;CaptchaProvider&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="nc"&gt;SomeStaticContent&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;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        ...react-hook-form
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&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="nc"&gt;CaptchaProvider&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting ‘use client’ for the whole page is a bad practice. But even if our &lt;code&gt;&amp;lt;CaptchaProvider/&amp;gt;&lt;/code&gt; is a &lt;strong&gt;Client Component&lt;/strong&gt;, &lt;a href="https://beta.nextjs.org/docs/rendering/server-and-client-components#importing-server-components-into-client-components"&gt;you can pass a &lt;strong&gt;Server Component&lt;/strong&gt; as a child or prop of a &lt;strong&gt;Client Component&lt;/strong&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;From React docs&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Server Component &lt;em&gt;may&lt;/em&gt; pass another Server Component as a child to a Client Component: &lt;code&gt;&amp;lt;ClientTabBar&amp;gt;&amp;lt;ServerTabContent /&amp;gt;&amp;lt;/ClientTabBar&amp;gt;&lt;/code&gt;. From the Client Component’s perspective, its child will be an already rendered tree, such as the &lt;code&gt;ServerTabContent&lt;/code&gt; output. This means that Server and Client components can be nested and interleaved in the tree at any level.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means only &lt;code&gt;&amp;lt;CaptchaProvider/&amp;gt;&lt;/code&gt; needs to be a Client component. As per NextJS docs, we can wrap our provider in our own client component&lt;/p&gt;

&lt;p&gt;&lt;em&gt;customCaptchaProvider.tsx&lt;/em&gt;&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&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;CaptchaProvider&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;captcha-library&lt;/span&gt;&lt;span class="dl"&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;CaptchaProvider&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can remove the ‘use client’ from page.tsx&lt;/p&gt;

&lt;p&gt;&lt;em&gt;page.tsx&lt;/em&gt;&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OurCaptchaProvider&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;./customCaptchaProvider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&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="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="nc"&gt;OurCaptchaProvider&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="nc"&gt;SomeStaticContent&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;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        ...react-hook-form
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&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="nc"&gt;OurCaptchaProvider&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, react-hook-form relies on &lt;code&gt;useRef&lt;/code&gt; under the hood, which can’t be used in a Server Component. We can extract the form into a separate client component&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ContactUsForm.tsx&lt;/em&gt;&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ContactUs&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      ...react-hook-form
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;page.tsx&lt;/em&gt;&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OurCaptchaProvider&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;./CustomCaptchaProvider&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;ContactUs&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;./ContactUsForm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&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="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="nc"&gt;OurCaptchaProvider&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="nc"&gt;SomeStaticContent&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="nc"&gt;ContactUs&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="nc"&gt;OurCaptchaProvider&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;&amp;lt;SomeStaticContent&amp;gt;&lt;/code&gt; is a small component, the difference won’t be that big, but the larger it gets, the more noticeable the difference will become. As a rule of thumb, you should try to make every component a Server Component first and resort to Client Components if you can’t.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get comfortable with SWR or React Query for fetching on the client
&lt;/h2&gt;

&lt;p&gt;Client components don’t support &lt;code&gt;fetch()&lt;/code&gt; yet, so you’ll have to use either &lt;a href="https://swr.vercel.app/"&gt;SWR&lt;/a&gt; or &lt;a href="https://react-query-v3.tanstack.com/"&gt;React Query&lt;/a&gt; for fetching data in Client Components. If you aren’t very familiar with those libraries, we’d recommend trying them out in a regular React project first to get comfortable with the fundamentals and choose the library that works for you. For MiKi website, we went with &lt;a href="https://swr.vercel.app/"&gt;SWR&lt;/a&gt;, and it was a pretty smooth experience, so this might be a good starting point.&lt;/p&gt;

&lt;p&gt;In Server Components, you can use &lt;code&gt;fetch()&lt;/code&gt; without any issues since Server Components support &lt;a href="https://github.com/acdlite/rfcs/blob/first-class-promises/text/0000-first-class-support-for-promises.md"&gt;async/await right inside the component&lt;/a&gt;. As a general rule, NextJS recommends fetching data in Server Components as much as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Change your “stance” against npm packages
&lt;/h2&gt;

&lt;p&gt;Using npm packages greatly improves the development speed. But remember the time when before installing some library, you had to check &lt;a href="https://bundlephobia.com/"&gt;https://bundlephobia.com/&lt;/a&gt; to see how it would affect bundle size and page load time? So many developers became against the excessive use of npm packages, as it can make your bundle size bigger, leading to slower compile and load times.&lt;/p&gt;

&lt;p&gt;Since Server Components are run only on the server, they don’t impact bundle size. With this in mind, you should be more open to using npm packages - this will save time and bring us to a more modular future where the functionality you need to be may already exist in npm. Even if the library weighs a lot, you can use it in Server Components without negatively affecting the bundle size. &lt;/p&gt;

&lt;p&gt;However, you have to remember that this is only true for Server Components, using a big library in a Client Component will still negatively affect your bundle size. As we advised earlier - try to make as few Client Components as possible. &lt;/p&gt;

&lt;h2&gt;
  
  
  Thank you for reading
&lt;/h2&gt;

&lt;p&gt;Those were the four most important tips we wanted to share. Hope they’ll make you a better NextJS 13 developer. If you have any questions or suggestions, feel free to leave them in the comments.&lt;/p&gt;




&lt;p&gt;At MiKi we help businesses make stunning websites with a blazing-fast and cost-efficient cloud backend.&lt;br&gt;
Interested?&lt;br&gt;
Feel free to give us a call at +447588739366, book a meeting at &lt;a href="https://lnkd.in/gGmfJu8z"&gt;https://lnkd.in/gGmfJu8z&lt;/a&gt; or feel out the contact form at our website &lt;a href="https://www.miki.digital/contact"&gt;https://www.miki.digital/contact&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Creating a useState hook from scratch</title>
      <dc:creator>Mikhail Kedzel</dc:creator>
      <pubDate>Thu, 22 Jun 2023 12:00:00 +0000</pubDate>
      <link>https://dev.to/miki-digital/creating-a-usestate-hook-from-scratch-b39</link>
      <guid>https://dev.to/miki-digital/creating-a-usestate-hook-from-scratch-b39</guid>
      <description>&lt;p&gt;In this article, we’ll create the most barebones version of the useState hook. If you want to understand how React hooks work in depth, how they use closures, and why can’t you nest hooks in &lt;code&gt;if&lt;/code&gt; blocks - read ahead!&lt;/p&gt;

&lt;p&gt;First of all, you probably know that React doesn’t need JSX, and in the end, it transforms everything to &lt;code&gt;React.createElement(component, props, ...children)&lt;/code&gt; . You can read more about it in the official docs &lt;a href="https://reactjs.org/docs/react-without-jsx.html" rel="noopener noreferrer"&gt;https://reactjs.org/docs/react-without-jsx.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this in mind, to not overcomplicate ourselves, let’s create just a .ts file called index.ts. Then, we can add our simple custom component without any JSX.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Count is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&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;setCount&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;To emulate rendering and re-rendering, we’ll do the same thing that React does  - just call the function. Then we’ll get our count and log it to see what’s there.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Count is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&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;setCount&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;Rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;App&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;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Oh, right, &lt;code&gt;useState&lt;/code&gt; is not defined… Let’s create it!&lt;/p&gt;

&lt;p&gt;We need our function to accept &lt;code&gt;initialState&lt;/code&gt; and return an array of two items - state and a function to modify it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;undefined&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newState&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;Let’s run our code again&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8p2rrcyqn3zk477s8r19.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8p2rrcyqn3zk477s8r19.png" alt="console output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’re getting somewhere :). But let’s try to change our state&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;Rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;App&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;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;Rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;//re-render after state change&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;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmh0a88zvg8az6k3qpd55.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmh0a88zvg8az6k3qpd55.png" alt="Console output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same thing. That’s because our useState function gets re-created on every re-render &lt;/p&gt;

&lt;p&gt;We can use closures to our advantage here and lift the state up to be a global variable not to get re-created on every re-render.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;let&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;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* We want to check if state is undefined, i.e. it's the first render
     before assigning initialState to it.
  */&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialState&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newState&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;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F436038ojko177zng24zp.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F436038ojko177zng24zp.png" alt="console output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Much better, but how do we go about creating two states? Three states?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John&lt;/span&gt;&lt;span class="dl"&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="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Count is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&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;setCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Name is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&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;setName&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;Rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;App&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;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;Rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//re-render after state change&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;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1htav7y73nt8h8ded0dt.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1htav7y73nt8h8ded0dt.png" alt="console ouput"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since we only have one global state variable, our two &lt;code&gt;useStates&lt;/code&gt; have to share it, which leads to incorrect behavior.&lt;/p&gt;

&lt;p&gt;The way React implements it - is by having a state array and a pointer to know which useState we are currently on. After the useState function is fired, it increments this pointer so that the next useState function will work with its state, and so on. After a re-render, since our App() and all the useState functions are called again, we need to set this pointer to 0. Can you already guess why nesting a useState in an if statement is bad?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;let&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;any&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Freeze the index, to make the 'setters'(setCount/setName) work&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;index&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="k"&gt;typeof&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;localIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;localIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;localIndex&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&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;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;localIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John&lt;/span&gt;&lt;span class="dl"&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="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Count is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&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;setCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Name is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&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;setName&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;Rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;App&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;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//Set the index to 0&lt;/span&gt;
&lt;span class="nx"&gt;Rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//re-render after state change&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;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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;Rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;One more trick we are doing here is “freezing” the index. Otherwise, when we get to the “name” useState, it’ll increment the index to 1, and setCount will end up changing the name instead of count. Because name has an index of 1 and count has an index of 0&lt;/p&gt;

&lt;p&gt;Let’s see where it got us!&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tbxb416401vzfq610sa.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tbxb416401vzfq610sa.png" alt="console output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Works perfectly!&lt;/p&gt;

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

&lt;p&gt;Of course, having built this we are still far of from becoming a React maintainer at Facebook :) But the best way to learn something is by doing it. So here are a couple of ways you can improve this on your own&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of manually setting index to 0 before calling our function every time, encapsulate this into a render method which’d do both.&lt;/li&gt;
&lt;li&gt;Store your custom React in an IIFE &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/IIFE" rel="noopener noreferrer"&gt;&lt;/a&gt;instead of globally in our index.ts file, just like React does it &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/IIFE" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Glossary/IIFE&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Implement useEffect&lt;/li&gt;
&lt;li&gt;Use your imagination and implement more stuff!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was inspired by two great talks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=KJP1E-Y-xyo" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=KJP1E-Y-xyo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=f2mMOiCSj5c" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=f2mMOiCSj5c&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;




&lt;p&gt;At MiKi(&lt;a href="https://miki.digital/" rel="noopener noreferrer"&gt;https://miki.digital/&lt;/a&gt;) we help businesses make stunning websites with a blazing-fast and cost-efficient cloud backend.&lt;br&gt;
Interested?&lt;br&gt;
Feel free to give us a call at +447588739366, book a meeting at &lt;a href="https://calendly.com/miki-digital/30-minute-consultation" rel="noopener noreferrer"&gt;https://calendly.com/miki-digital/30-minute-consultation&lt;/a&gt; or feel out the contact form at our website &lt;a href="https://www.miki.digital/contact" rel="noopener noreferrer"&gt;https://www.miki.digital/contact&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Reducing Lambda bundle size with EsBuild and Lambda layers</title>
      <dc:creator>Mikhail Kedzel</dc:creator>
      <pubDate>Fri, 16 Jun 2023 12:43:42 +0000</pubDate>
      <link>https://dev.to/miki-digital/reducing-lambda-bundle-size-with-esbuild-and-lambda-layers-3l02</link>
      <guid>https://dev.to/miki-digital/reducing-lambda-bundle-size-with-esbuild-and-lambda-layers-3l02</guid>
      <description>&lt;p&gt;&lt;strong&gt;Serverless&lt;/strong&gt; is becoming increasingly popular as it lifts the burden of having to manage your servers and is more economical than cloud containers or on-premise servers. Popular BE frameworks like NestJS allow you to switch from containerized to lambda quite easily. &lt;a href="https://docs.nestjs.com/faq/serverless" rel="noopener noreferrer"&gt;https://docs.nestjs.com/faq/serverless&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;While by just transforming your monolithic backend into one lambda, you’d already see the benefits like easier management, less cost, and, maybe, improved performance. But the performance aspect is the most difficult, as having one “fat” lambda with a huge bundle size will lead to slow cold start times. Since during cold starts, Lambda downloads all your code, and the bigger your bundle is - the longer it’ll take to download.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore the approaches we use at &lt;a href="https://miki.digital/" rel="noopener noreferrer"&gt;MiKi&lt;/a&gt;  to optimize that using Lambda layers, EsBuild, and smarter BE framework choices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing the right framework
&lt;/h3&gt;

&lt;p&gt;First, let’s see how much overhead a modern fully-fledged framework adds. Let’s say we want to build an AppSync Api with a lambda behind it, along with some basic authorization. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;I’ve left out quite a few dependencies; only included the core ones, to make the comparison easier.&lt;/em&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fab72iieyw801ejehr7ti.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fab72iieyw801ejehr7ti.png" alt="bundlephobia"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But do we need all those dependencies, or can we write something from scratch using mostly what NodeJS gives us? Instead of NestJS’s dependency injection, we can use tools like &lt;a href="https://www.npmjs.com/package/tsyringe" rel="noopener noreferrer"&gt;tsyringe&lt;/a&gt; or &lt;a href="https://www.npmjs.com/package/typedi" rel="noopener noreferrer"&gt;typedi&lt;/a&gt;, etc. We can recreate the graphql annotations that NestJS gives us with &lt;a href="https://typegraphql.com/" rel="noopener noreferrer"&gt;type-graphql&lt;/a&gt;. And like in the NestJS example, we’ll also need graphql and typeorm.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I’ve left out quite a few dependencies; only included the core ones, to make the comparison easier.&lt;/em&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2p15b071tkvmbzq2p4yy.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2p15b071tkvmbzq2p4yy.png" alt="bundlephobia without NestJS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Already, it’s three times smaller than before, but we can do better&lt;/p&gt;

&lt;h3&gt;
  
  
  Splitting into multiple smaller lambdas
&lt;/h3&gt;

&lt;p&gt;We’ll need to do some re-architecting to decouple our code and make many small, independent lambdas. This will reduce the bundle size even further, since every lambda will only import the dependencies it needs. For example, auth dependencies can only be imported by your auth lambda. Or, if you have a number of big libraries for some specific functionality, you can extract this into a separate lambda, to reduce the bundle size of other lambdas.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note that I’m not talking about microservice architecture here because all our lambdas can still use the same database.&lt;/em&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Making our bundling speed extremely fast
&lt;/h3&gt;

&lt;p&gt;NestJS uses webpack under the hood, which might be one of the slowest bundlers. Since we got rid of NestJS, we can choose a more performant bundler. One of the best options is esbuild - “An extremely fast bundler for the web” (c). &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxu2i2bmuh7r32e3wo5ax.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxu2i2bmuh7r32e3wo5ax.png" alt="bundlers speed comparison"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Faster bundling will improve the performance of your CI/CD by 10-100x allowing your developers to work more productively. &lt;/p&gt;

&lt;h3&gt;
  
  
  Using Lambda layers
&lt;/h3&gt;

&lt;p&gt;Our final step on the way to the tiniest bundle you’ve ever seen is to leverage &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html" rel="noopener noreferrer"&gt;Lambda layers&lt;/a&gt;. It allows you to move your common dependencies to a “layer”, then every lambda would only bundle its unique dependencies, accessing everything else from the layer. A layer is just a zip file, where we can put our &lt;code&gt;node_modules&lt;/code&gt; and &lt;code&gt;package.json&lt;/code&gt; . Or, we can put only the package.json and create a step in our CI/CD pipeline that would install the dependencies. &lt;/p&gt;

&lt;p&gt;Due to the way &lt;a href="https://nodejs.org/api/modules.html#loading-from-node_modules-folders" rel="noopener noreferrer"&gt;node_modules resolution works&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Node.js starts at the directory of the current module, adds &lt;code&gt;/node_modules&lt;/code&gt;, and attempts to load the module from that location.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If our lambda will not find a dependency in local node_modules, it’ll go one level up and search in our layer. Let’s adjust our esbuild config to only bundle the unique dependencies.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt; &lt;span class="p"&gt;}&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;esbuild&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
&lt;span class="c1"&gt;// Needed to make decorators work&lt;/span&gt;&lt;br&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;esbuildDecorators&lt;/span&gt; &lt;span class="p"&gt;}&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;@anatine/esbuild-decorators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pkg&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;./layer/nodejs/package.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="kd"&gt;const&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;br&gt;
&lt;span class="kd"&gt;const&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;br&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;externals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{}),&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;peerDependencies&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{}),&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;];&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getEndpoints&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lambdasFolder&lt;/span&gt; &lt;span class="o"&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;join&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;./src/lambdas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&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;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lambdasFolder&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br&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;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lambdasFolder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tsconfig&lt;/span&gt; &lt;span class="o"&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;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;&lt;strong&gt;dirname&lt;/strong&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;./tsconfig.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node14&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;bundle&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;br&gt;
    &lt;span class="na"&gt;sourcemap&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;br&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;esbuildDecorators&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;tsconfig&lt;/span&gt; &lt;span class="p"&gt;})],&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;entryPoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getEndpoints&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;outdir&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;join&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;dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;br&gt;
    &lt;span class="nx"&gt;tsconfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;treeShaking&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;br&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;externals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&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;br&gt;
    &lt;span class="c1"&gt;// eslint-disable-next-line no-console&lt;/span&gt;&lt;br&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Build completed: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="nf"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="c1"&gt;// eslint-disable-next-line no-console&lt;/span&gt;&lt;br&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&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;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;});&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;I went through the same transformation in an averagely-sized commercial project, and, compared to one fat lambda, the bundle size of each of our small lambdas was on average 20 times smaller. So next time you build a project from scratch, or will want to improve the performance of an existing application, I advise you to re-evaluate the need for a fully-fledged BE framework. Since most of the time, a more minimalist approach will give you way better performance and, consequently, lesser costs.&lt;/p&gt;




&lt;p&gt;At MiKi(&lt;a href="https://miki.digital/" rel="noopener noreferrer"&gt;https://miki.digital/&lt;/a&gt;) we help businesses make stunning websites with a blazing-fast and cost-efficient cloud backend.&lt;br&gt;
Interested?&lt;br&gt;
Feel free to give us a call at +447588739366, book a meeting at &lt;a href="https://calendly.com/miki-digital/30-minute-consultation" rel="noopener noreferrer"&gt;https://calendly.com/miki-digital/30-minute-consultation&lt;/a&gt; or feel out the contact form at our website &lt;a href="https://www.miki.digital/contact" rel="noopener noreferrer"&gt;https://www.miki.digital/contact&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Atomic design</title>
      <dc:creator>Mikhail Kedzel</dc:creator>
      <pubDate>Tue, 06 Jun 2023 12:21:01 +0000</pubDate>
      <link>https://dev.to/bearrrrr/atomic-design-pa2</link>
      <guid>https://dev.to/bearrrrr/atomic-design-pa2</guid>
      <description>&lt;p&gt;At the dawn of web development, we used to have extremely simple pages, with most of the logic being on the backend. But nowadays, having a thoughtfully designed and built website is crucial to success, as among all factors for rejecting/mistrusting a website, over 94% are related to poor design. So better-looking websites help to build trust with your customers and attract more people. &lt;/p&gt;

&lt;p&gt;With the advance of development, we also started to value the separation of concerns and modularity more. So it became clear that we needed to create functionality in a reusable way. On the FE, this can be achieved with a design system. &lt;/p&gt;

&lt;p&gt;In short, the UI/UX designer creates simple, building-blocks components like inputs, alerts, buttons, etc., and then starts building pages using as many existing components as possible. The developer can also create the basic components and then build the pages like lego using the pieces(components) they already have. A good design system can be a game changer - allowing your designers and developers to create and iterate faster. &lt;/p&gt;

&lt;p&gt;“Atomic design” is an amazing design system that takes its inspiration from chemistry. Like in web design, everything can be built from simple components like inputs, text, buttons; in chemistry, everything is built from atoms. In Atomic design, there are five levels of components.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Atoms&lt;/strong&gt; - basic building blocks like buttons, text, inputs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Molecules&lt;/strong&gt; - more complex components combining multiple atoms, e.g. a search input - combines input, label text, and a button&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organisms&lt;/strong&gt; - rather complex components made from molecules like headers or footers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Templates&lt;/strong&gt; - A page made from organisms but without any real content. In terms of React, this can be a layout component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pages&lt;/strong&gt; - A specific instance of a template, a real page in your application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LO5CB0n2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rljmkt30h7fzv4na8ygn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LO5CB0n2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rljmkt30h7fzv4na8ygn.png" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The distinction between templates and pages is rather hard to see, especially in frameworks like React, where a page is just a “template” because some content can be dynamic, i.e., fetched from the server. &lt;/p&gt;

&lt;p&gt;Atomic design provides you with a clear mental model of separating components and creating design systems. It makes you write more reusable code by encouraging you to use more components and make your code more modular. It can greatly speed up work because after the initial investment in building out reusable components, creating actual pages will be much easier. &lt;/p&gt;

&lt;p&gt;Have you tried Atomic design?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>frontend</category>
    </item>
    <item>
      <title>When should you leverage no-code or low-code</title>
      <dc:creator>Mikhail Kedzel</dc:creator>
      <pubDate>Thu, 20 Apr 2023 06:34:04 +0000</pubDate>
      <link>https://dev.to/miki-digital/when-should-you-leverage-no-code-or-low-code-3kg4</link>
      <guid>https://dev.to/miki-digital/when-should-you-leverage-no-code-or-low-code-3kg4</guid>
      <description>&lt;p&gt;When starting on a new website, even before selecting a framework or a JavaScript library, you should first decide if you want to write code. Perhaps, 10 or more years ago, this wasn't even a question, but now there are so many extremely powerful yet easy-to-use no-code and low-code solutions. More and more companies are tapping into the potential of low-code to save them time and money. Low-code seems like the perfect solution for an early-stage startup or someone who wants to build out a test version of their website.&lt;/p&gt;

&lt;p&gt;So, should you delete all your JavaScript apps and immediately switch to low-code? Well, it's not that one-sided. In my experience, almost every startup I've helped leveraged a no-code solution when they had just started, but practically no one ended up going with it all the way through. Since, with low-code, it can be impossible to customize your website beyond what the low-code platform allows you, and often the customization can be limited. So when and why using a modern JavaScript framework instead of a low-code platform can be a better choice?&lt;/p&gt;

&lt;h2&gt;
  
  
  You want to have more control over your website
&lt;/h2&gt;

&lt;p&gt;Even if you are building out a small website, no-code, and low-code platforms provide a pretty high level of abstraction. Sometimes, it's good enough, but you'd often want to customize SEO, install a custom library or a design framework. Those all can be impossible since low-code platforms provide you with a pre-defined set of tools. &lt;br&gt;
Using a modern JS framework like React or NextJS can make your website faster than a no-code platform because you can leverage the newest tools and library versions. For example, NextJS 13 supports React Server Components, making your app much faster. Want to use it? Well, a low-code platform probably doesn't support it. &lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid vendor lock-in
&lt;/h2&gt;

&lt;p&gt;If you've built out your app on one low-code platform, transferring it to another may be cumbersome. But, for example, if you use React, you can deploy your app anywhere you want. If you deployed your frontend on AWS Amplify and it stops working one day, you can always deploy on Firebase or Vercel instead. Of course, you'll have to change your CI/CD, but it's still easier than changing a low-code platform, in my experience. &lt;/p&gt;

&lt;h2&gt;
  
  
  More longevity
&lt;/h2&gt;

&lt;p&gt;On the one hand, it can be easy to innovate with a low-code solution, since you spend less time writing code and more time creating business features. So, you can iterate faster and try out new ideas without investing much time. &lt;br&gt;
On the other hand, the no-code and low-code world innovates even faster than the JavaScript world. React has been around for many years, and you can expect it to be actively maintained for the foreseeable future. There are many more low-code development websites than JS frameworks, so many can be less maintained and have less longevity. &lt;/p&gt;

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

&lt;p&gt;There is no one size fits all approach when it comes to going with low-code or not. It all comes down to personal preference, and mostly the deadlines and the budget. Need to get a good-looking website quickly and for a low development cost - use low or even no-code solutions. Want to invest more time and build a more future-proof and customizable app - build it from scratch with a modern JS framework. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>frontend</category>
      <category>design</category>
    </item>
  </channel>
</rss>
