<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Techformist</title>
    <link>https://techformist.com/</link>
    <description>Recent content on Techformist</description>
    <image>
      <url>https://techformist.com/logo.svg</url>
      <link>https://techformist.com/logo.svg</link>
    </image>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language><atom:link href="https://techformist.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Pexand - A Simple and Free Text Expander</title>
      <link>https://techformist.com/pexand-simple-free-text-expander/</link>
      <pubDate>Sat, 03 Jan 2026 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/pexand-simple-free-text-expander/</guid>
      <description>&lt;p&gt;After years of building web apps where &amp;ldquo;performance&amp;rdquo; means a 2-second LCP and &amp;ldquo;local storage&amp;rdquo; is a suggestion, I have taken the last 2-3 months to explore how the desktop ecosystem has changed. Since I don&amp;rsquo;t like opening browsers masquerading as an app all the time, Rust and specifically Tauri looked great.&lt;/p&gt;
&lt;p&gt;However I did lean back on AI coding a lot more with my latest project - &lt;strong&gt;Pexand&lt;/strong&gt;. I wanted to try how much can I like the core desktop app building experience that I have not delved into for sometime.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>After years of building web apps where &ldquo;performance&rdquo; means a 2-second LCP and &ldquo;local storage&rdquo; is a suggestion, I have taken the last 2-3 months to explore how the desktop ecosystem has changed. Since I don&rsquo;t like opening browsers masquerading as an app all the time, Rust and specifically Tauri looked great.</p>
<p>However I did lean back on AI coding a lot more with my latest project - <strong>Pexand</strong>. I wanted to try how much can I like the core desktop app building experience that I have not delved into for sometime.</p>
<p>Pexand a text expander. It&rsquo;s written in Rust. And it&rsquo;s gloriously, unapologetically &ldquo;dumb.&rdquo;</p>
<h2 id="the-sentinel-is-watching">The &ldquo;Sentinel&rdquo; is Watching</h2>
<p>Most modern apps want to know your location, your mother&rsquo;s maiden name, and your favorite flavor of cloud storage. Pexand just wants to know if you typed <code>;shrug</code>.</p>
<p>The app just monitors key strokes and upon finding a pattern replaces the abbreviation with an expanded form. While the core design suggestions were by multiple AI agents, I did try to make the app blow up here and there.</p>
<p>The way it works is interesting -</p>
<ol>
<li>A background thread called the <strong>Sentinel</strong> sits in the background, quietly monitoring your keystrokes using Windows hooks, waiting for a trigger.</li>
<li>When the sentinel sees one, it reaches into a <strong>Radix Trie</strong> (because O(m) lookup is the only way to live) and swaps your shortcut for the real deal in under 5ms.</li>
</ol>
<p>And.. that&rsquo;s it.</p>
<p>Here&rsquo;s what it looks like.</p>
<p><img loading="lazy" src="/2026/pexand-text-expander-home.png" type="" alt="pexand-ui-screenshot"  /></p>
<h2 id="why-build-another-text-expander">Why build another text expander?</h2>
<ul>
<li><strong>Cloud Fatigue:</strong> I don&rsquo;t want my snippets synced to a server in Singapore. I want them in a local SQLite database that I own.</li>
<li><strong>The &ldquo;Dumb&rdquo; Factor:</strong> No AI. No &ldquo;smart&rdquo; suggestions. No collaboration features. Just: I type <code>;addr</code>, it gives me my address.</li>
<li><strong>Rust:</strong> Honestly? I just wanted to see if I could make a GUI app in Rust without losing my mind.</li>
</ul>
<h2 id="the-tech-stack">The Tech Stack</h2>
<p>Building a native Windows app in 2026 feels like a superpower with AI coding.</p>
<ul>
<li><strong>Iced:</strong> The GUI framework uses the Elm Architecture, which means state management did not actually make sense to me. But, something new for sure - no more &ldquo;is this component re-rendering because of a ghost prop?&rdquo;</li>
<li><strong>SQLite:</strong> Every snippet lives in a local <code>.db</code> file. It&rsquo;s ACID compliant, fast, and portable. If I want to move my snippets, I just move the file. I could also export / import snippets - just saying.</li>
<li><strong>Radix Trie:</strong> This was most unfamiliar to me. Instead of looping through a list of snippets every time you press a key, the app traverses a tree. It&rsquo;s fast!</li>
</ul>
<p>I deliberately chose a tech stack that I had been putting away for sometime now. AI coding makes everything fast - even making terrible mistakes.</p>
<p>I was surprised and dismayed at the same time on how coding agents have evolved and helped through the process. That&rsquo;s a story for another day.</p>
<h2 id="features-for-the-minimalist">Features for the Minimalist</h2>
<ul>
<li><strong>Dynamic Variables:</strong> Use <code>{{date}}</code> or <code>{{clipboard}}</code> to inject context on the fly.</li>
<li><strong>App Filtering:</strong> Want expansion in VS Code but not in your terminal? Just blacklist it.</li>
<li><strong>Fuzzy Search:</strong> The &ldquo;Dashboard&rdquo; (summoned with <code>Ctrl+Alt+Shift+P</code>) lets you find snippets even if you only remember half the trigger.</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>Pexand isn&rsquo;t going to change the world. It&rsquo;s not a &ldquo;platform.&rdquo; It&rsquo;s a tool.</p>
<p>It&rsquo;s for the people who still appreciate a single <code>.exe</code> that does one thing and one thing.. uh, better than average. Or, it&rsquo;s only for me, because I&rsquo;m tired of copying and pasting from Notepad++ every time.</p>
<p>Check out the code, or download the binary and start being efficiently lazy:
<a href="https://github.com/techformist/pexand">https://github.com/techformist/pexand</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Notocan is a simple, local Google Keep alternative</title>
      <link>https://techformist.com/notocan-simple-local-notes/</link>
      <pubDate>Thu, 02 Oct 2025 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/notocan-simple-local-notes/</guid>
      <description>&lt;p&gt;After spending years 😏 building applications with Nuxt.js (and occasionally dipping into Next.js), I decided to take a step back to pure Vue 3 and create a.. lo and behold - a Google Keep alternative.&lt;/p&gt;
&lt;p&gt;Just kidding - the app is far more dumb.&lt;/p&gt;
&lt;h2 id=&#34;notocan-a-dumb-google-keep-alternative&#34;&gt;Notocan: A Dumb Google Keep Alternative&lt;/h2&gt;
&lt;p&gt;Notocan is what I like to say &amp;ldquo;deliberately dumb&amp;rdquo;, local and fast. It&amp;rsquo;s not trying to be the next big productivity platform with AI features, cloud sync complexity, or fancy collaboration tools. It&amp;rsquo;s just notes, done right in a browser window.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>After spending years 😏 building applications with Nuxt.js (and occasionally dipping into Next.js), I decided to take a step back to pure Vue 3 and create a.. lo and behold - a Google Keep alternative.</p>
<p>Just kidding - the app is far more dumb.</p>
<h2 id="notocan-a-dumb-google-keep-alternative">Notocan: A Dumb Google Keep Alternative</h2>
<p>Notocan is what I like to say &ldquo;deliberately dumb&rdquo;, local and fast. It&rsquo;s not trying to be the next big productivity platform with AI features, cloud sync complexity, or fancy collaboration tools. It&rsquo;s just notes, done right in a browser window.</p>
<p><img loading="lazy" src="/2025/notocan-keep-alternative.png" type="" alt="notocan-local-notes-in-browser"  /></p>
<p>tldr;</p>
<ul>
<li>Has it been done a million times? Yes.</li>
<li>Has it been done by me in the past? Probably, yes.</li>
<li>Will it deter me from building something dumb again. Absolutely not.</li>
</ul>
<p>The core features are straightforward:</p>
<ul>
<li>Create notes with titles and rich text content</li>
<li>Color-code your notes for visual organization</li>
<li>Pin important notes to keep them at the top</li>
<li>Archive notes you don&rsquo;t need anymore</li>
<li>Search through all your notes instantly</li>
<li>Keyboard navigation</li>
</ul>
<p>Check it out here:
<a href="https://notocan.techformist.com">https://notocan.techformist.com</a></p>
<p>If you are gungho about todo&rsquo;s and notes - Notocan is open source and available on <a href="https://github.com/prashanth1k/notocan">GitHub</a>.</p>
<p>Feel free to use the app, or just poke around the code!</p>
<h2 id="back-to-the-experience">Back to the Experience</h2>
<p>The experience though has been nothing short of refreshing. No more complex configurations, no more wrestling with SSR setups and errors, just pure Vue 3 with the Composition API.</p>
<p>The dev experience is incredibly fast - hot reload is instantaneous, compilation is lightning-quick, and the build process feels almost instantaneous.</p>
<p>It&rsquo;s amazing how much mental overhead you shed when you don&rsquo;t have to think about server-side rendering for a client-side notes app. Also, there are no accounts, no subscriptions, no worrying about data privacy or service outages.</p>
<p>Your notes live in your browser&rsquo;s IndexedDB, which means:</p>
<ul>
<li>Instant loading (no network calls)</li>
<li>Works offline perfectly</li>
<li>Your data stays yours</li>
<li>Migration from localStorage is handled automatically</li>
</ul>
<p>The IndexedDB implementation includes pagination for performance, so even with hundreds of notes, the app stays snappy.</p>
<p>Also, I can&rsquo;t say enough good things about DaisyUI. Every time I use it, I&rsquo;m reminded why it was my go-to UI library. The component system is thoughtful and the default styles just work without being overwhelming.</p>
<p>Combined with Tailwind CSS, DaisyUI makes building polished interfaces feel effortless. The color system, spacing, and component variants work together seamlessly. It&rsquo;s the kind of library that gets out of your way and lets you focus on building features, not fighting CSS. And, not having all the code in my repo mocking my design skills. I would like that mocking to be deep insite the node_modules thank you very much.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Building Notocan reinforced some important lessons:</p>
<ol>
<li>Simple is indeed beautiful</li>
<li>I continue to be undeterred by no one using the applications I build</li>
</ol>
<p>If you need a simple notes app, check out Notocan - it might just become your new favorite way to jot down thoughts.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>TimeMomo - A Shared Timer App</title>
      <link>https://techformist.com/shared-timer-app-free-self-hosted/</link>
      <pubDate>Thu, 02 Oct 2025 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/shared-timer-app-free-self-hosted/</guid>
      <description>&lt;p&gt;As someone who&amp;rsquo;s never been a huge fan of React, I found myself diving headfirst into building &lt;strong&gt;TimeMomo&lt;/strong&gt; - a real-time collaborative timer platform. This project was born out of a desire to learn more about modern web development stacks while creating something genuinely useful (for me, if no one else!).&lt;/p&gt;
&lt;p&gt;TimeMomo is designed for presenters, streamers, and event managers who need to share timers with audiences in real-time, without the complexity of traditional WebSocket implementations.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>As someone who&rsquo;s never been a huge fan of React, I found myself diving headfirst into building <strong>TimeMomo</strong> - a real-time collaborative timer platform. This project was born out of a desire to learn more about modern web development stacks while creating something genuinely useful (for me, if no one else!).</p>
<p>TimeMomo is designed for presenters, streamers, and event managers who need to share timers with audiences in real-time, without the complexity of traditional WebSocket implementations.</p>
<h2 id="what-is-timemomo">What is TimeMomo?</h2>
<p>TimeMomo is a collaborative timer application that allows users to create &ldquo;rooms&rdquo; where timers can be started, paused, and synchronized across all participants in real-time. Think of it as a professional timer platform for:</p>
<ul>
<li><strong>Presenters</strong> who need to manage speaking time during conferences</li>
<li><strong>Streamers</strong> who want to share countdowns with their audience</li>
<li><strong>Event managers</strong> coordinating multiple sessions</li>
<li><strong>Meeting facilitators</strong> keeping discussions on track</li>
</ul>
<p>The app features a clean, intuitive interface with room management, user authentication, and responsive design that works seamlessly on both desktop and mobile devices.</p>
<p>Using TimeMomo is simple.</p>
<p>Register &gt; Create a room &gt; Share the room URL with audience and presenters to see a common timer.</p>
<p><img loading="lazy" src="/2025/timemomo-timer.png" type="" alt="timemomo-timer"  /></p>
<p>It is an alternative to apps like stagetimer.io, but let&rsquo;s face it - there are many great apps and it&rsquo;s not a great alternative. TimeMomo happens to be the app I built.</p>
<p>Use it for free (well, limited to 3 concurrent rooms and ~100 participants).
<a href="http://timemomo.techformist.com/">http://timemomo.techformist.com/</a></p>
<p>Or, make the project your own! TimeMomo is open source and available on <a href="https://github.com/techformist/timemomo">GitHub</a>.</p>
<p>Try it out and let me know what you think!</p>
<h2 id="why-i-built-this">Why I Built This</h2>
<p>My motivation was twofold: <strong>learning</strong> and <strong>solving a real problem</strong>. Despite my reservations about React (I&rsquo;ve always preferred Vue/Nuxt), I wanted to challenge myself with Next.js to understand what all the hype was about. At the same time, I kept encountering situations where I needed a reliable timer that could be shared across devices without the hassle of screen sharing or manual coordination.</p>
<p>The idea crystallized when I realized how many professional settings could benefit from a real-time timer platform - from agile ceremonies to public speaking events. And since I&rsquo;m a big fan of keeping things simple, I wanted to build something that didn&rsquo;t require complex infrastructure.</p>
<h2 id="technology-choices-keeping-it-simple-and-powerful">Technology Choices: Keeping It Simple and Powerful</h2>
<h3 id="nextjs-facing-my-react-fears">Next.js: Facing My React Fears</h3>
<p>Choosing Next.js was a deliberate step outside my comfort zone. As someone who&rsquo;s struggled with React&rsquo;s verbosity and component lifecycle complexities, I approached this with skepticism. However, Next.js 15&rsquo;s improvements, combined with TypeScript, made the experience surprisingly smooth. The App Router and server components felt more intuitive than I expected, and the built-in optimization features handled performance concerns automatically.</p>
<h3 id="pocketbase-real-time-magic">PocketBase: Real-Time Magic</h3>
<p>This is where the project really shines. <strong>PocketBase is absolutely incredible</strong> for real-time applications. While I always appreciated the one-file philosophy for entire backend, I was blown away by how it handles live synchronization without needing to set up WebSocket servers or manage connection states. The real-time subscriptions API is so clean and reliable that I could focus on building features rather than infrastructure.</p>
<p>The decision to use PocketBase instead of traditional WebSockets was a game-changer. It simplified the architecture dramatically:</p>
<ul>
<li>No need for separate WebSocket servers</li>
<li>Built-in authentication and authorization</li>
<li>SQLite backend that&rsquo;s easy to deploy</li>
<li>Automatic real-time updates across all connected clients</li>
</ul>
<h3 id="shadcnui-the-ui-i-always-wanted">Shadcn/UI: The UI I Always Wanted</h3>
<p>If PocketBase is the backend hero, Shadcn is definitely the frontend star. The developer experience is exceptional - copy-paste components that just work, with full TypeScript support and excellent documentation.</p>
<h3 id="dokploy-deployment-adventures">Dokploy: Deployment Adventures</h3>
<p>Using Dokploy for the first time was an interesting experience. I always wanted the Vercel / Netlify experience at budget and this is certainly it. The ability to deploy both the Next.js frontend and PocketBase backend as containers with automated CI/CD made the whole process much smoother than traditional hosting setups.</p>
<h2 id="travails-and-turbulences-the-learning-curve">Travails and Turbulences: The Learning Curve</h2>
<p>Building TimeMomo wasn&rsquo;t without its challenges. As someone new to React/Next.js, I hit several roadblocks:</p>
<h3 id="react-learning-pains">React Learning Pains</h3>
<ul>
<li>Understanding React&rsquo;s component lifecycle and hooks took time</li>
<li>State management across real-time updates required careful planning</li>
<li>TypeScript integration had a learning curve, especially with complex types</li>
</ul>
<p>I am still not a fan.</p>
<h3 id="real-time-synchronization-headaches">Real-Time Synchronization Headaches</h3>
<ul>
<li>Love the real-time capabilities</li>
<li>Debugging hooks - not so much</li>
</ul>
<h3 id="deployment-drama">Deployment Drama</h3>
<ul>
<li>Dokploy&rsquo;s initial setup was trickier than expected</li>
<li>Docker networking between Next.js and PocketBase containers</li>
</ul>
<h2 id="and-finally-addressing-the-ai-in-the-room">And finally.. addressing the AI in the room</h2>
<p>AI tools were incredibly helpful throughout this project. I started out with Bolt, and switched to VSCode. Throughout the cycle, AI assistance was a game-changer for Next.js and Shadcn specifically. I was never very successful getting clean first versions out with Nuxt in the past, but with React I could certainly iterate much faster.</p>
<ul>
<li>Fast conversion of design ideas into working React components</li>
<li>Query issues during development</li>
<li>Get contextual answers for deployment issues</li>
</ul>
<h2 id="in-conclusion">In Conclusion</h2>
<p>This project taught me that sometimes stepping outside your comfort zone pays off. While I&rsquo;m still not a React convert, I now understand its strengths and can appreciate why it&rsquo;s so popular. The combination of Next.js + PocketBase + Shadcn proved to be incredibly productive.</p>
<p>Looking ahead, I&rsquo;m excited about the potential improvements:</p>
<ul>
<li>Nuxt 4 with Nuxt UI and Shadcn-Vue MCP (that AI-assisted Vue development I keep hearing about)</li>
<li>Laravel with Laravel Boost!</li>
</ul>
<p>My plans for this app? Well, not much - unless I see people really interested.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Introducing utils@techformist - A Developer&#39;s Swiss Army Knife</title>
      <link>https://techformist.com/free-developer-tools/</link>
      <pubDate>Tue, 25 Mar 2025 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/free-developer-tools/</guid>
      <description>&lt;p&gt;Today, I&amp;rsquo;m excited to introduce &lt;strong&gt;utils.techformist.com&lt;/strong&gt; – a collection of client-side web utilities designed to make developers&amp;rsquo; lives easier. Built with speed, simplicity, and privacy in mind, this tool suite aims to be your go-to resource for common development tasks.&lt;/p&gt;
&lt;h2 id=&#34;why-another-utility-site&#34;&gt;Why Another Utility Site?&lt;/h2&gt;
&lt;p&gt;The web is full of utility sites, but many come with drawbacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Intrusive ads and analytics&lt;/li&gt;
&lt;li&gt;Server-side processing of potentially sensitive data&lt;/li&gt;
&lt;li&gt;Slow loading times&lt;/li&gt;
&lt;li&gt;Inconsistent UI/UX&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://utils.techformist.com&#34;&gt;utils.techformist.com&lt;/a&gt; addresses these issues by keeping everything client-side, ensuring your data never leaves your browser. The site loads quickly, works offline, and offers a clean, consistent interface for all tools.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today, I&rsquo;m excited to introduce <strong>utils.techformist.com</strong> – a collection of client-side web utilities designed to make developers&rsquo; lives easier. Built with speed, simplicity, and privacy in mind, this tool suite aims to be your go-to resource for common development tasks.</p>
<h2 id="why-another-utility-site">Why Another Utility Site?</h2>
<p>The web is full of utility sites, but many come with drawbacks:</p>
<ul>
<li>Intrusive ads and analytics</li>
<li>Server-side processing of potentially sensitive data</li>
<li>Slow loading times</li>
<li>Inconsistent UI/UX</li>
</ul>
<p><a href="https://utils.techformist.com">utils.techformist.com</a> addresses these issues by keeping everything client-side, ensuring your data never leaves your browser. The site loads quickly, works offline, and offers a clean, consistent interface for all tools.</p>
<p><img loading="lazy" src="/2025/great-developer-tools-free.png" type="" alt="great-developer-tools-free"  /></p>
<h2 id="key-features">Key Features</h2>
<h3 id="1-tools-that-you-want-to-use">1. Tools that you want to use!</h3>
<p>Our collection includes essential utilities that solve real problems :)</p>
<ul>
<li><strong>Calculator</strong>: A simple yet powerful calculator for quick arithmetic operations.</li>
<li><strong>QR Code Generator</strong>: Create QR codes for URLs, WiFi networks, contact details, and more with customizable colors.</li>
<li><strong>Password Generator</strong>: Generate secure, random passwords with options for length, character types, and complexity.</li>
<li><strong>Barcode Generator</strong>: Create various barcode formats with customizable settings for professional or personal use.</li>
<li><strong>Image Converter</strong>: Convert images between different formats without uploading them to any server.</li>
<li><strong>Favicon Generator</strong>: Quickly create favicons for your website from any image.</li>
<li><strong>Color Picker</strong>: Extract and analyze colors from images with support for multiple color formats.</li>
<li><strong>JSON Formatter</strong>: Format, validate, and beautify JSON data with easy-to-use controls and copy functionality.</li>
<li><strong>Base64 Converter</strong>: Encode and decode text or files to and from Base64 format right in your browser.</li>
</ul>
<p>.. and so on. Check out the site for the latest updates.</p>
<h3 id="2-fast-search-and-category-based-organization">2. Fast Search and Category-Based Organization</h3>
<p>A simple tool search is at the heart of the site!
At the same time, tools are organized into logical categories for easy discovery:</p>
<ul>
<li><strong>Code</strong>: Developer tools like JSON Formatter and Base64 Converter for everyday coding tasks</li>
<li><strong>Image</strong>: Tools for working with images, including QR Code Generator, Barcode Generator, Image Converter, and Favicon Generator</li>
<li><strong>Text</strong>: Text manipulation utilities like the Password Generator</li>
<li><strong>Design</strong>: Creative tools such as the Color Picker for design work</li>
<li><strong>File</strong>: File processing tools like the PDF Compressor</li>
<li><strong>Other</strong>: Miscellaneous utilities including the Calculator</li>
</ul>
<p>This categorization ensures you can quickly find the right tool for your current task.</p>
<h3 id="3-responsive-and-accessible-design">3. Responsive and Accessible Design</h3>
<p>All tools feature:</p>
<ul>
<li>Fully responsive layouts that work on devices of any size</li>
<li>Dark/light mode support</li>
</ul>
<h3 id="4-privacy-first-approach">4. Privacy-First Approach</h3>
<p>What sets util.techformist.com apart is its commitment to privacy:</p>
<ul>
<li>No tracking (except essentials)</li>
<li>No server-side processing</li>
<li>No data storage outside of the browser</li>
<li>No data transmission to any external computer outside of your own browser</li>
</ul>
<h2 id="technology-stack">Technology Stack</h2>
<p>Utils.techformist.com is built on modern web technologies:</p>
<ul>
<li><strong>Nuxt 3</strong>: For its excellent developer experience, automatic routing, and performance optimizations</li>
<li><strong>NuxtUI</strong>: Providing a consistent design system and accessible components</li>
<li><strong>Tailwind CSS</strong>: For rapid styling and responsive design</li>
</ul>
<p>The app is client-side only - no database or server processing.</p>
<h2 id="why-client-side-only">Why Client-Side Only?</h2>
<p>The decision to make util.techformist.com entirely client-side was deliberate:</p>
<ol>
<li><strong>Privacy</strong>: Your data never leaves your browser, eliminating privacy concerns.</li>
<li><strong>Performance</strong>: No server roundtrips means instant processing of your tasks.</li>
<li><strong>Availability</strong>: The site works offline once loaded.</li>
<li><strong>Scalability</strong>: Without server costs, the site can scale infinitely.</li>
<li><strong>Simplicity</strong>: The architecture remains clean without databases or APIs.</li>
</ol>
<h2 id="development-approach">Development Approach</h2>
<p>Building the site was straightforward with Nuxt&rsquo;s module system and NuxtUI&rsquo;s component library. The development workflow included:</p>
<ol>
<li>Setting up a Nuxt 3 project with the content and UI modules</li>
<li>Creating a consistent layout and navigation system</li>
<li>Implementing individual utility components</li>
<li>Ensuring responsive design with Tailwind</li>
<li>Optimizing for performance</li>
</ol>
<p>The entire project required no backend infrastructure, making deployment simple through static site hosting.
The site is hosted on Cloudflare Pages.</p>
<h2 id="looking-ahead">Looking Ahead</h2>
<p>Util.techformist.com is just getting started. Future plans include:</p>
<ul>
<li>Adding more utility tools based on user feedback!</li>
<li>Implementing more advanced features like tool chaining :)</li>
<li>Improving keyboard shortcuts and accessibility</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>Util.techformist.com represents my philosophy that web tools should be fast, private, and straightforward. By keeping everything in the browser, I&rsquo;ve created a resource that respects your data while providing genuinely useful functionality.</p>
<p>Give it a try at <a href="https://utils.techformist.com">utils.techformist.com</a> and let me know what you think.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Create a Client-Side PDF Generator with Nuxt 3</title>
      <link>https://techformist.com/create-pdf-json-nuxt/</link>
      <pubDate>Sat, 01 Mar 2025 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/create-pdf-json-nuxt/</guid>
      <description>&lt;p&gt;We will walk through the steps to build a document analysis web application using Nuxt 3 and Azure Document Intelligence. This application allows users to -&lt;/p&gt;
&lt;p&gt;Features will include -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;🔍 Create/pass a template in HTML and placeholders for values&lt;/li&gt;
&lt;li&gt;🕶️ Real-time document analysis status&lt;/li&gt;
&lt;li&gt;💾 Download merged content as PDF&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s a quick demo.
&lt;img loading=&#34;lazy&#34; src=&#34;https://techformist.com/2025/docgen-pdf-generator-json-nuxt.gif&#34; type=&#34;&#34; alt=&#34;docgen-pdf-generator-json-nuxt&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;While the demo showcases invoice generation, the same program can be extended to any document type - filled application forms, documents, etc.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>We will walk through the steps to build a document analysis web application using Nuxt 3 and Azure Document Intelligence. This application allows users to -</p>
<p>Features will include -</p>
<ul>
<li>🔍 Create/pass a template in HTML and placeholders for values</li>
<li>🕶️ Real-time document analysis status</li>
<li>💾 Download merged content as PDF</li>
</ul>
<p>Here&rsquo;s a quick demo.
<img loading="lazy" src="/2025/docgen-pdf-generator-json-nuxt.gif" type="" alt="docgen-pdf-generator-json-nuxt"  /></p>
<p>While the demo showcases invoice generation, the same program can be extended to any document type - filled application forms, documents, etc.</p>
<p>Technology stack -</p>
<ol>
<li>NuxtJS</li>
<li>Tailwind CSS</li>
<li>PDFJS</li>
<li>CKEditor</li>
</ol>
<h2 id="why-client-side-pdf-generation">Why Client-Side PDF Generation?</h2>
<p>Generating PDFs on the client-side offers several benefits:</p>
<ul>
<li><strong>Performance:</strong> Offloading PDF generation to the client&rsquo;s device reduces server load and leads to faster response times.</li>
<li><strong>User Experience:</strong> Users can preview changes in real-time, adjust their inputs, and generate PDFs without a trip to the server.</li>
<li><strong>Cost-Effective:</strong> Avoid additional server infrastructure by leveraging modern browsers and their capabilities.</li>
<li><strong>Flexibility:</strong> Easily integrate rich text editing and custom templates to create personalized documents.</li>
</ul>
<p>Who is this post for?</p>
<ul>
<li>You are trying to roll-out a PDF generator for invoices or filled applications</li>
<li>You are using an external service to generate PDFs</li>
<li>You are not satisfied with server-side PDF generators</li>
</ul>
<h2 id="setting-up-the-project">Setting Up the Project</h2>
<p>Before we start, make sure you have Node.js 18.x or later installed in your computer.</p>
<p>Create a blank Nuxt app.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">bunx nuxi@latest init docgen
</span></span></code></pre></div><p>A key component of our PDF generator is a rich text editor to create templates. We will use CKEditor to achieve just that. We will also use a JSON editor to enable editing JSON data.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">bun i ckeditor/ckeditor5-vue ckeditor5 vue3-json-editor
</span></span></code></pre></div><p>We will use pdfjs to preview and generate PDF, and DomPurify to make sure we are rendering things safer. Also, install types while at it.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">bun i dompurify html2canvas jspdf pdfjs-dist pdfmake
</span></span><span class="line"><span class="cl">bun i -d @types/pdfmake
</span></span></code></pre></div><p>Add styling and icons.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">bunx nuxi@latest module add tailwindcss lucide-vue-next
</span></span></code></pre></div><h2 id="develop-the-app">Develop the app</h2>
<h3 id="rich-text-editor">Rich Text Editor</h3>
<p>Rich text editor is one of the main components that enables users to edit templates.
You will not need the rich text editor if you don&rsquo;t plan to edit templates within the app (the template is plain HTML anyway.)</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;richtext-editor&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">ckeditor</span>
</span></span><span class="line"><span class="cl">      <span class="nt">v-if</span><span class="o">=</span><span class="s">&#34;editor &amp;&amp; config &amp;&amp; modelValue&#34;</span><span class="p">
</span></span></span><span class="line"><span class="cl">      <span class="nt">:editor</span><span class="o">=</span><span class="s">&#34;editor&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">v-model</span><span class="o">=</span><span class="s">&#34;modelValue&#34;</span><span class="p">
</span></span></span><span class="line"><span class="cl">      <span class="nt">:config</span><span class="o">=</span><span class="s">&#34;config&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span>
</span></span><span class="line"><span class="cl">      <span class="nt">v-if</span><span class="o">=</span><span class="s">&#34;previewContent&#34;</span><span class="p">
</span></span></span><span class="line"><span class="cl">      <span class="na">class</span><span class="o">=</span><span class="s">&#34;preview-overlay prose&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">v-html</span><span class="o">=</span><span class="s">&#34;previewContent&#34;</span><span class="p">
</span></span></span><span class="line"><span class="cl">    <span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">onMounted</span><span class="p">,</span> <span class="nx">ref</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ClassicEditor</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Autoformat</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">AutoImage</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Autosave</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Base64UploadAdapter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Bold</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Essentials</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// other items - see GitHub link
</span></span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;ckeditor5&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;ckeditor5/ckeditor5.css&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">Ckeditor</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;@ckeditor/ckeditor5-vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;ckeditor5/ckeditor5.css&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">isLayoutReady</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">editor</span> <span class="o">=</span> <span class="nx">ClassicEditor</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">LICENSE_KEY</span> <span class="o">=</span> <span class="s2">&#34;GPL&#34;</span><span class="p">;</span> <span class="c1">// or &lt;YOUR_LICENSE_KEY&gt;.
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">config</span> <span class="o">=</span> <span class="nx">computed</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isLayoutReady</span><span class="p">.</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">toolbar</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">items</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;sourceEditing&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;|&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;heading&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;|&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;fontSize&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;fontFamily&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// other toolbar items. See GitHub link for all buttons
</span></span></span><span class="line"><span class="cl">      <span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nx">shouldNotGroupWhenFull</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">plugins</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// relevant plugins - see GitHub link
</span></span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fontFamily</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">supportAllValues</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fontSize</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">options</span><span class="o">:</span> <span class="p">[</span><span class="mi">10</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">14</span><span class="p">,</span> <span class="s2">&#34;default&#34;</span><span class="p">,</span> <span class="mi">18</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">22</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nx">supportAllValues</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">heading</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">options</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">model</span><span class="o">:</span> <span class="s2">&#34;paragraph&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="s2">&#34;Paragraph&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="kr">class</span><span class="o">:</span> <span class="s2">&#34;ck-heading_paragraph&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">model</span><span class="o">:</span> <span class="s2">&#34;heading1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">view</span><span class="o">:</span> <span class="s2">&#34;h1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="s2">&#34;Heading 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="kr">class</span><span class="o">:</span> <span class="s2">&#34;ck-heading_heading1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">model</span><span class="o">:</span> <span class="s2">&#34;heading2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">view</span><span class="o">:</span> <span class="s2">&#34;h2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="s2">&#34;Heading 2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="kr">class</span><span class="o">:</span> <span class="s2">&#34;ck-heading_heading2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">model</span><span class="o">:</span> <span class="s2">&#34;heading3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">view</span><span class="o">:</span> <span class="s2">&#34;h3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="s2">&#34;Heading 3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="kr">class</span><span class="o">:</span> <span class="s2">&#34;ck-heading_heading3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">model</span><span class="o">:</span> <span class="s2">&#34;heading4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">view</span><span class="o">:</span> <span class="s2">&#34;h4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="s2">&#34;Heading 4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="kr">class</span><span class="o">:</span> <span class="s2">&#34;ck-heading_heading4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">model</span><span class="o">:</span> <span class="s2">&#34;heading5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">view</span><span class="o">:</span> <span class="s2">&#34;h5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="s2">&#34;Heading 5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="kr">class</span><span class="o">:</span> <span class="s2">&#34;ck-heading_heading5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">model</span><span class="o">:</span> <span class="s2">&#34;heading6&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">view</span><span class="o">:</span> <span class="s2">&#34;h6&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="s2">&#34;Heading 6&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="kr">class</span><span class="o">:</span> <span class="s2">&#34;ck-heading_heading6&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">image</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">toolbar</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;imageTextAlternative&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">initialData</span><span class="o">:</span> <span class="s2">&#34;..&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">licenseKey</span><span class="o">:</span> <span class="nx">LICENSE_KEY</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">link</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">addTargetToExternalLinks</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">defaultProtocol</span><span class="o">:</span> <span class="s2">&#34;https://&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">decorators</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">toggleDownloadable</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">mode</span><span class="o">:</span> <span class="s2">&#34;manual&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">label</span><span class="o">:</span> <span class="s2">&#34;Downloadable&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">attributes</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">download</span><span class="o">:</span> <span class="s2">&#34;file&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">placeholder</span><span class="o">:</span> <span class="s2">&#34;Type or paste your content here!&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">contentToolbar</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;tableColumn&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;tableRow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;mergeTableCells&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;tableProperties&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;tableCellProperties&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">modelValue</span> <span class="o">=</span> <span class="nx">defineModel</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nx">defineProps</span><span class="o">&lt;</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">previewContent</span><span class="o">?:</span> <span class="nx">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="o">&gt;</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">onMounted</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">isLayoutReady</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="cm">/* include styles */</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><h3 id="json-editor">JSON Editor</h3>
<p>Create the JSON editor that is used to edit JSON data.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="c">&lt;!--</span> <span class="nx">components</span><span class="o">/</span><span class="nx">DataEditor</span><span class="p">.</span><span class="nx">vue</span> <span class="o">--&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">ClientOnly</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span>
</span></span><span class="line"><span class="cl">      <span class="na">class</span><span class="o">=</span><span class="s">&#34;h-[300px] border border-white/20 rounded-lg overflow-hidden bg-white/5&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">textarea</span>
</span></span><span class="line"><span class="cl">        <span class="nt">v-model</span><span class="o">=</span><span class="s">&#34;jsonString&#34;</span><span class="p">
</span></span></span><span class="line"><span class="cl">        <span class="na">class</span><span class="o">=</span><span class="s">&#34;w-full h-full p-4 font-mono text-sm bg-transparent text-black dark:text-white/90 focus:outline-none&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">@input</span><span class="s">=&#34;handleInput&#34;</span><span class="p">
</span></span></span><span class="line"><span class="cl">        <span class="na">spellcheck</span><span class="o">=</span><span class="s">&#34;false&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&gt;&lt;/</span><span class="nt">textarea</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="nt">v-if</span><span class="o">=</span><span class="s">&#34;error&#34; class=&#34;mt-2 text-red-400 text-sm&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">{{</span> <span class="na">error</span> <span class="p">}}</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">ClientOnly</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">watch</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useDocumentStore</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;~/stores/document&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nx">defineProps</span><span class="o">&lt;</span><span class="p">{</span> <span class="nx">modelValue</span><span class="o">:</span> <span class="nx">Record</span><span class="p">&lt;</span><span class="nt">string</span><span class="err">,</span> <span class="na">any</span><span class="p">&gt;</span> <span class="p">}</span><span class="o">&gt;</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">emit</span> <span class="o">=</span> <span class="nx">defineEmits</span><span class="o">&lt;</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;update:modelValue&#34;</span><span class="o">:</span> <span class="p">[</span><span class="nx">value</span><span class="o">:</span> <span class="nx">Record</span><span class="p">&lt;</span><span class="nt">string</span><span class="err">,</span> <span class="na">any</span><span class="p">&gt;];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="o">&gt;</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">documentStore</span> <span class="o">=</span> <span class="nx">useDocumentStore</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">error</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">jsonString</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">props</span><span class="p">.</span><span class="nx">modelValue</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="mi">2</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">watch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="p">()</span> <span class="p">=&gt;</span> <span class="nx">props</span><span class="p">.</span><span class="nx">modelValue</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nx">newVal</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">newString</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">newVal</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">jsonString</span><span class="p">.</span><span class="nx">value</span> <span class="o">!==</span> <span class="nx">newString</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">jsonString</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">newString</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">handleInput</span> <span class="o">=</span> <span class="p">(</span><span class="nx">event</span><span class="o">:</span> <span class="nx">Event</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">target</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">target</span> <span class="nx">as</span> <span class="nx">HTMLTextAreaElement</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">parsed</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">error</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">documentStore</span><span class="p">.</span><span class="nx">isDirty</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">emit</span><span class="p">(</span><span class="s2">&#34;update:modelValue&#34;</span><span class="p">,</span> <span class="nx">parsed</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">error</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;Invalid JSON format&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="cm">/* include styles */</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><h3 id="create-pdf-viewer">Create PDF Viewer</h3>
<p>PDF viewer shows the PDF after merging data in template.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="c">&lt;!--</span> <span class="nx">components</span><span class="o">/</span><span class="nx">PdfViewer</span><span class="p">.</span><span class="nx">vue</span> <span class="o">--&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;pdf-viewer&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="nt">v-if</span><span class="o">=</span><span class="s">&#34;loading&#34; class=&#34;loading-indicator&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;spinner&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span><span class="nx">Generating</span> <span class="nx">PDF</span> <span class="nx">preview</span><span class="p">...&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="nt">v-else-if</span><span class="o">=</span><span class="s">&#34;error&#34; class=&#34;error-message&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">{{</span> <span class="na">error</span> <span class="p">}}</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="nt">v-else</span><span class="p"> </span><span class="na">ref</span><span class="o">=</span><span class="s">&#34;canvasContainer&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;canvas-container&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">onMounted</span><span class="p">,</span> <span class="nx">watch</span><span class="p">,</span> <span class="nx">onBeforeUnmount</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nx">defineProps</span><span class="o">&lt;</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">content</span><span class="o">:</span> <span class="nx">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="o">&gt;</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">canvasContainer</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">&lt;</span><span class="nt">HTMLElement</span> <span class="err">|</span> <span class="na">null</span><span class="p">&gt;(</span><span class="kc">null</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">loading</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">error</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">&lt;</span><span class="nt">string</span> <span class="err">|</span> <span class="na">null</span><span class="p">&gt;(</span><span class="kc">null</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">pdfDoc</span><span class="o">:</span> <span class="nx">any</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">currentPage</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">pageRendering</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">pageNumPending</span><span class="o">:</span> <span class="nx">number</span> <span class="o">|</span> <span class="kc">null</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">pdfjsLib</span><span class="o">:</span> <span class="nx">any</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Clean up any resources when component is unmounted
</span></span></span><span class="line"><span class="cl"><span class="nx">onBeforeUnmount</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">pdfDoc</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">pdfDoc</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Initialize PDF.js
</span></span></span><span class="line"><span class="cl"><span class="nx">onMounted</span><span class="p">(</span><span class="nx">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">client</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// Import PDF.js dynamically
</span></span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">pdfjsModule</span> <span class="o">=</span> <span class="nx">await</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;pdfjs-dist&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">pdfjsLib</span> <span class="o">=</span> <span class="nx">pdfjsModule</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1">// Set worker source - using CDN for the worker
</span></span></span><span class="line"><span class="cl">      <span class="nx">pdfjsLib</span><span class="p">.</span><span class="nx">GlobalWorkerOptions</span><span class="p">.</span><span class="nx">workerSrc</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1">// Generate and render PDF
</span></span></span><span class="line"><span class="cl">      <span class="nx">await</span> <span class="nx">generatePdf</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error initializing PDF.js:&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">error</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;Failed to initialize PDF viewer. Please try again.&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="nx">loading</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Watch for content changes
</span></span></span><span class="line"><span class="cl"><span class="nx">watch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="p">()</span> <span class="p">=&gt;</span> <span class="nx">props</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">pdfjsLib</span> <span class="o">&amp;&amp;</span> <span class="nx">process</span><span class="p">.</span><span class="nx">client</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">loading</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="nx">error</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="nx">await</span> <span class="nx">generatePdf</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Generate PDF from content
</span></span></span><span class="line"><span class="cl"><span class="nx">async</span> <span class="kd">function</span> <span class="nx">generatePdf</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">pdfjsLib</span> <span class="o">||</span> <span class="o">!</span><span class="nx">process</span><span class="p">.</span><span class="nx">client</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// Import pdfMake dynamically
</span></span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">pdfMakeModule</span> <span class="o">=</span> <span class="nx">await</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;pdfmake/build/pdfmake&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">pdfFontsModule</span> <span class="o">=</span> <span class="nx">await</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;pdfmake/build/vfs_fonts&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Get the default export or the module itself
</span></span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">pdfMake</span> <span class="o">=</span> <span class="nx">pdfMakeModule</span><span class="p">.</span><span class="k">default</span> <span class="o">||</span> <span class="nx">pdfMakeModule</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Manually set up the vfs with a basic font
</span></span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">pdfMake</span><span class="p">.</span><span class="nx">vfs</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// @ts-ignore - We know this property might exist
</span></span></span><span class="line"><span class="cl">      <span class="nx">pdfMake</span><span class="p">.</span><span class="nx">vfs</span> <span class="o">=</span> <span class="nx">pdfFontsModule</span><span class="p">.</span><span class="nx">pdfMake</span><span class="o">?</span><span class="p">.</span><span class="nx">vfs</span> <span class="o">||</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Create a temporary element to parse the HTML
</span></span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">tempDiv</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">&#34;div&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">tempDiv</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">props</span><span class="p">.</span><span class="nx">content</span> <span class="o">||</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Extract text content and structure
</span></span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">pdfContent</span> <span class="o">=</span> <span class="nx">extractPdfContent</span><span class="p">(</span><span class="nx">tempDiv</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Define the document with basic fonts
</span></span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">docDefinition</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">content</span><span class="o">:</span> <span class="nx">pdfContent</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">defaultStyle</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">font</span><span class="o">:</span> <span class="s2">&#34;Roboto&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">fontSize</span><span class="o">:</span> <span class="mi">12</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">lineHeight</span><span class="o">:</span> <span class="mf">1.5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">pageSize</span><span class="o">:</span> <span class="s2">&#34;A4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">pageMargins</span><span class="o">:</span> <span class="p">[</span><span class="mi">40</span><span class="p">,</span> <span class="mi">60</span><span class="p">,</span> <span class="mi">40</span><span class="p">,</span> <span class="mi">60</span><span class="p">]</span> <span class="nx">as</span> <span class="p">[</span><span class="nx">number</span><span class="p">,</span> <span class="nx">number</span><span class="p">,</span> <span class="nx">number</span><span class="p">,</span> <span class="nx">number</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Generate PDF as Blob
</span></span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">pdfDocGenerator</span> <span class="o">=</span> <span class="nx">pdfMake</span><span class="p">.</span><span class="nx">createPdf</span><span class="p">(</span><span class="nx">docDefinition</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">pdfDocGenerator</span><span class="p">.</span><span class="nx">getBlob</span><span class="p">(</span><span class="nx">async</span> <span class="p">(</span><span class="nx">blob</span><span class="o">:</span> <span class="nx">Blob</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Convert blob to array buffer
</span></span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">arrayBuffer</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">blob</span><span class="p">.</span><span class="nx">arrayBuffer</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// Load PDF document
</span></span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">loadingTask</span> <span class="o">=</span> <span class="nx">pdfjsLib</span><span class="p">.</span><span class="nx">getDocument</span><span class="p">({</span> <span class="nx">data</span><span class="o">:</span> <span class="nx">arrayBuffer</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">        <span class="nx">pdfDoc</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">loadingTask</span><span class="p">.</span><span class="nx">promise</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// Initial/first page rendering
</span></span></span><span class="line"><span class="cl">        <span class="nx">await</span> <span class="nx">renderPage</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">loading</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error rendering PDF:&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">error</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;Failed to render PDF preview.&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nx">loading</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error generating PDF:&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">error</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;Failed to generate PDF preview.&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">loading</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Render the specified page
</span></span></span><span class="line"><span class="cl"><span class="nx">async</span> <span class="kd">function</span> <span class="nx">renderPage</span><span class="p">(</span><span class="nx">num</span><span class="o">:</span> <span class="nx">number</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">pdfDoc</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">pageRendering</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// Get page
</span></span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">page</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">pdfDoc</span><span class="p">.</span><span class="nx">getPage</span><span class="p">(</span><span class="nx">num</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Clear previous content
</span></span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">canvasContainer</span><span class="p">.</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">canvasContainer</span><span class="p">.</span><span class="nx">value</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Calculate scale to fit the container width
</span></span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">containerWidth</span> <span class="o">=</span> <span class="nx">canvasContainer</span><span class="p">.</span><span class="nx">value</span><span class="o">?</span><span class="p">.</span><span class="nx">clientWidth</span> <span class="o">||</span> <span class="mi">800</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">viewport</span> <span class="o">=</span> <span class="nx">page</span><span class="p">.</span><span class="nx">getViewport</span><span class="p">({</span> <span class="nx">scale</span><span class="o">:</span> <span class="mi">1</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">scale</span> <span class="o">=</span> <span class="nx">containerWidth</span> <span class="o">/</span> <span class="nx">viewport</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">scaledViewport</span> <span class="o">=</span> <span class="nx">page</span><span class="p">.</span><span class="nx">getViewport</span><span class="p">({</span> <span class="nx">scale</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Create canvas for each page
</span></span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">&#34;canvas&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">ctx</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="s2">&#34;2d&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span> <span class="o">=</span> <span class="nx">scaledViewport</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nx">scaledViewport</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">canvas</span><span class="p">.</span><span class="nx">className</span> <span class="o">=</span> <span class="s2">&#34;pdf-page&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Add canvas to container
</span></span></span><span class="line"><span class="cl">    <span class="nx">canvasContainer</span><span class="p">.</span><span class="nx">value</span><span class="o">?</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">canvas</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Render PDF page into canvas context
</span></span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">renderContext</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">canvasContext</span><span class="o">:</span> <span class="nx">ctx</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">viewport</span><span class="o">:</span> <span class="nx">scaledViewport</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="nx">renderContext</span><span class="p">).</span><span class="nx">promise</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">pageRendering</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// If there&#39;s a pending page, render it
</span></span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">pageNumPending</span> <span class="o">!==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">renderPage</span><span class="p">(</span><span class="nx">pageNumPending</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">pageNumPending</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// If there are more pages, render them too
</span></span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">num</span> <span class="o">&lt;</span> <span class="nx">pdfDoc</span><span class="p">.</span><span class="nx">numPages</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">renderPage</span><span class="p">(</span><span class="nx">num</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error rendering page:&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">pageRendering</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">error</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;Failed to render PDF page.&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Extract content from HTML for PDF generation
</span></span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">extractPdfContent</span><span class="p">(</span><span class="nx">element</span><span class="o">:</span> <span class="nx">HTMLElement</span><span class="p">)</span><span class="o">:</span> <span class="nx">any</span><span class="p">[]</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">result</span><span class="o">:</span> <span class="nx">any</span><span class="p">[]</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// Process child nodes
</span></span></span><span class="line"><span class="cl">  <span class="nb">Array</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="nx">element</span><span class="p">.</span><span class="nx">childNodes</span><span class="p">).</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">node</span><span class="o">:</span> <span class="nx">Node</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">nodeType</span> <span class="o">===</span> <span class="nx">Node</span><span class="p">.</span><span class="nx">TEXT_NODE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">text</span> <span class="o">=</span> <span class="nx">node</span><span class="p">.</span><span class="nx">textContent</span><span class="o">?</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span> <span class="o">||</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span> <span class="nx">text</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">nodeType</span> <span class="o">===</span> <span class="nx">Node</span><span class="p">.</span><span class="nx">ELEMENT_NODE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">elementNode</span> <span class="o">=</span> <span class="nx">node</span> <span class="nx">as</span> <span class="nx">HTMLElement</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">nodeName</span> <span class="o">=</span> <span class="nx">elementNode</span><span class="p">.</span><span class="nx">nodeName</span><span class="p">.</span><span class="nx">toLowerCase</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1">// Handle different element types
</span></span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">nodeName</span> <span class="o">===</span> <span class="s2">&#34;p&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">text</span><span class="o">:</span> <span class="nx">elementNode</span><span class="p">.</span><span class="nx">textContent</span><span class="o">?</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span> <span class="o">||</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">margin</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">nodeName</span> <span class="o">===</span> <span class="s2">&#34;h1&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">text</span><span class="o">:</span> <span class="nx">elementNode</span><span class="p">.</span><span class="nx">textContent</span><span class="o">?</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span> <span class="o">||</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">fontSize</span><span class="o">:</span> <span class="mi">24</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">bold</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">margin</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">nodeName</span> <span class="o">===</span> <span class="s2">&#34;h2&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">text</span><span class="o">:</span> <span class="nx">elementNode</span><span class="p">.</span><span class="nx">textContent</span><span class="o">?</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span> <span class="o">||</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">fontSize</span><span class="o">:</span> <span class="mi">20</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">bold</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">margin</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">nodeName</span> <span class="o">===</span> <span class="s2">&#34;h3&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">text</span><span class="o">:</span> <span class="nx">elementNode</span><span class="p">.</span><span class="nx">textContent</span><span class="o">?</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span> <span class="o">||</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">fontSize</span><span class="o">:</span> <span class="mi">16</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">bold</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">margin</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">nodeName</span> <span class="o">===</span> <span class="s2">&#34;ul&#34;</span> <span class="o">||</span> <span class="nx">nodeName</span> <span class="o">===</span> <span class="s2">&#34;ol&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">items</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="nx">elementNode</span><span class="p">.</span><span class="nx">children</span><span class="p">).</span><span class="nx">map</span><span class="p">((</span><span class="nx">li</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="k">return</span> <span class="p">{</span> <span class="nx">text</span><span class="o">:</span> <span class="nx">li</span><span class="p">.</span><span class="nx">textContent</span><span class="o">?</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span> <span class="o">||</span> <span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="nx">margin</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">ul</span><span class="o">:</span> <span class="nx">nodeName</span> <span class="o">===</span> <span class="s2">&#34;ul&#34;</span> <span class="o">?</span> <span class="nx">items</span> <span class="o">:</span> <span class="kc">undefined</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">ol</span><span class="o">:</span> <span class="nx">nodeName</span> <span class="o">===</span> <span class="s2">&#34;ol&#34;</span> <span class="o">?</span> <span class="nx">items</span> <span class="o">:</span> <span class="kc">undefined</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">margin</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">nodeName</span> <span class="o">===</span> <span class="s2">&#34;table&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Extract table data
</span></span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">tableData</span><span class="o">:</span> <span class="nx">string</span><span class="p">[][]</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">        <span class="nb">Array</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="nx">elementNode</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="s2">&#34;tr&#34;</span><span class="p">)).</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">row</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="kr">const</span> <span class="nx">rowData</span><span class="o">:</span> <span class="nx">string</span><span class="p">[]</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">          <span class="nb">Array</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="nx">row</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="s2">&#34;td, th&#34;</span><span class="p">)).</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">cell</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">rowData</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">cell</span><span class="p">.</span><span class="nx">textContent</span><span class="o">?</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span> <span class="o">||</span> <span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">          <span class="p">});</span>
</span></span><span class="line"><span class="cl">          <span class="k">if</span> <span class="p">(</span><span class="nx">rowData</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">tableData</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">rowData</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">tableData</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">            <span class="nx">table</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nx">body</span><span class="o">:</span> <span class="nx">tableData</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nx">widths</span><span class="o">:</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">tableData</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">length</span><span class="p">).</span><span class="nx">fill</span><span class="p">(</span><span class="s2">&#34;*&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="nx">margin</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">          <span class="p">});</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Recursively process other elements
</span></span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">childContent</span> <span class="o">=</span> <span class="nx">extractPdfContent</span><span class="p">(</span><span class="nx">elementNode</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">childContent</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">(...</span><span class="nx">childContent</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">result</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Include this in a <code>DocumentPreview.vue</code> component that can toggle between PDF viewer and a rich text viewer - if needed, of course.</p>
<h3 id="layout-and-page">Layout and Page</h3>
<p>Update layout -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="c">&lt;!--</span> <span class="nx">layouts</span><span class="o">/</span><span class="k">default</span><span class="p">.</span><span class="nx">vue</span> <span class="o">--&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;min-h-screen bg-surface-ground&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">nav</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;bg-surface-card border-b border-surface-border md:px-12 px-6&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34; h-16 flex items-center justify-between&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h1</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-xl font-bold text-black&#34;</span><span class="p">&gt;</span><span class="nx">docgen</span><span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;flex items-center gap-4&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">button</span>
</span></span><span class="line"><span class="cl">            <span class="na">variant</span><span class="o">=</span><span class="s">&#34;secondary&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="o">:</span><span class="na">icon</span><span class="o">=</span><span class="s">&#34;isDark ? &#39;sun&#39; : &#39;moon&#39;&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">@click</span><span class="s">=&#34;toggleTheme&#34;</span><span class="p">
</span></span></span><span class="line"><span class="cl">            <span class="o">:</span><span class="na">title</span><span class="o">=</span><span class="s">&#34;isDark ? &#39;Switch to light mode&#39; : &#39;Switch to dark mode&#39;&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">main</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34; py-6&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">slot</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>&hellip; and the page.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;mx-auto px-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;grid grid-cols-1 lg:grid-cols-2 gap-6&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;flex flex-col gap-6&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;card&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;toolbar&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;section-title&#34;</span><span class="p">&gt;</span><span class="nx">Template</span><span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;h-[600px] overflow-hidden&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">ClientOnly</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">&lt;</span><span class="nt">RichTextEditor</span> <span class="nt">v-model</span><span class="o">=</span><span class="s">&#34;template&#34; class=&#34;h-full&#34;</span><span class="p"> /&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">ClientOnly</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;card&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="c">&lt;!--</span> <span class="nx">Removed</span> <span class="nx">flex</span><span class="o">-</span><span class="mi">1</span> <span class="nx">from</span> <span class="nx">card</span> <span class="o">--&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;toolbar&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;section-title&#34;</span><span class="p">&gt;</span><span class="nx">Data</span> <span class="p">(</span><span class="nx">JSON</span><span class="p">)&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;editor-container h-[400px] overflow-hidden&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">DataEditor</span> <span class="nt">v-model</span><span class="o">=</span><span class="s">&#34;jsonData&#34; class=&#34;h-full&#34;</span><span class="p"> /&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;card&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="c">&lt;!--</span> <span class="nx">Removed</span> <span class="nx">flex</span><span class="o">-</span><span class="mi">1</span> <span class="nx">from</span> <span class="nx">card</span> <span class="o">--&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;toolbar&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;section-title&#34;</span><span class="p">&gt;</span><span class="nx">Generated</span> <span class="nx">Document</span><span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;toolbar-actions&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="c">&lt;!--</span> <span class="p">&lt;</span><span class="nt">Button</span> <span class="na">variant</span><span class="o">=</span><span class="s">&#34;secondary&#34;</span> <span class="na">icon</span><span class="o">=</span><span class="s">&#34;refresh&#34;</span><span class="p">&gt;</span><span class="nx">Auto</span><span class="o">-</span><span class="nx">refresh</span><span class="p">&lt;/</span><span class="nt">Button</span><span class="p">&gt;</span> <span class="o">--&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;h-[1024px] overflow-hidden&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">DocumentPreview</span> <span class="nt">:data</span><span class="o">=</span><span class="s">&#34;jsonData&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;h-full&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useDocumentStore</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;~/stores/document&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">storeToRefs</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;pinia&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">documentStore</span> <span class="o">=</span> <span class="nx">useDocumentStore</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">template</span><span class="p">,</span> <span class="nx">jsonData</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">storeToRefs</span><span class="p">(</span><span class="nx">documentStore</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span> <span class="na">scoped</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="cm">/* styles */</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><h2 id="run-the-app">Run the app!</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">bun dev
</span></span></code></pre></div><p>This should populate some default template and data, and show you a nice preview of the merged content.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Generating PDF on client is not hard and keeps your server load low.</p>
<p>While generating PDFs client-side can certainly help in most use cases (especially for enterprise customers), it may not be a pleasant experience for mobile users. Also, features like emailing PDF, supporting non-PDF formats, etc. are hard to achieve.</p>
<p>See complete code on <a href="http://github.com/prashanth1k/docgen">GitHub</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Document Analysis App with Azure Document Intelligence</title>
      <link>https://techformist.com/document-analysis-app-nuxt/</link>
      <pubDate>Sun, 23 Feb 2025 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/document-analysis-app-nuxt/</guid>
      <description>&lt;p&gt;We will walk through the steps to build a document analysis web application using Nuxt 3 and Azure Document Intelligence. This application allows users to -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;upload PDF or images&lt;/li&gt;
&lt;li&gt;specify fields (if needed)&lt;/li&gt;
&lt;li&gt;extract specific fields of information&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Features will include -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;🔍 Extract custom fields from identification documents&lt;/li&gt;
&lt;li&gt;🔄 Real-time document analysis status&lt;/li&gt;
&lt;li&gt;💾 Download extracted data as JSON&lt;/li&gt;
&lt;li&gt;🎨 UI with Shadcn-vue /Tailwind CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s a quick demo.
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/_FLmnAfiqUo?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>We will walk through the steps to build a document analysis web application using Nuxt 3 and Azure Document Intelligence. This application allows users to -</p>
<ul>
<li>upload PDF or images</li>
<li>specify fields (if needed)</li>
<li>extract specific fields of information</li>
</ul>
<p>Features will include -</p>
<ul>
<li>🔍 Extract custom fields from identification documents</li>
<li>🔄 Real-time document analysis status</li>
<li>💾 Download extracted data as JSON</li>
<li>🎨 UI with Shadcn-vue /Tailwind CSS</li>
</ul>
<p>Here&rsquo;s a quick demo.
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/_FLmnAfiqUo?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>
</p>
<p>While the demo covers only identification documents, the same program can be extended to any document type - application forms, invoices, etc.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before we start, make sure you have the following:</p>
<ul>
<li>Node.js 18.x or later</li>
<li>An Azure account with a Document Intelligence resource</li>
<li>Azure Document Intelligence API key and endpoint</li>
</ul>
<h2 id="step-1-setting-up-the-project">Step 1: Setting Up the Project</h2>
<p>Create a blank Nuxt app..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">pnpx nuxi@latest init docformist
</span></span></code></pre></div><p>Get your API key and environment details from <a href="https://azure.microsoft.com/products/ai-services/ai-document-intelligence">Azure site</a>. You can sign up for free and use a Free plan to test out the service.</p>
<p>Create a <code>.env</code> file in the root directory with your Azure credentials:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-env" data-lang="env"><span class="line"><span class="cl"><span class="nv">AZURE_DOCUMENT_INTELLIGENCE_KEY</span><span class="o">=</span>your_key_here
</span></span><span class="line"><span class="cl"><span class="nv">AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT</span><span class="o">=</span>your_endpoint_here
</span></span></code></pre></div><p>Add Nuxt modules -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">pnpx nuxi@latest module add shadcn-nuxt
</span></span><span class="line"><span class="cl">pnpx nuxi@latest module add tailwindcss
</span></span></code></pre></div><p>Initialize shadcn and tailwind -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">pnpx tailwindcss init
</span></span><span class="line"><span class="cl">pnpx shadcn-vue@latest init
</span></span></code></pre></div><p>Accept sensible defaults.</p>
<h2 id="step-2-configuring-nuxt">Step 2: Configuring Nuxt</h2>
<p>Ensure <code>nuxt.config.ts</code> is updated. Add the CSS file reference:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="c1">// ...existing code...
</span></span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineNuxtConfig</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...existing code...
</span></span></span><span class="line"><span class="cl">  <span class="nx">modules</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;shadcn-nuxt&#34;</span><span class="p">,</span> <span class="s2">&#34;@nuxt/icon&#34;</span><span class="p">,</span> <span class="s2">&#34;@nuxtjs/tailwindcss&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nx">css</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;~/assets/css/tailwind.css&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...existing code...
</span></span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Add shadcn-vue components.</p>
<pre tabindex="0"><code>pnpx shadcn-vue@latest add label button card input separator
</code></pre><h2 id="step-3-creating-the-document-uploader-component">Step 3: Creating the Document Uploader Component</h2>
<p>Create <code>DocumentUploader.vue</code> in the components folder to handle file uploads:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="c1">// filepath: /c:/dev/1p/nuxt/docformist/components/DocumentUploader.vue
</span></span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c">&lt;!--</span> <span class="p">...</span><span class="nx">existing</span> <span class="nx">code</span><span class="p">...</span> <span class="o">--&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">emit</span> <span class="o">=</span> <span class="nx">defineEmits</span><span class="p">([</span><span class="s2">&#34;file-selected&#34;</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">handleFileSelect</span> <span class="o">=</span> <span class="p">(</span><span class="nx">event</span><span class="o">:</span> <span class="nx">Event</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">file</span> <span class="o">=</span> <span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">target</span> <span class="nx">as</span> <span class="nx">HTMLInputElement</span><span class="p">).</span><span class="nx">files</span><span class="o">?</span><span class="p">.[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">file</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">emit</span><span class="p">(</span><span class="s2">&#34;file-selected&#34;</span><span class="p">,</span> <span class="nx">file</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">handleDrop</span> <span class="o">=</span> <span class="p">(</span><span class="nx">event</span><span class="o">:</span> <span class="nx">DragEvent</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">file</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">dataTransfer</span><span class="o">?</span><span class="p">.</span><span class="nx">files</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">file</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">emit</span><span class="p">(</span><span class="s2">&#34;file-selected&#34;</span><span class="p">,</span> <span class="nx">file</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h2 id="step-4-creating-the-document-viewer-component">Step 4: Creating the Document Viewer Component</h2>
<p>Create <code>DocumentViewer.vue</code> to preview the uploaded document:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="c1">// filepath: /c:/dev/1p/nuxt/docformist/components/DocumentViewer.vue
</span></span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c">&lt;!--</span> <span class="p">...</span><span class="nx">existing</span> <span class="nx">code</span><span class="p">...</span> <span class="o">--&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nx">defineProps</span><span class="o">&lt;</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">file</span><span class="o">:</span> <span class="nx">File</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="o">&gt;</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">fileUrl</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">&lt;</span><span class="nt">string</span> <span class="err">|</span> <span class="na">null</span><span class="p">&gt;(</span><span class="kc">null</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">isPDF</span> <span class="o">=</span> <span class="nx">computed</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="nx">props</span><span class="p">.</span><span class="nx">file</span><span class="p">.</span><span class="nx">type</span> <span class="o">===</span> <span class="s2">&#34;application/pdf&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">watch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="p">()</span> <span class="p">=&gt;</span> <span class="nx">props</span><span class="p">.</span><span class="nx">file</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nx">newFile</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">fileUrl</span><span class="p">.</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">URL</span><span class="p">.</span><span class="nx">revokeObjectURL</span><span class="p">(</span><span class="nx">fileUrl</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fileUrl</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">URL</span><span class="p">.</span><span class="nx">createObjectURL</span><span class="p">(</span><span class="nx">newFile</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">immediate</span><span class="o">:</span> <span class="kc">true</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">onBeforeUnmount</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">fileUrl</span><span class="p">.</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">URL</span><span class="p">.</span><span class="nx">revokeObjectURL</span><span class="p">(</span><span class="nx">fileUrl</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h2 id="step-5-creating-the-api-endpoint">Step 5: Creating the API Endpoint</h2>
<p>Create an API endpoint <code>analyze.post.ts</code> for document analysis with Azure Document Intelligence:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">DocumentIntelligence</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">getLongRunningPoller</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">isUnexpected</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@azure-rest/ai-document-intelligence&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">AzureKeyCredential</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@azure/core-auth&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">formidable</span> <span class="kr">from</span> <span class="s2">&#34;formidable&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">readFile</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;fs/promises&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineEventHandler</span><span class="p">(</span><span class="kr">async</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...existing code...
</span></span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><h2 id="step-6-building-the-main-page">Step 6: Building the Main Page</h2>
<p>Integrate the components and API in the main page <code>index.vue</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="c1">// filepath: /c:/dev/1p/nuxt/docformist/pages/index.vue
</span></span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c">&lt;!--</span> <span class="p">...</span><span class="nx">existing</span> <span class="nx">code</span><span class="p">...</span> <span class="o">--&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">selectedFile</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">&lt;</span><span class="nt">File</span> <span class="err">|</span> <span class="na">null</span><span class="p">&gt;(</span><span class="kc">null</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">extractedData</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">&lt;</span><span class="nt">Record</span><span class="p">&lt;</span><span class="nt">string</span><span class="err">,</span> <span class="na">any</span><span class="p">&gt;</span> <span class="o">|</span> <span class="kc">null</span><span class="o">&gt;</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">loading</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">selectedFields</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">&lt;</span><span class="nt">string</span><span class="err">[]</span><span class="p">&gt;([]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">handleFileSelect</span> <span class="o">=</span> <span class="p">(</span><span class="nx">file</span><span class="o">:</span> <span class="nx">File</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">selectedFile</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">file</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">extractedData</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">handleExtract</span> <span class="o">=</span> <span class="nx">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">selectedFields</span><span class="p">.</span><span class="nx">value</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;No fields selected&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">loading</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">formData</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">FormData</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">formData</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s2">&#34;file&#34;</span><span class="p">,</span> <span class="nx">selectedFile</span><span class="p">.</span><span class="nx">value</span><span class="o">!</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">formData</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s2">&#34;fields&#34;</span><span class="p">,</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">selectedFields</span><span class="p">.</span><span class="nx">value</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">fetch</span><span class="p">(</span><span class="s2">&#34;/api/analyze&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">method</span><span class="o">:</span> <span class="s2">&#34;POST&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">body</span><span class="o">:</span> <span class="nx">formData</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">response</span><span class="p">.</span><span class="nx">ok</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">&#34;Failed to analyze document&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">extractedData</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error analyzing document:&#34;</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// TODO: Show error toast
</span></span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">finally</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">loading</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h2 id="step-7-run-the-application">Step 7: Run the Application</h2>
<p>Start the development server:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pnpm dev
</span></span></code></pre></div><p>Visit <code>http://localhost:3000</code> to upload a document and see the results.</p>
<h2 id="conclusion">Conclusion</h2>
<p>That was a quick demo of how we build a document analysis / identification app using Azure Document Intelligence. Customize the application further to meet your needs.</p>
<p>Here&rsquo;s the Github repo - <a href="https://github.com/prashanth1k/docformist">https://github.com/prashanth1k/docformist</a>.</p>
<p>All of this was done within 2 hours - thanks to AI. The era of personal applications is here.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Identity in .NET API Makes Auth Easy</title>
      <link>https://techformist.com/2024-10-01-identity-dotnet-api-auth-made-easy/</link>
      <pubDate>Tue, 01 Oct 2024 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/2024-10-01-identity-dotnet-api-auth-made-easy/</guid>
      <description>&lt;p&gt;There was a time to be scared of the auth in ASP.NET. Identity really makes it easy.
But before delving any further, let&amp;rsquo;s keep the tradition alive by knowing the ancient Roman history of auth in ASP.NET.&lt;/p&gt;
&lt;h2 id=&#34;how-auth-was-done-earlier&#34;&gt;How Auth was done earlier?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Manual Token Generation: Developers manually created JWT tokens using libraries like System.IdentityModel.Tokens.Jwt and hardcoded key management.&lt;/li&gt;
&lt;li&gt;No Built-in User Management: Handling user registration, login, password hashing, and role management required custom code.&lt;/li&gt;
&lt;li&gt;Manual Claims Management: Claims (roles, permissions) were added to JWT tokens manually, increasing the risk of errors.&lt;/li&gt;
&lt;li&gt;Token Validation: Developers manually validated JWT tokens in each request, including signature, expiration, and claims validation.&lt;/li&gt;
&lt;li&gt;No Built-in Features for Role Management: Handling user roles and claims for authorization were complex&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s not uncommon to see code like this even today (there continue to be valid use cases, of course).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>There was a time to be scared of the auth in ASP.NET. Identity really makes it easy.
But before delving any further, let&rsquo;s keep the tradition alive by knowing the ancient Roman history of auth in ASP.NET.</p>
<h2 id="how-auth-was-done-earlier">How Auth was done earlier?</h2>
<ul>
<li>Manual Token Generation: Developers manually created JWT tokens using libraries like System.IdentityModel.Tokens.Jwt and hardcoded key management.</li>
<li>No Built-in User Management: Handling user registration, login, password hashing, and role management required custom code.</li>
<li>Manual Claims Management: Claims (roles, permissions) were added to JWT tokens manually, increasing the risk of errors.</li>
<li>Token Validation: Developers manually validated JWT tokens in each request, including signature, expiration, and claims validation.</li>
<li>No Built-in Features for Role Management: Handling user roles and claims for authorization were complex</li>
</ul>
<p>It&rsquo;s not uncommon to see code like this even today (there continue to be valid use cases, of course).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cs" data-lang="cs"><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">key</span> <span class="p">=</span> <span class="k">new</span> <span class="n">SymmetricSecurityKey</span><span class="p">(</span><span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="n">GetBytes</span><span class="p">(</span><span class="s">&#34;YourSecretKey&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">creds</span> <span class="p">=</span> <span class="k">new</span> <span class="n">SigningCredentials</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">SecurityAlgorithms</span><span class="p">.</span><span class="n">HmacSha256</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">claims</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">new</span> <span class="n">Claim</span><span class="p">(</span><span class="n">JwtRegisteredClaimNames</span><span class="p">.</span><span class="n">Sub</span><span class="p">,</span> <span class="s">&#34;username&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="k">new</span> <span class="n">Claim</span><span class="p">(</span><span class="n">JwtRegisteredClaimNames</span><span class="p">.</span><span class="n">Jti</span><span class="p">,</span> <span class="n">Guid</span><span class="p">.</span><span class="n">NewGuid</span><span class="p">().</span><span class="n">ToString</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">token</span> <span class="p">=</span> <span class="k">new</span> <span class="n">JwtSecurityToken</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">issuer</span><span class="p">:</span> <span class="s">&#34;yourdomain.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">audience</span><span class="p">:</span> <span class="s">&#34;yourdomain.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">claims</span><span class="p">:</span> <span class="n">claims</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">expires</span><span class="p">:</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">.</span><span class="n">AddMinutes</span><span class="p">(</span><span class="m">30</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">signingCredentials</span><span class="p">:</span> <span class="n">creds</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// create token</span>
</span></span><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">tokenString</span> <span class="p">=</span> <span class="k">new</span> <span class="n">JwtSecurityTokenHandler</span><span class="p">().</span><span class="n">WriteToken</span><span class="p">(</span><span class="n">token</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// time passes..</span>
</span></span><span class="line"><span class="cl"><span class="c1">//</span>
</span></span><span class="line"><span class="cl"><span class="c1">// time now to validate in another part of the code..</span>
</span></span><span class="line"><span class="cl"><span class="c1">// validate token</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="p">.</span><span class="n">AddAuthentication</span><span class="p">(</span><span class="n">options</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">options</span><span class="p">.</span><span class="n">DefaultAuthenticateScheme</span> <span class="p">=</span> <span class="n">JwtBearerDefaults</span><span class="p">.</span><span class="n">AuthenticationScheme</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">options</span><span class="p">.</span><span class="n">DefaultChallengeScheme</span> <span class="p">=</span> <span class="n">JwtBearerDefaults</span><span class="p">.</span><span class="n">AuthenticationScheme</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">AddJwtBearer</span><span class="p">(</span><span class="n">options</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">options</span><span class="p">.</span><span class="n">TokenValidationParameters</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TokenValidationParameters</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">ValidateIssuer</span> <span class="p">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">ValidateAudience</span> <span class="p">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">ValidateLifetime</span> <span class="p">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">ValidateIssuerSigningKey</span> <span class="p">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">ValidIssuer</span> <span class="p">=</span> <span class="s">&#34;yourdomain.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">ValidAudience</span> <span class="p">=</span> <span class="s">&#34;yourdomain.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">IssuerSigningKey</span> <span class="p">=</span> <span class="k">new</span> <span class="n">SymmetricSecurityKey</span><span class="p">(</span><span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="n">GetBytes</span><span class="p">(</span><span class="s">&#34;YourSecretKey&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span></code></pre></div><h2 id="roll-in-identity">Roll-in Identity</h2>
<ul>
<li>Built-in User and Role Management
<ul>
<li>Identity provides a complete user management system with built-in support for user registration, login, password hashing, and role management.</li>
<li>No need to manually store user credentials or roles in the database; Identity handles it through its own entity models (e.g., IdentityUser, IdentityRole).</li>
</ul>
</li>
<li>Automatic Token Generation and Validation
<ul>
<li>Identity integrates easily with JWT authentication, automatically handling token generation, validation, and expiration management.</li>
<li>Developers no longer need to manually create or validate tokens using JwtSecurityTokenHandler.</li>
</ul>
</li>
<li>Claims and Role Management: Manage claims and roles through simple, high-level APIs (UserManager, RoleManager), which abstract away the complexity of managing claims in the token payload manually.</li>
<li>Out-of-the-Box (&ldquo;OOB&rdquo;) Security
<ul>
<li>OOB industry-standard security practices such as password hashing (with customizable password policies) and token expiration management - reduce security risks.</li>
<li>Built-in support for multi-factor authentication (MFA), account lockout, and password recovery without custom implementations.</li>
</ul>
</li>
<li>Simplified Middleware Integration
<ul>
<li>Easily integrated into the ASP.NET middleware pipeline - no need to manually configure authentication schemes or token validation parameters.</li>
<li>Built-in Identity middleware automatically manages authentication cookies and tokens.</li>
</ul>
</li>
<li>Flexible Data Store: Work with multiple data stores (SQL Server, MySQL, etc.) by default</li>
<li>Support for External Authentication Providers: Integrating OAuth providers like Google, Facebook, and Microsoft is simplified</li>
</ul>
<h2 id="identity-in-action-a-simple-demo">Identity in Action: A Simple Demo</h2>
<p>Create a new project..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">dotnet new webapi -n dotnet-api-auth-demo
</span></span></code></pre></div><p>Add the below packages..</p>
<ul>
<li>Microsoft.EntityFrameworkCore.Sqlite</li>
<li>Microsoft.EntityFrameworkCore.Design</li>
<li>Microsoft.EntityFrameworkCore.Tools</li>
<li>Microsoft.AspNetCore.Identity.EntityFrameworkCore</li>
</ul>
<p>The first three are for Entity Framework Core and for using a SQLite database. The last one is for Identity.</p>
<p>Create the <code>ApplicationDbContext</code> class like as God intended. However, inherit from <code>IdentityDbContext</code> this time.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cs" data-lang="cs"><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Identity</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Identity.EntityFrameworkCore</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Microsoft.EntityFrameworkCore</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">public</span> <span class="k">class</span> <span class="nc">ApplicationDbContext</span> <span class="p">:</span> <span class="n">IdentityDbContext</span><span class="p">&lt;</span><span class="n">IdentityUser</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">public</span> <span class="n">ApplicationDbContext</span><span class="p">(</span><span class="n">DbContextOptions</span><span class="p">&lt;</span><span class="n">ApplicationDbContext</span><span class="p">&gt;</span> <span class="n">options</span><span class="p">)</span> <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>IdentityDbContext</code> will add magic that we are about to experience.</p>
<p>Add three lines of code in <code>Program.cs</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cs" data-lang="cs"><span class="line"><span class="cl"><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddAuthorization</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddIdentityApiEndpoints</span><span class="p">&lt;</span><span class="n">IdentityUser</span><span class="p">&gt;().</span><span class="n">AddEntityFrameworkStores</span><span class="p">&lt;</span><span class="n">ApplicationDbContext</span><span class="p">&gt;();</span>
</span></span><span class="line"><span class="cl"><span class="c1">// add the above lines before initializing `app`</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="n">Build</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// add the below line after `app` is initialized</span>
</span></span><span class="line"><span class="cl"><span class="n">app</span><span class="p">.</span><span class="n">MapIdentityApi</span><span class="p">&lt;</span><span class="n">IdentityUser</span><span class="p">&gt;();</span>
</span></span></code></pre></div><ul>
<li><code>AddEntityFrameworkStores</code> shows which database to use. In this case, we are using SQLite and using the main <code>ApplicationDbContext</code> itself. We could have used a different auth database as easily.</li>
<li><code>MapIdentityApi</code> automatically adds the necessary routes for Identity.</li>
</ul>
<p>Since we have no other endpoints, add auth to the default <code>weatherforecast</code> endpoint using <code>RequireAuthorization()</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cs" data-lang="cs"><span class="line"><span class="cl"><span class="n">app</span><span class="p">.</span><span class="n">MapGet</span><span class="p">(</span><span class="s">&#34;/weatherforecast&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">var</span> <span class="n">forecast</span> <span class="p">=</span> <span class="n">Enumerable</span><span class="p">.</span><span class="n">Range</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">5</span><span class="p">).</span><span class="n">Select</span><span class="p">(</span><span class="n">index</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="k">new</span> <span class="n">WeatherForecast</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">DateOnly</span><span class="p">.</span><span class="n">FromDateTime</span><span class="p">(</span><span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">.</span><span class="n">AddDays</span><span class="p">(</span><span class="n">index</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">            <span class="n">Random</span><span class="p">.</span><span class="n">Shared</span><span class="p">.</span><span class="n">Next</span><span class="p">(-</span><span class="m">20</span><span class="p">,</span> <span class="m">55</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="n">summaries</span><span class="p">[</span><span class="n">Random</span><span class="p">.</span><span class="n">Shared</span><span class="p">.</span><span class="n">Next</span><span class="p">(</span><span class="n">summaries</span><span class="p">.</span><span class="n">Length</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">        <span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="n">ToArray</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">forecast</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="n">WithName</span><span class="p">(</span><span class="s">&#34;GetWeatherForecast&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="n">WithOpenApi</span><span class="p">().</span><span class="n">RequireAuthorization</span><span class="p">();</span>
</span></span></code></pre></div><p>Do a build to ensure there are no errors.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">dotnet build
</span></span></code></pre></div><p>Migrate the database.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">dotnet ef migrations add InitAuth -o Data/Migrations
</span></span><span class="line"><span class="cl">dotnet ef database update
</span></span></code></pre></div><p>Run the application.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">dotnet run
</span></span></code></pre></div><p>Navigate to <code>http://localhost:5001/swagger/index.html</code> to see the Identity endpoints.</p>
<p><img loading="lazy" src="/2024/swagger-dotnet-identity-endpoints.png" type="" alt="swagger-dotnet-identity-endpoints"  /></p>
<p>You can test the auth endpoints using Swagger, or as I prefer - Insomnia/Postman REST clients.</p>
<p>First, do a GET to <code>http://localhost:5001/weatherforecast</code> to see a 401 Unauthorized response.</p>
<p><img loading="lazy" src="/2024/unauthorized-identity-endpoint.png" type="" alt="unauthorized-identity-endpoints"  /></p>
<p>Now, call the <code>register</code> to create a user, and subsequently, the <code>login</code> endpoint to get a token.</p>
<p>POST http://localhost:5001/register</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;a1@a.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;Pass@123&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>POST http://localhost:5001/login</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;a1@a.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;Pass@123&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You should get the token response.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;tokenType&#34;</span><span class="p">:</span> <span class="s2">&#34;Bearer&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;accessToken&#34;</span><span class="p">:</span> <span class="s2">&#34;CfDJ8AcfSlDrZbhNlphsDvuO8gDgQty5M...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;expiresIn&#34;</span><span class="p">:</span> <span class="mi">3600</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;refreshToken&#34;</span><span class="p">:</span> <span class="s2">&#34;CfDJ8AcfSlDrZbhNlphsDvuO8gD60O...&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Use the access token to call the <code>weatherforecast</code> endpoint and see the glorious response.</p>
<p><img loading="lazy" src="/2024/identity-asp-dotnet-token-api-call.png" type="" alt="identity-asp-dotnet-token-api-call"  /></p>
<p>We have just scratched the surface of Identity in .NET. There is a lot more to explore, including:</p>
<ul>
<li>Account lockout/ recovery</li>
<li>Password policies</li>
<li>Claims and roles management</li>
<li>Customizing Identity</li>
<li>Using external providers</li>
<li>Role-based authorization</li>
<li>Multi-factor authentication</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>Check out the full code on <a href="https://github.com/techformist/dotnet-api-auth-demo/">GitHub</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Setting up development environment for Laravel</title>
      <link>https://techformist.com/setup-dev-environment-laravel/</link>
      <pubDate>Mon, 15 Jul 2024 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/setup-dev-environment-laravel/</guid>
      <description>&lt;p&gt;Laravel is cool and all, but does not quite provide the &amp;ldquo;out of the box&amp;rdquo; dev experience as ASP.NET or, gasp, Typescript.&lt;/p&gt;
&lt;p&gt;Let us change that by using a few good editor tools and packages.&lt;/p&gt;
&lt;h2 id=&#34;php-intelephense-extension&#34;&gt;PHP Intelephense extension&lt;/h2&gt;
&lt;p&gt;I use VSCode and there is no better auto completion than &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client&#34;&gt;PHP Intelephense&lt;/a&gt;. It is fast, reasonably accurate and provides more than few options for playing around the code.&lt;/p&gt;
&lt;h2 id=&#34;laravel-extra-intellisense-extension&#34;&gt;Laravel Extra Intellisense extension&lt;/h2&gt;
&lt;p&gt;Install &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=amiralizadeh9480.laravel-extra-intellisense&#34;&gt;Laravel Extra Intellisense&lt;/a&gt; extension for -&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Laravel is cool and all, but does not quite provide the &ldquo;out of the box&rdquo; dev experience as ASP.NET or, gasp, Typescript.</p>
<p>Let us change that by using a few good editor tools and packages.</p>
<h2 id="php-intelephense-extension">PHP Intelephense extension</h2>
<p>I use VSCode and there is no better auto completion than <a href="https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client">PHP Intelephense</a>. It is fast, reasonably accurate and provides more than few options for playing around the code.</p>
<h2 id="laravel-extra-intellisense-extension">Laravel Extra Intellisense extension</h2>
<p>Install <a href="https://marketplace.visualstudio.com/items?itemName=amiralizadeh9480.laravel-extra-intellisense">Laravel Extra Intellisense</a> extension for -</p>
<ul>
<li>Route names and parameters</li>
<li>Suggestions in middlewares</li>
<li>Views</li>
</ul>
<h2 id="laravel-snippets-extension">Laravel Snippets extension</h2>
<p>Install <a href="https://marketplace.visualstudio.com/items?itemName=onecentlin.laravel5-snippets">Laravel Snippets</a> extension for Laravel snippets.</p>
<h2 id="laravel-blade-snippets-extension">Laravel Blade Snippets extension</h2>
<p>Install <a href="https://marketplace.visualstudio.com/items?itemName=onecentlin.laravel-blade">Laravel Blade Snippets</a> extension for Laravel Blade snippets.</p>
<h2 id="laravel-ide-helper-package">Laravel IDE Helper package</h2>
<p>Install [Laravel IDE Helper] <a href="https://github.com/barryvdh/laravel-ide-helper">https://github.com/barryvdh/laravel-ide-helper</a> for better auto completion in Laravel.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">composer require --dev barryvdh/laravel-ide-helper
</span></span></code></pre></div><h2 id="address-auto-complete-annoyances-for-laravel-and-php-in-vscode">Address Auto Complete Annoyances for Laravel and PHP in VSCode</h2>
<p>When you open Laravel code, you will see autocomplete suggestions, but you will see a lot more than desired. The suggestions -</p>
<ul>
<li>lacks context</li>
<li>has generic suggestions</li>
</ul>
<p>There are a few things you can do -</p>
<ul>
<li><code>Ctrl + Shift + p</code> &gt; Go to <code>Preferences &gt; Open Settings (UI)</code>. Search for <code>editor.snippetSuggestions</code> and set it to <code>bottom</code></li>
<li>Next, search for <code>php.suggest.basic</code> and set it to <code>false</code></li>
</ul>
<h2 id="set-alias-for-php-artisan">Set Alias for <code>php artisan</code></h2>
<p>You will be typing <code>php artisan</code> at least a hundred times a day - better to save all the calories by setting an alias or a shortcut.</p>
<p>In Powershell, open your default profile -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">notepad</span> <span class="nv">$Profile</span>
</span></span></code></pre></div><p>Enter the below to set alias to <code>pa</code>-.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="kd">function</span><span class="w"> </span><span class="nb">pa</span> <span class="p">{</span> <span class="n">php</span> <span class="n">artisan</span> <span class="nv">$args</span> <span class="p">}</span>
</span></span></code></pre></div><p>If you use <code>wsl</code>, you would be using <code>bash</code> or <code>zsh</code>. Just edit your <code>.bashrc</code> or <code>.zshrc</code> file to add an alias.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">vim ~/.bashrc
</span></span><span class="line"><span class="cl"><span class="c1"># .. or</span>
</span></span><span class="line"><span class="cl"><span class="c1"># vim ~/.zshrc</span>
</span></span></code></pre></div><p>Add the below line -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">pa</span><span class="o">=</span><span class="s1">&#39;php artisan&#39;</span>
</span></span></code></pre></div><p>Now you can type <code>pa</code> instead of <code>php artisan</code> with how many ever arguments and it should work seamlessly.</p>
<h2 id="use-laravel-debugbar">Use Laravel debugbar.</h2>
<p>Install the debugbar in your Laravel project.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">composer require barryvdh/laravel-debugbar --dev
</span></span></code></pre></div><p>Ensure your <code>.env</code> file has <code>APP_DEBUG=true</code> and <code>APP_ENV=local</code>.</p>
<p>Start your Laravel server and you should see the debugbar at the bottom of the page.
See the <a href="https://github.com/barryvdh/laravel-debugbar">documentation</a> for more options.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Manage SVG Icons in Nuxt</title>
      <link>https://techformist.com/manage-svg-icons-images/</link>
      <pubDate>Sat, 20 Jan 2024 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/manage-svg-icons-images/</guid>
      <description>&lt;p&gt;Gone are the days when we depended on styling libraries to provide fast access to icons and go through untold suffering due to payload size, performance issues etc.. With the advent of SVG, we can use icons from a variety of sources. We will see how to do just that.&lt;/p&gt;
&lt;p&gt;SVG images have the advantage of -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Being vector based, so it can be scaled to any size&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Is just text&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Can be styled&lt;/li&gt;
&lt;li&gt;Small in size!&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;using-svg-icons-why-do-that&#34;&gt;Using SVG Icons: Why do that?&lt;/h1&gt;
&lt;p&gt;You see in the old west, we used to have icons like this -&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Gone are the days when we depended on styling libraries to provide fast access to icons and go through untold suffering due to payload size, performance issues etc.. With the advent of SVG, we can use icons from a variety of sources. We will see how to do just that.</p>
<p>SVG images have the advantage of -</p>
<ol>
<li>Being vector based, so it can be scaled to any size</li>
<li>&ldquo;Is just text&rdquo;</li>
<li>Can be styled</li>
<li>Small in size!</li>
</ol>
<h1 id="using-svg-icons-why-do-that">Using SVG Icons: Why do that?</h1>
<p>You see in the old west, we used to have icons like this -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">i</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;fa fa-user&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">i</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>With libraries like Vuetify, the above statement looks like this -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">v-icon</span><span class="p">&gt;</span>mdi-account<span class="p">&lt;/</span><span class="nt">v-icon</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The code is easy to use, but you have to depend on the library to provide you the icon. You are also dependent on the library for applying changes to color, size, and probably even for the freaking dark mode.</p>
<p>With SVG, you can use the icon from any source, and apply any styling you want.</p>
<h1 id="using-svg-icons">Using SVG Icons</h1>
<p>Getting started with SVG icons is pretty easy.</p>
<ol>
<li>Identify the SVG</li>
<li>Copy the SVG and paste it directly in a Vue component (OR) Save the SVG in a file and import it in a Vue component</li>
</ol>
<p>As always the modern web makes using SVG icons trivial. 😜</p>
<h2 id="method-1-use-direct-links-to-icons">Method 1: Use direct links to icons</h2>
<p>You can use the SVG icon directly in your Vue component.</p>
<p>An example using <a href="https://icongr.am">icongram</a> ie below.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">img</span>
</span></span><span class="line"><span class="cl">    <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://icongr.am/material/airplane-takeoff.svg?size=128&amp;color=4023d1&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The parameters are self-explanatory.
You can see the image, change the size / color and see how URLs are constructed for various icons from the <a href="https://icongr.am/material">icongram</a> website (linked to Material icons, it can be anything really).</p>
<p>Others doing the same fun stuff -</p>
<ul>
<li><a href="https://ionic.io/ionicons">Ionicons</a></li>
<li><a href="https://iconify.design/">Iconify</a></li>
<li><a href="https://css.gg/add">CSS icons</a> - icons are also available as SVG</li>
</ul>
<p>There is an easier way to use the icons directly.
Use something like a <a href="https://nuxt.com/modules/icon">NuxtIcon</a> and set it up as a plugin.</p>
<p>And, voila -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c">&lt;!-- ... --&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">Icon</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;uil:github&#34;</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;black&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c">&lt;!-- ... --&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><h2 id="method-2-download-and-use-icons">Method 2: Download and use icons</h2>
<p>Any of the sites outlined in the previous section allow you to download the SVG icon. Just save the file in your local public / assets folder and use it in your Vue component.</p>
<p>More example sites providing SVG downloads -</p>
<ul>
<li><a href="https://heroicons.com/">Heroicons</a></li>
<li><a href="https://feathericons.com/">Feather</a></li>
<li><a href="https://www.svgrepo.com/">SVG Repo</a></li>
<li><a href="https://material.io/resources/icons/?style=baseline">Material</a></li>
</ul>
<p>Once the images are available in your project, using them should be as simple as -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;images/airplane-takeoff.svg&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Another way to do this (probably more efficient) is to create a pass through Vue component that renders the SVG. This way you can play around with the size/colors etc. in a more uniform way.</p>
<p>Example Vue component to render a given SVG -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">svg</span>
</span></span><span class="line"><span class="cl">    <span class="na">:viewBox</span><span class="o">=</span><span class="s">&#34;viewBox&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns</span><span class="o">=</span><span class="s">&#34;http://www.w3.org/2000/svg&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">:width</span><span class="o">=</span><span class="s">&#34;width&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">:height</span><span class="o">=</span><span class="s">&#34;height&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">class</span><span class="o">=</span><span class="s">&#34;svg-icon&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&gt;&lt;/</span><span class="nt">svg</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="p">{</span> <span class="nx">defineProps</span><span class="p">,</span> <span class="nx">computed</span><span class="p">,</span> <span class="nx">Component</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">defineProps</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">viewBox</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;0 0 24 24&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">width</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;24&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">height</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;24&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Invoke the component as any other Vue component. This approach has the advantage of consistency in the way you render the SVG icons - e.g., use similar sizes, color, etc.</p>
<h2 id="method-3-just-paste-the-svg">Method 3: Just paste the SVG</h2>
<p>As an alternative to downloading icons, just paste the SVG in your Vue component.</p>
<p>For e.g. -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">svg</span>
</span></span><span class="line"><span class="cl">  <span class="na">data-slot</span><span class="o">=</span><span class="s">&#34;icon&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">fill</span><span class="o">=</span><span class="s">&#34;none&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">stroke-width</span><span class="o">=</span><span class="s">&#34;1.5&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">stroke</span><span class="o">=</span><span class="s">&#34;currentColor&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">viewBox</span><span class="o">=</span><span class="s">&#34;0 0 24 24&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">xmlns</span><span class="o">=</span><span class="s">&#34;http://www.w3.org/2000/svg&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">aria-hidden</span><span class="o">=</span><span class="s">&#34;true&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">path</span>
</span></span><span class="line"><span class="cl">    <span class="na">stroke-linecap</span><span class="o">=</span><span class="s">&#34;round&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">stroke-linejoin</span><span class="o">=</span><span class="s">&#34;round&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">d</span><span class="o">=</span><span class="s">&#34;m20.25 7.5-.625 10.632a2.25 2.25 0 0 1-2.247 2.118H6.622a2.25 2.25 0 0 1-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&gt;&lt;/</span><span class="nt">path</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">svg</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>As outlined in the previous section, you can also paste the SVG in a separate Vue component and use that component in your project.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Use Dynamic Images in Nuxt</title>
      <link>https://techformist.com/dynamic-images-nuxt/</link>
      <pubDate>Sun, 14 Jan 2024 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/dynamic-images-nuxt/</guid>
      <description>&lt;p&gt;First, let me clarify what I mean by &amp;ldquo;dynamic image&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Imagine the below situations -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You are rendering a list of products and their images. The image may be stored in local folder or coming in from S3/comparable infrastructure&lt;/li&gt;
&lt;li&gt;You want to change image / make image interactive. For e.g., users select fruits and the corresponding fruit image gets added in a basket&lt;/li&gt;
&lt;li&gt;You want to preprocess the image in some shape and form at runtime. For e.g., watermarking the image&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;rendering-an-image&#34;&gt;Rendering an Image&lt;/h1&gt;
&lt;p&gt;Typically, you render images with -&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>First, let me clarify what I mean by &ldquo;dynamic image&rdquo;.</p>
<p>Imagine the below situations -</p>
<ol>
<li>You are rendering a list of products and their images. The image may be stored in local folder or coming in from S3/comparable infrastructure</li>
<li>You want to change image / make image interactive. For e.g., users select fruits and the corresponding fruit image gets added in a basket</li>
<li>You want to preprocess the image in some shape and form at runtime. For e.g., watermarking the image</li>
</ol>
<h1 id="rendering-an-image">Rendering an Image</h1>
<p>Typically, you render images with -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://example.com/images/apple.png&#34;</span> <span class="p">/&gt;</span>
</span></span></code></pre></div><p>This assumes that <code>images/apple.png</code> exists in <code>public</code> folder or available publicly.</p>
<h1 id="rendering-a-dynamic-image">Rendering a Dynamic Image</h1>
<p>While providing images from a public location is great (&amp; should be preferred), sometimes we need the images to be &ldquo;processed&rdquo; during build, or make it &ldquo;dynamic&rdquo; in some way or the other (e.g., watermarked on the go). I typically use <code>assets/images</code> for images that need not be publicly exposed - but any folder should work well.</p>
<p>Pointing images to the <code>assets</code> or some other folder is straight-forward in Nuxt2.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">template</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">img</span> <span class="o">:</span><span class="nx">src</span><span class="o">=</span><span class="s2">&#34;require(`~/assets/images/${apple.image}`)&#34;</span><span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">/template&gt;</span>
</span></span></code></pre></div><p><code>require</code> works since Nuxt2 uses Webpack, which will get the import image dynamically and make it available for rendering on the page.</p>
<p>Nuxt3 and Vite do not work in the same way. There is more than one way to render dynamic images in Nuxt 3.</p>
<h2 id="1-using-glob">1. Using <code>glob</code></h2>
<p>As mentioned <a href="https://github.com/nuxt/nuxt/issues/14766/#issuecomment-1397365205">here</a>, you can use <code>glob</code> to feed the right input to the image -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">img</span> <span class="na">:src</span><span class="o">=</span><span class="s">&#34;fruit_name&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="p">{</span> <span class="nx">filename</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;pathe/utils&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">glob</span> <span class="o">=</span> <span class="kr">import</span><span class="p">.</span><span class="nx">meta</span><span class="p">.</span><span class="nx">glob</span><span class="p">(</span><span class="s1">&#39;~/assets/images/*.png&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">eager</span><span class="o">:</span> <span class="kc">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">images</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">fromEntries</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Object</span><span class="p">.</span><span class="nx">entries</span><span class="p">(</span><span class="nx">glob</span><span class="p">).</span><span class="nx">map</span><span class="p">(([</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">])</span> <span class="p">=&gt;</span> <span class="p">[</span><span class="nx">filename</span><span class="p">(</span><span class="nx">key</span><span class="p">),</span> <span class="nx">value</span><span class="p">.</span><span class="k">default</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">fruit_name</span> <span class="o">=</span> <span class="s1">&#39;apple&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>This option works, but is tiring to look at. There may also be performance issues if there are large number of images.</p>
<p>Note that the issue described here exists for local images. Remote images provide public URLs that can be rendered directly.</p>
<h4 id="2-use-vite-require-plugin">2. Use Vite require plugin</h4>
<p>Bring the usability of Webpack <code>require</code> to Vite using <a href="https://www.npmjs.com/package/vite-plugin-require">vite-plugin-require</a> plugin.</p>
<p>Install the plugin -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install -D vite-require-context
</span></span></code></pre></div><p>Change <code>vite.config.js</code> to add the plugin -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">vitePluginRequire</span> <span class="nx">from</span> <span class="s2">&#34;vite-plugin-require&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="nx">plugins</span><span class="o">:</span> <span class="p">[</span><span class="nx">vitePluginRequire</span><span class="p">()],</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>Nuxt (specifically <code>NuxtImg</code>) provides a helpful <code>useImage</code> composable.</p>
<p>You should now be able to do -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">NuxtImg</span> <span class="na">:src</span><span class="o">=</span><span class="s">&#34;require(fruit_image_url)&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">fruit_image_url</span> <span class="o">=</span> <span class="s2">&#34;~/assets/images/apple.png&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h1 id="conclusion">Conclusion</h1>
<p>While both options work, do note that -</p>
<ol>
<li>Use <code>public</code> for images that will not change. This option is easier and likely to be more performant</li>
<li>Else, use one of the above options based on your use case</li>
</ol>
]]></content:encoded>
    </item>
    
    <item>
      <title>Create a Blog with Astro</title>
      <link>https://techformist.com/create-blog-astro/</link>
      <pubDate>Sun, 24 Dec 2023 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/create-blog-astro/</guid>
      <description>&lt;p&gt;With Astro 4 released recently, I wanted to check out what is going on in that part of the world. What better way to do that than to create a blog using Astro.. or so I thought.&lt;/p&gt;
&lt;p&gt;I had not been quite sold on Astro for the stuff that I typically do.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I tend to focus more on SPA-like apps. Am a fan of Vue, of course&lt;/li&gt;
&lt;li&gt;Hugo is more than enough as SSG. While I absolutely have no clue what I do there 90% of the time (or is it more like 99%?), it just works and works blazingly fast&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Being a stickler to &amp;ldquo;try everything that is recommended on Twitter&amp;rdquo;, I could not continue the state of not jumpin on the Astro train for long. So, here we are.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>With Astro 4 released recently, I wanted to check out what is going on in that part of the world. What better way to do that than to create a blog using Astro.. or so I thought.</p>
<p>I had not been quite sold on Astro for the stuff that I typically do.</p>
<ul>
<li>I tend to focus more on SPA-like apps. Am a fan of Vue, of course</li>
<li>Hugo is more than enough as SSG. While I absolutely have no clue what I do there 90% of the time (or is it more like 99%?), it just works and works blazingly fast</li>
</ul>
<p>Being a stickler to &ldquo;try everything that is recommended on Twitter&rdquo;, I could not continue the state of not jumpin on the Astro train for long. So, here we are.</p>
<h2 id="what-is-astro">What is Astro?</h2>
<p>The official <a href="https://astro.build/">astro.build</a> website says:</p>
<blockquote>
<p>The web framework for content-driven websites.</p>
</blockquote>
<p>The categories listed out there include -</p>
<ul>
<li>Marketing &amp; other content sites</li>
<li>Blogs</li>
<li>eCommerce</li>
<li>Portfolios</li>
<li>Documentation (not featured, I see this as a good thing)</li>
</ul>
<p>Astro is not the typical SPA, MPA or SSG.</p>
<p>You use Astro to -</p>
<ul>
<li>Build your app in components and connect all of them</li>
<li>Deliver pages to client with no or minimal JS</li>
<li>Use your favorite framework (React, Vue, Svelte, Preact, etc) for SSR or for interactivity</li>
</ul>
<p>In terms of how all of that comes together -</p>
<ul>
<li>Astro creates static pages for static or dynamic routes</li>
<li>Astro components and pages, as well as any of the components of the frameworks you use, are compiled to static pages. Addition of different frameworks in different pages or even on the same page does not necessarily mean performance impact .. if everything is server rendered</li>
<li>Client interactivity can be with any framework of your choice, or with JS</li>
<li>Get content from Markdown etc. or from external sites</li>
<li>Astro provides many features (e.g. vue transitions, routing, image optimization, etc.) out of the box</li>
</ul>
<p>Focus on developer experience and content sites means there are ** a lot of ** amazing features -</p>
<ul>
<li><a href="https://astro.build/themes/">Free and paid themes</a></li>
<li><a href="https://astro.build/integrations/">Many integrations</a>. Includes integrations to CMS (of course), plugins to speedup deployment on AWS (e.g. SST)</li>
<li><a href="https://docs.astro.build/en/guides/backend/">Integrations with backend services</a> like Turso, Supabase, etc.</li>
</ul>
<p>The below image on performance speaks volumes.</p>
<p><img loading="lazy" src="/2023/astro-performance.png" type="" alt="astro performance"  /></p>
<h2 id="create-a-blog-using-astro">Create a blog using Astro</h2>
<p>Let us get back on the topic at hand.</p>
<p>Create a blog by issuing the below command -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pnpm create astro@latest
</span></span></code></pre></div><p>Select the right options thereon. I chose the <code>blog template</code> with some dummy content for demo purposes.</p>
<p><img loading="lazy" src="/2023/astro-create.png" type="" alt="astro create"  /></p>
<p>Run the app -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pnpm dev
</span></span></code></pre></div><p>And, voila..</p>
<p><img loading="lazy" src="/2023/astro-blog-template-home.png" type="" alt="astro-blog-template-home"  /></p>
<p>If I was honest, there is nothing more to say. But, I will continue blabbering on since creation of a blog with just one command is just crazy.</p>
<h2 id="what-have-we-created-so-far">What have we created so far?</h2>
<p>The structure of the application is inline with the expectations of a typical JS app -</p>
<ol>
<li><code>public</code> directory with all static content</li>
<li><code>src</code> directory with all the code</li>
<li><code>src/page</code> directory with all pages. You will see a curios markdown like header in the page that includes Javascript code. This is the <a href="https://docs.astro.build/core-concepts/frontmatter/">frontmatter</a> that is used to import components, data, etc. into the page. For e.g., see <code>pages/index.astro</code> -
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">import BaseHead from &#39;../components/BaseHead.astro&#39;;
</span></span><span class="line"><span class="cl">import Header from &#39;../components/Header.astro&#39;;
</span></span><span class="line"><span class="cl">import { SITE_TITLE, SITE_DESCRIPTION } from &#39;../consts&#39;;
</span></span><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">&lt;!doctype html&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">BaseHead</span> <span class="na">title</span><span class="o">=</span><span class="s">{SITE_TITLE}</span> <span class="na">description</span><span class="o">=</span><span class="s">{SITE_DESCRIPTION}</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">Header</span> <span class="na">title</span><span class="o">=</span><span class="s">{SITE_TITLE}</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>🧑‍🚀 Hello, Astronaut!<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                Welcome to the official <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://astro.build/&#34;</span><span class="p">&gt;</span>Astro<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span> blog starter template. This
</span></span><span class="line"><span class="cl">                template serves as a lightweight, minimally-styled starting point for anyone looking to
</span></span><span class="line"><span class="cl">                build a personal website, blog, or portfolio with Astro.
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="c">&lt;!-- snip --&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div></li>
<li>Components that are imported in pages (or within other components) in <code>src/components</code></li>
<li><code>src/layouts</code> and <code>src/styles</code> directories that supplement pages &amp; components</li>
<li><code>src/content</code> directory with all content. Static content is seamlessly integrated into the app. For e.g., see <code>pages/blog/index.astro</code> -
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">import Footer from &#39;../../components/Footer.astro&#39;;
</span></span><span class="line"><span class="cl">import { SITE_TITLE, SITE_DESCRIPTION } from &#39;../../consts&#39;;
</span></span><span class="line"><span class="cl">import { getCollection } from &#39;astro:content&#39;;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">const posts = (await getCollection(&#39;blog&#39;)).sort(
</span></span><span class="line"><span class="cl">    (a, b) =&gt; a.data.pubDate.valueOf() - b.data.pubDate.valueOf()
</span></span><span class="line"><span class="cl">);
</span></span><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- lot of lines --&gt;</span>
</span></span><span class="line"><span class="cl">posts.map((post) =&gt; (
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">{`/blog/${post.slug}/`}</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                            <span class="p">&lt;</span><span class="nt">img</span> <span class="na">width</span><span class="o">=</span><span class="s">{720}</span> <span class="na">height</span><span class="o">=</span><span class="s">{360}</span> <span class="na">src</span><span class="o">=</span><span class="s">{post.data.heroImage}</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">                            <span class="p">&lt;</span><span class="nt">h4</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span>{post.data.title}<span class="p">&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                            <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;date&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                                <span class="p">&lt;</span><span class="nt">FormattedDate</span> <span class="na">date</span><span class="o">=</span><span class="s">{post.data.pubDate}</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">                            <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">					))
</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- more lines --&gt;</span>
</span></span></code></pre></div></li>
<li>Seamless styling scoped to the components or applied globally</li>
</ol>
<p>Gotta say, I love the -
- 📄simplicity
- 🧩component architecture that just focuses on what is needed - no fluff</p>
<p>Remember all of this came with the template, I have not done anything yet.</p>
<h2 id="level-up-the-blog">Level-up the blog</h2>
<h4 id="add-a-sitemap">Add a sitemap</h4>
<p>Add a sitemap with a <a href="https://docs.astro.build/en/guides/integrations-guide/sitemap/">plugin</a>. A single line configuration should be good in most cases-</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="c1">// astro.config.mjs
</span></span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineConfig</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="nx">site</span><span class="o">:</span> <span class="s1">&#39;https://awesomesite.club&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">integrations</span><span class="o">:</span> <span class="p">[</span><span class="nx">sitemap</span><span class="p">()],</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span></code></pre></div><h4 id="embed-videos-tweets-etc-in-the-blog">Embed videos, tweets, etc. in the blog</h4>
<p>Use one of the many plugins (e.g., <a href="https://github.com/delucis/astro-embed/tree/main/packages/astro-embed#readme">astro-embed</a>) -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-md" data-lang="md"><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl"><span class="gh"># src/content/examples/page.mdx
</span></span></span><span class="line"><span class="cl">title: My MDX page with embed components
</span></span><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">import { Tweet, Vimeo, YouTube } from &#39;astro-embed&#39;;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Embed a tweet <span class="ge">_in Markdown_</span>!
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">&lt;Tweet id=&#34;https://twitter.com/astrodotbuild&#34; /&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">&lt;YouTube id=&#34;https://youtu.be/gxBkghlglTg&#34; /
</span></span></code></pre></div><h4 id="make-seo-better">Make SEO better</h4>
<p>Use a plugin like <a href="https://github.com/jonasmerlin/astro-seo#readme">astro-seo</a> and some code to level-up your SEO game.</p>
<h4 id="add-comments">Add Comments</h4>
<p>Add <a href="https://help.disqus.com/en/articles/1717104-embedding-a-comment-on-your-website-or-blog">Disqus</a> or <a href="https://utteranc.es/">Utterances</a> to add comments to your blog.</p>
<h4 id="add-analytics">Add Analytics</h4>
<p>Add <a href="https://code.juliancataldo.com/component/astro-google-analytics/#doc">Google Analytics</a> or <a href="https://docs.astro.build/en/guides/integrations-guide/vercel/#web-analytics">Vercel Analytics</a> to add analytics to your blog.</p>
<p>Leverage <a href="https://docs.astro.build/en/guides/integrations-guide/partytown/">Partytown plugin</a> to lazy load everything.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Astro is just spectacular and consider me intrigued.</p>
<p>I am half-tempted to switch my blog to Astro - am sure that will take me down yet another rabit hole.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Nuxt/Vue and Next/React - A Predicament</title>
      <link>https://techformist.com/nuxt-next-predicament/</link>
      <pubDate>Sun, 03 Dec 2023 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/nuxt-next-predicament/</guid>
      <description>&lt;p&gt;I have a full-time job that does not involve active web development. I am, however, on the constant look-out for the next big thing that will solve all my life&amp;rsquo;s problems.., by quickly creating apps that is.&lt;/p&gt;
&lt;p&gt;Vue has always been a tool that I depend on. Vue is quite easy to understand, use and build apps with. Nuxt just makes it even easier.&lt;/p&gt;
&lt;p&gt;I found React to be too verbose, generally more complicated, and not fun to work with. With &lt;a href=&#34;https://nextjs.org/&#34;&gt;NextJS&lt;/a&gt; 14, React Server Components, and the ** huge ** number of NextJS templates out there (not to mention &lt;a href=&#34;https://v0.dev&#34;&gt;v0.dev&lt;/a&gt;), I could kinda see how my workflow could be so much more easier.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have a full-time job that does not involve active web development. I am, however, on the constant look-out for the next big thing that will solve all my life&rsquo;s problems.., by quickly creating apps that is.</p>
<p>Vue has always been a tool that I depend on. Vue is quite easy to understand, use and build apps with. Nuxt just makes it even easier.</p>
<p>I found React to be too verbose, generally more complicated, and not fun to work with. With <a href="https://nextjs.org/">NextJS</a> 14, React Server Components, and the ** huge ** number of NextJS templates out there (not to mention <a href="https://v0.dev">v0.dev</a>), I could kinda see how my workflow could be so much more easier.</p>
<p>The big question though was - &ldquo;does Next+React really deliver the goods for me&rdquo;. And thus began a long time &ldquo;investing&rdquo; effort to find out what should be my stack of choice for the foreseeable future.</p>
<p>tldr;
It does not matter. Stick to the tooling that you like.</p>
<p>Before we move forward, for those of you who want all the other libraries &amp; frameworks considered - yes, I do code in them from time to time. No, they cannot be my go-to choice since I need to create things quickly lest I lose my interest and having lot of people out there simply means I can look forward to more answered questions and getting away with my scrappy &ldquo;expertise&rdquo;.</p>
<h1 id="the-need">The Need</h1>
<p>I am largely interested in building applications that help organize data, and provide ways to get things done in general. While not strictly focused on enterprises, they will border on things like -</p>
<ol>
<li>CRM/ERP&rsquo;s of the world</li>
<li>Project organization</li>
<li>People and task management for specific focus areas like recruitment, vendor management, etc.</li>
</ol>
<p>My typical apps have -</p>
<ol>
<li>Forms</li>
<li>Data tables</li>
<li>A few charts, reports and such</li>
</ol>
<p>Indirectly, I need -</p>
<ol>
<li>Ability to switch b/w real-time and classic fetching of updates</li>
<li>Easier state management</li>
<li>Ability to create a lot of reusable components</li>
<li>Ability to integrate with many libraries that can integrate well with documents, tables, reports and so forth</li>
</ol>
<h1 id="the-comparison-factors">The Comparison Factors</h1>
<p>Given the need is so generic and seem straight-forward at the outset, it is easy to get carried away. I decided to focus on a few seemingly random factors that I find useful or problematic.</p>
<ol>
<li><a href="#component-structure">Component Structure</a></li>
<li><a href="#server-side-rendering">Server-Side Rendering &amp; Data Fetching</a></li>
<li><a href="#state-management">State Management</a></li>
<li><a href="#performance">Performance</a></li>
<li><a href="#developer-experience">Developer Experience</a></li>
</ol>
<h1 id="component-structure">Component Structure</h1>
<p>Components are building blocks of any app. They are the ones that make up the UI and the logic behind it.</p>
<p>Creating components in Vue has been a breeze. The single file component structure is a joy to work with.</p>
<ul>
<li>Everything is neat and organized - from code, to styles, to the HTML</li>
<li>The separation of concerns is easy to manage</li>
<li>Code for reactive UI looks intuitive and easy to understand</li>
<li>Reusable code can be managed through Components and Services. Auto imports in Nuxt make it even easier to use them</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span> <span class="p">{{</span> <span class="nx">title</span> <span class="p">}}</span> <span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="s1">&#39;Hello World&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>React is not far off from here -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">App</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;App&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span><span class="nx">Hello</span> <span class="nx">World</span><span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>A somewhat more complexified version can be -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useState</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;react&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">TodoList</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">items</span><span class="p">,</span> <span class="nx">setItems</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">([]);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">newItem</span><span class="p">,</span> <span class="nx">setNewItem</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">addItem</span> <span class="o">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setItems</span><span class="p">([...</span><span class="nx">items</span><span class="p">,</span> <span class="nx">newItem</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setNewItem</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">input</span> <span class="na">value</span><span class="o">=</span><span class="p">{</span><span class="nx">newItem</span><span class="p">}</span> <span class="na">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">e</span> <span class="p">=&gt;</span> <span class="nx">setNewItem</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">)}</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">button</span> <span class="na">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">addItem</span><span class="p">}&gt;</span><span class="nx">Add</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span><span class="nx">items</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">item</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">li</span> <span class="na">key</span><span class="o">=</span><span class="p">{</span><span class="nx">index</span><span class="p">}&gt;{</span><span class="nx">item</span><span class="p">}&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">))}</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Vue still manages to look clean -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span> <span class="nt">v-model</span><span class="o">=</span><span class="s">&#34;newItem&#34;</span><span class="p"> /&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="nt">@click</span><span class="s">=&#34;addItem&#34;</span><span class="p">&gt;</span><span class="na">Add</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">li</span> <span class="nt">v-for</span><span class="o">=</span><span class="s">&#34;(item, index) in items&#34; :key=&#34;index&#34;</span><span class="p">&gt;{{</span> <span class="na">item</span> <span class="p">}}&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">ref</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">items</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">([]);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">newItem</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">addItem</span> <span class="o">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">items</span><span class="p">.</span><span class="nx">value</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">newItem</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">newItem</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>I had a hard preference for Vue structure (think Options API), but not any more.</p>
<ul>
<li>Reactivity is easy to write &amp; manage in Vue. Just use <code>ref</code> / <code>reactive</code> and you are good to go.</li>
<li>Intuitive code in templates and script. Cleaner separation of concerns</li>
<li>Bidirectional data binding is a breeze</li>
<li>Template helpers like <code>v-for</code>, <code>v-if</code> are a God-send</li>
</ul>
<h1 id="server-side-rendering--data-fetching">Server-Side Rendering &amp; Data Fetching</h1>
<p>React Server Components make it easier to write server-side code and have the right mix of client and server logic in the same component.</p>
<p>For example, I could fetch <code>posts</code> data from server and send the HTML to the client.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useEffect</span><span class="p">,</span> <span class="nx">useState</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;react&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">PostList</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">posts</span><span class="p">,</span> <span class="nx">setPosts</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">([]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">useEffect</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fetch</span><span class="p">(</span><span class="s1">&#39;https://jsonplaceholder.typicode.com/posts&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span> <span class="p">=&gt;</span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">data</span> <span class="p">=&gt;</span> <span class="nx">setPosts</span><span class="p">(</span><span class="nx">data</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span> <span class="p">[]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">posts</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span><span class="nx">Loading</span><span class="p">...&lt;/</span><span class="nt">div</span><span class="p">&gt;;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="nx">posts</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">post</span> <span class="p">=&gt;</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</span> <span class="na">key</span><span class="o">=</span><span class="p">{</span><span class="nx">post</span><span class="p">.</span><span class="nx">id</span><span class="p">}&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">h2</span><span class="p">&gt;{</span><span class="nx">post</span><span class="p">.</span><span class="nx">title</span><span class="p">}&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;{</span><span class="nx">post</span><span class="p">.</span><span class="nx">body</span><span class="p">}&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">))}</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>No haggling around with API calls, no moving around JS to get basic things done, and more control over how/who fetches data.</p>
<p>If I use Nuxt for the same problem, here&rsquo;s how the component looks like -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">data</span><span class="o">:</span> <span class="nx">posts</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">useAsyncData</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="nx">$fetch</span><span class="p">(</span><span class="s1">&#39;https://jsonplaceholder.typicode.com/posts&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="nt">v-for</span><span class="o">=</span><span class="s">&#34;post in posts&#34; :key=&#34;post&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">{{</span> <span class="na">post</span> <span class="p">}}</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>See <a href="https://nuxt.com/docs/guide/concepts/rendering">Nuxt SSR</a>.</p>
<p>RSC is a hard win for React. Next components are server by default, and mixing server / client components without a care for the world is enticing. While Nuxt makes it easy to build data fetching on top of Vue, it just does not compare to the magic of RSC.</p>
<p>That said, I really love the Vue way of doing things -</p>
<ul>
<li>don&rsquo;t worry about <code>useEffect</code> and other thousand hooks</li>
<li>no easy foot-guns causing performance issues or code spaghetti</li>
<li>clean, easy to understand template</li>
</ul>
<p>Many other SSR and data fetching features exist, but are not super important for me.</p>
<h1 id="state-management">State Management</h1>
<p>Using state management in React can be tricky. There are many ways to do it, and each has its own pros and cons. Let us see an example of a simple todo app using Zustland.</p>
<p>The component will look something like this -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">React</span> <span class="nx">from</span> <span class="s1">&#39;react&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">useStore</span> <span class="nx">from</span> <span class="s1">&#39;./store&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">TodoApp</span> <span class="o">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todos</span> <span class="o">=</span> <span class="nx">useStore</span><span class="p">(</span><span class="nx">state</span> <span class="p">=&gt;</span> <span class="nx">state</span><span class="p">.</span><span class="nx">todos</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">addTodo</span> <span class="o">=</span> <span class="nx">useStore</span><span class="p">(</span><span class="nx">state</span> <span class="p">=&gt;</span> <span class="nx">state</span><span class="p">.</span><span class="nx">addTodo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">toggleTodo</span> <span class="o">=</span> <span class="nx">useStore</span><span class="p">(</span><span class="nx">state</span> <span class="p">=&gt;</span> <span class="nx">state</span><span class="p">.</span><span class="nx">toggleTodo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">removeTodo</span> <span class="o">=</span> <span class="nx">useStore</span><span class="p">(</span><span class="nx">state</span> <span class="p">=&gt;</span> <span class="nx">state</span><span class="p">.</span><span class="nx">removeTodo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">newTodo</span><span class="p">,</span> <span class="nx">setNewTodo</span><span class="p">]</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">useState</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">handleAddTodo</span> <span class="o">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">addTodo</span><span class="p">(</span><span class="nx">newTodo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setNewTodo</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">input</span> <span class="na">value</span><span class="o">=</span><span class="p">{</span><span class="nx">newTodo</span><span class="p">}</span> <span class="na">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">e</span> <span class="p">=&gt;</span> <span class="nx">setNewTodo</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">)}</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">button</span> <span class="na">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">handleAddTodo</span><span class="p">}&gt;</span><span class="nx">Add</span> <span class="nx">Todo</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span><span class="nx">todos</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">todo</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">li</span> <span class="na">key</span><span class="o">=</span><span class="p">{</span><span class="nx">index</span><span class="p">}&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;checkbox&#34;</span> <span class="na">checked</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">completed</span><span class="p">}</span> <span class="na">onChange</span><span class="o">=</span><span class="p">{()</span> <span class="p">=&gt;</span> <span class="nx">toggleTodo</span><span class="p">(</span><span class="nx">index</span><span class="p">)}</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">text</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">button</span> <span class="na">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="p">=&gt;</span> <span class="nx">removeTodo</span><span class="p">(</span><span class="nx">index</span><span class="p">)}&gt;</span><span class="nx">Remove</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">))}</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">TodoApp</span><span class="p">;</span>
</span></span></code></pre></div><p>.. and the store -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">create</span> <span class="nx">from</span> <span class="s1">&#39;zustand&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">useStore</span> <span class="o">=</span> <span class="nx">create</span><span class="p">(</span><span class="nx">set</span> <span class="p">=&gt;</span> <span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">todos</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">  <span class="nx">addTodo</span><span class="o">:</span> <span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">set</span><span class="p">(</span><span class="nx">state</span> <span class="p">=&gt;</span> <span class="p">({</span> <span class="nx">todos</span><span class="o">:</span> <span class="p">[...</span><span class="nx">state</span><span class="p">.</span><span class="nx">todos</span><span class="p">,</span> <span class="p">{</span> <span class="nx">text</span><span class="p">,</span> <span class="nx">completed</span><span class="o">:</span> <span class="kc">false</span> <span class="p">}]</span> <span class="p">})),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">removeTodo</span><span class="o">:</span> <span class="p">(</span><span class="nx">index</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">set</span><span class="p">(</span><span class="nx">state</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">newTodos</span> <span class="o">=</span> <span class="p">[...</span><span class="nx">state</span><span class="p">.</span><span class="nx">todos</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="nx">newTodos</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">index</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{</span> <span class="nx">todos</span><span class="o">:</span> <span class="nx">newTodos</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="p">}),</span>
</span></span><span class="line"><span class="cl"><span class="p">}));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">useStore</span><span class="p">;</span>
</span></span></code></pre></div><p>In the Vue world, Pina (or even Nuxt state mgt.) is quite easy to use.
The component is simpler but comparable -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span> <span class="nt">v-model</span><span class="o">=</span><span class="s">&#34;newTodo&#34; type=&#34;text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="nt">@click</span><span class="s">=&#34;addTodo&#34;</span><span class="p">&gt;</span><span class="na">Add</span> <span class="na">Todo</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">li</span> <span class="nt">v-for</span><span class="o">=</span><span class="s">&#34;(todo, index) in todos&#34; :key=&#34;index&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{{</span> <span class="na">todo.text</span> <span class="p">}}</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">button</span> <span class="nt">@click</span><span class="s">=&#34;removeTodo(index)&#34;</span><span class="p">&gt;</span><span class="na">Remove</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">ref</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useStore</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;./store&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">setup</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">store</span> <span class="o">=</span> <span class="nx">useStore</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">newTodo</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">addTodo</span> <span class="o">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">store</span><span class="p">.</span><span class="nx">addTodo</span><span class="p">(</span><span class="nx">newTodo</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">newTodo</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">todos</span><span class="o">:</span> <span class="nx">store</span><span class="p">.</span><span class="nx">todos</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">newTodo</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">addTodo</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">removeTodo</span><span class="o">:</span> <span class="nx">store</span><span class="p">.</span><span class="nx">removeTodo</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Here&rsquo;s how the store looks like -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">defineStore</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;pinia&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">useStore</span> <span class="o">=</span> <span class="nx">defineStore</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">id</span><span class="o">:</span> <span class="s1">&#39;todos&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">state</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">todos</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">  <span class="p">}),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">actions</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">addTodo</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">todos</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span> <span class="nx">text</span><span class="p">,</span> <span class="nx">completed</span><span class="o">:</span> <span class="kc">false</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">removeTodo</span><span class="p">(</span><span class="nx">index</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">todos</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">index</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>I find Vue easier to use for arrays, object processing, and that trend continues for stores. But, I can totally understand how majority of the people out there feel as strong about React.</p>
<h1 id="performance">Performance</h1>
<p>Performance has not been a straight-forward and direct aspect of choosing a frontend framework. Most of the apps I build use database, data fetching from multiple sources, and components like maps/ charts - all of which shift performance considerations elsewhere.</p>
<p>I tend to rely on and follow the benchmarks published by talented people out there.</p>
<ul>
<li><a href="https://krausest.github.io/js-framework-benchmark/current.html">krausest/js-framework-benchmark</a></li>
<li>.. or more theoritical exercises like <a href="https://helda.helsinki.fi/server/api/core/bitstreams/a301a028-2441-41d2-b13e-e6ab8aa6e4d5/content">this</a></li>
</ul>
<p>There are not going to be any clear answers here, but Vue and React perform on par with each other.</p>
<h1 id="developer-experience">Developer Experience</h1>
<p>In general I am strongly biased towards the Vue way of working.</p>
<p>I have tried to change my ways multiple times - for React, Blazor, Astro, HTMX and so forth - but keep picking up Nuxt/Vue for real projects. This may be more of a reflection of my own laziness than anything else.</p>
<p>I do like the fact that -</p>
<ol>
<li>Vue is easy to learn and use</li>
<li>Nuxt makes it quite easy to build apps</li>
<li>Has a decent ecosystem of libraries and tools</li>
</ol>
<p>React and NextJS have always been the tools that I will certainly choose in the &ldquo;next&rdquo; project.</p>
<ul>
<li>A larger community implies many more people answering questions that an amateur like me tends to have</li>
<li>Many starter templates - including a few that are targeted at SaaS apps</li>
<li>More AI generator friendly since they are used by more people and have many more repositories available publicly. However, React Server Components and the frequent NextJS changes somewhat blunt that advantage</li>
<li>v0.dev is a significant advantage too</li>
<li><code>Framework of frameworks</code> like RedwoodJS, BlitzJS help stitch together many other tools and libraries to create a full-stack app</li>
<li>Styling libraries like Chakra UI, mui seem to be far more popular than their Vue counterparts</li>
</ul>
<h1 id="conclusion">Conclusion</h1>
<p>There are no significant advantages or limitations of using either of the options.</p>
<p>I see my own Vue + Nuxt bias, which has nothing to do with the tools themselves. While I continue to use Vue, I will have a keen eye on how React Server Components evolve and how Vue Vapor potentially changes the game.</p>
<p>If you are new to the ecosystem, build a few apps with either and see which option you like more. You may find yourself using both at one time or the other - so don&rsquo;t get too bogged down by the choices.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Building a Todo App using Nuxt, PrimeVue and SQLite</title>
      <link>https://techformist.com/todo-app-nuxt-primevue-sqlite/</link>
      <pubDate>Sat, 14 Oct 2023 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/todo-app-nuxt-primevue-sqlite/</guid>
      <description>&lt;p&gt;Let us create a simple Todo app using Nuxt -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PrimeVue for styling&lt;/li&gt;
&lt;li&gt;Store todos in a database&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;setup&#34;&gt;Setup&lt;/h1&gt;
&lt;p&gt;Ensure NodeJS is installed. Download and follow instructions &lt;a href=&#34;https://nodejs.org/en/download/&#34;&gt;here&lt;/a&gt; if you don&amp;rsquo;t have Node installed on your computer. I use pnpm as my package manager. You can use npm or yarn if you prefer. Install pnpm globally using the following command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;npm install -g pnpm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Create a new &lt;a href=&#34;https://nuxtjs.org/docs/get-started/installation&#34;&gt;Nuxt&lt;/a&gt; project.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pnpx nuxi@latest init nuxt-primevue-todo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command should initiate a project, install dependencies and also prompt you to initiate a git repository.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Let us create a simple Todo app using Nuxt -</p>
<ul>
<li>PrimeVue for styling</li>
<li>Store todos in a database</li>
</ul>
<h1 id="setup">Setup</h1>
<p>Ensure NodeJS is installed. Download and follow instructions <a href="https://nodejs.org/en/download/">here</a> if you don&rsquo;t have Node installed on your computer. I use pnpm as my package manager. You can use npm or yarn if you prefer. Install pnpm globally using the following command.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install -g pnpm
</span></span></code></pre></div><p>Create a new <a href="https://nuxtjs.org/docs/get-started/installation">Nuxt</a> project.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pnpx nuxi@latest init nuxt-primevue-todo
</span></span></code></pre></div><p>This command should initiate a project, install dependencies and also prompt you to initiate a git repository.</p>
<p>Next, install <a href="https://primevue.org/installation">PrimeVue</a>..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pnpm install primevue
</span></span></code></pre></div><p>..and follow instructions to enable <a href="https://primevue.org/installation/#nuxtintegration">PrimeVue for Nuxt</a>.</p>
<p>While at it, let us also install a few additional libraries that will help with styling.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pnpm add primeflex primeicons
</span></span></code></pre></div><p>Add below content in <code>nuxt.config.js</code> to enable PrimeVue.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineNuxtConfig</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="nx">css</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;public/themes/light/theme.css&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;~/assets/styles.scss&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;primeicons/primeicons.css&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;primeflex/primeflex.css&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">],</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">build</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">transpile</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;primevue&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="nx">modules</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;nuxt-primevue&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="nx">primevue</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">usePrimeVue</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">options</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">components</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">prefix</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">name</span><span class="o">:</span> <span class="kc">undefined</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">include</span><span class="o">:</span> <span class="s2">&#34;*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">exclude</span><span class="o">:</span> <span class="kc">undefined</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><p>Note that we have included all primevue components in the <code>components</code> section. Typically you use <code>include</code> and <code>exclude</code> to be selective about the components to be included for the project.</p>
<p>Next, we will include some custom styling. Since I am lazy, I will get inspired by a free template provided by PrimeVue called <a href="https://github.com/primefaces/sakai-vue/">SakaiVue</a></p>
<p>Create a file <code>assets/styles.scss</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scss" data-lang="scss"><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;layout/layout.scss&#34;</span><span class="p">;</span>
</span></span></code></pre></div><p>Create a new file <code>styles/layout/layout.scss</code> and add below content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scss" data-lang="scss"><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;./_variables&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;./_mixins&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;./_preloading&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;./_main&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;./_topbar&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;./_config&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;./_content&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;./_footer&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;./_responsive&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;./_utils&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;./_typography&#34;</span><span class="p">;</span>
</span></span></code></pre></div><p>The individual files will have some custom styling elements - you will find them in the <a href="https://github.com/prashanth1k/nuxt-primevue-todo">repo here</a>. Again, all the circus with styling is not quite necessary for the simple app we are building, but is simply included to force a structured approach.</p>
<p>Start server with the command <code>pnpm run dev</code> and you should see the following screen.</p>
<p>
    <img loading="lazy" src="/static/2023/nuxt-starting-up-todoapp.png" alt="Nuxt Starting up with PrimeVue"  /></p>
<h1 id="home-page--navigation">Home Page &amp; Navigation</h1>
<p>Add a navigation bar to the app. Create a new file <code>components/NavbarAnon.vue</code> and add below content. I used <code>Anon</code> suffix to denote that the toolbar is for anonymous user - I have found it easier to have a separate toolbar for logged-in users (not quite relevant here).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">Toolbar</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;layout-topbar&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">template</span> <span class="err">#</span><span class="na">start</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">NuxtLink</span> <span class="na">to</span><span class="o">=</span><span class="s">&#34;/&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">NuxtImg</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;logo&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;../assets/images/todo-logo.png&#34;</span> <span class="na">sizes</span><span class="o">=</span><span class="s">&#34;150vw sm:100vw md:200vw&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;mr-2&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">NuxtLink</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">template</span> <span class="err">#</span><span class="na">end</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">i</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;pi pi-question-circle&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">i</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">Toolbar</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Toolbar</span> <span class="nx">from</span> <span class="s1">&#39;primevue/toolbar&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create a default layout for the app with a new file <code>layouts/default.vue</code> and add below content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">NuxtLoadingIndicator</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">NavbarAnon</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="na">layout</span><span class="nt">-main-container</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="na">layout</span><span class="nt">-main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">slot</span><span class="p">&gt;&lt;/</span><span class="nt">slot</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">Footer</span><span class="p">&gt;&lt;/</span><span class="nt">Footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create the home page <code>pages/index.vue</code> and add below content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;grid&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">Hero</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 mt-12&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;features&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">Features</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 mt-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;surface-section px-4 py-8 md:px-6 lg:px-8&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-700 text-center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-900 font-bold text-5xl mb-3&#34;</span><span class="p">&gt;</span><span class="nx">What</span> <span class="nx">are</span> <span class="nx">you</span> <span class="nx">waiting</span> <span class="k">for</span><span class="o">?</span> <span class="nx">It</span><span class="err">&#39;</span><span class="nx">s</span> <span class="nx">free</span> <span class="k">for</span> <span class="nx">individual</span> <span class="nx">use</span><span class="o">!</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-700 text-2xl mb-5&#34;</span><span class="p">&gt;</span><span class="nx">Experience</span> <span class="nx">the</span> <span class="nx">task</span> <span class="nx">organizing</span> <span class="kr">super</span> <span class="nx">power</span><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">Button</span> <span class="na">label</span><span class="o">=</span><span class="s">&#34;Sign up&#34;</span> <span class="na">icon</span><span class="o">=</span><span class="s">&#34;pi pi-discord&#34;</span>
</span></span><span class="line"><span class="cl">                        <span class="na">class</span><span class="o">=</span><span class="s">&#34;font-bold px-5 py-3 p-button-raised p-button-rounded white-space-nowrap&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">Button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The page will use the <code>default</code> layout. The individual components are not much to speak about - you will find them in the <a href="https://github.com/prashanth1k/nuxt-primevue-todo">repo</a>.</p>
<p>You should now see a nice looking home page at <code>http://localhost:3000</code>.</p>
<p><img loading="lazy" src="/2023/nuxt-primevue-home-page.png" type="" alt="nuxt-primevue-home-page"  /></p>
<p>I did include a second layout for the logged-in user in the repo, but am not discussing that here (useful in cases where I need a different toolbar, sidebar navigation for the actual app, for example).</p>
<h1 id="setup-drizzle--data-migrations">Setup Drizzle &amp; Data Migrations</h1>
<p>Let us setup Drizzle ORM and Drizzle Kit. The latter is used for migrations and other admin tasks.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pnpm i drizzle-orm better-sqlite3
</span></span><span class="line"><span class="cl">pnpm i -D drizzle-kit
</span></span></code></pre></div><p>Create a new file <code>drizzle.config.js</code> and add below content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">schema</span><span class="o">:</span> <span class="s2">&#34;./data/schema_*.js&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">out</span><span class="o">:</span> <span class="s2">&#34;./data/migrations&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">driver</span><span class="o">:</span> <span class="s2">&#34;better-sqlite&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">dbCredentials</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">url</span><span class="o">:</span> <span class="s2">&#34;./data/data.db&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>The schema file is going to be used by default by Drizzle CLI.  While we do the actual migrations, all we need to do is <code>pnpm exec drizzle-kit generate:sqlite</code> and the migration files are automatically created in the <code>out</code> folder. We will see this in action in a second.</p>
<p>First, let us create a simple table. Create a new file <code>./data/schema_user.js</code> and add below content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">sqliteTable</span><span class="p">,</span> <span class="nx">integer</span><span class="p">,</span> <span class="nx">text</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;drizzle-orm/sqlite-core&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">sql</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;drizzle-orm&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">user</span> <span class="o">=</span> <span class="nx">sqliteTable</span><span class="p">(</span><span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">id</span><span class="o">:</span> <span class="nx">integer</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">).</span><span class="nx">primaryKey</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">firstName</span><span class="o">:</span> <span class="nx">text</span><span class="p">(</span><span class="s2">&#34;first_name&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">lastName</span><span class="o">:</span> <span class="nx">text</span><span class="p">(</span><span class="s2">&#34;last_name&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">email</span><span class="o">:</span> <span class="nx">text</span><span class="p">(</span><span class="s2">&#34;email&#34;</span><span class="p">).</span><span class="nx">unique</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">created</span><span class="o">:</span> <span class="nx">text</span><span class="p">(</span><span class="s2">&#34;created&#34;</span><span class="p">).</span><span class="k">default</span><span class="p">(</span><span class="nx">sql</span><span class="sb">`CURRENT_TIMESTAMP`</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">updated</span><span class="o">:</span> <span class="nx">text</span><span class="p">(</span><span class="s2">&#34;updated&#34;</span><span class="p">).</span><span class="k">default</span><span class="p">(</span><span class="nx">sql</span><span class="sb">`CURRENT_TIMESTAMP`</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Let us also create the table for our todos. Create a new file <code>./data/schema_todo.js</code> and add below content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">sqliteTable</span><span class="p">,</span> <span class="nx">integer</span><span class="p">,</span> <span class="nx">text</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;drizzle-orm/sqlite-core&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">sql</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;drizzle-orm&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">todo</span> <span class="o">=</span> <span class="nx">sqliteTable</span><span class="p">(</span><span class="s2">&#34;todo&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">id</span><span class="o">:</span> <span class="nx">integer</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">).</span><span class="nx">primaryKey</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">firstName</span><span class="o">:</span> <span class="nx">text</span><span class="p">(</span><span class="s2">&#34;title&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">lastName</span><span class="o">:</span> <span class="nx">text</span><span class="p">(</span><span class="s2">&#34;status&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">created</span><span class="o">:</span> <span class="nx">text</span><span class="p">(</span><span class="s2">&#34;created&#34;</span><span class="p">).</span><span class="k">default</span><span class="p">(</span><span class="nx">sql</span><span class="sb">`CURRENT_TIMESTAMP`</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">updated</span><span class="o">:</span> <span class="nx">text</span><span class="p">(</span><span class="s2">&#34;updated&#34;</span><span class="p">).</span><span class="k">default</span><span class="p">(</span><span class="nx">sql</span><span class="sb">`CURRENT_TIMESTAMP`</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Create the migration file.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pnpm <span class="nb">exec</span> drizzle-kit generate:sqlite
</span></span></code></pre></div><p>You could also suffix <code>--out data/migrations --schema data/schema_user.js</code> if you want to be explicit about the output folder and schema file.</p>
<p>Run the migration.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pnpm <span class="nb">exec</span> drizzle-kit push:sqlite
</span></span></code></pre></div><p>You can see browse the SQLite database and see the table created using the Drizzle tool (<code>pnpm exec drizzle-kit studio</code> &amp; point the browser at the URL), or using a tool like <a href="https://sqlitebrowser.org/">DB Browser for SQLite</a>.</p>
<h1 id="creating-the-server-api">Creating the Server API</h1>
<p>Nuxt is great for the frontend, but also features a full-fledged node server / framework based on <a href="https://github.com/unjs/h3">h3</a>.</p>
<p>We will use this server to create a test API.</p>
<p>Create a new file <code>server/api/hello.js</code> with below content -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineEventHandler</span><span class="p">((</span><span class="nx">event</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span> <span class="nx">message</span><span class="o">:</span> <span class="s2">&#34;Hello world!&#34;</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>You can also use the <code>nuxi</code> command to <a href="https://nuxt.com/docs/api/commands/add#nuxi-add-api">generate the <code>api</code></a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pnpx nuxi generate api hello
</span></span></code></pre></div><p>When your Nuxt server is running, you can hit this route at <code>http://localhost:3000/api/hello</code> to see the response.</p>
<p>Now that we know the server works, let us create our first API. Create a new file <code>server/api/user-exists.js</code> and add below content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">user</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;~/data/schema_user&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">db</span><span class="p">,</span> <span class="nx">sqlite</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;../dbservice&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">eq</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;drizzle-orm&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineEventHandler</span><span class="p">(</span><span class="kr">async</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">body</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">readBody</span><span class="p">(</span><span class="nx">event</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;Initiated user find. Got body: &#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">body</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34; and search param: &#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">body</span><span class="o">?</span><span class="p">.</span><span class="nx">email</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">resp</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">select</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="nx">user</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="nx">eq</span><span class="p">(</span><span class="nx">user</span><span class="p">.</span><span class="nx">email</span><span class="p">,</span> <span class="nx">body</span><span class="o">?</span><span class="p">.</span><span class="nx">email</span> <span class="o">||</span> <span class="s2">&#34;&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">get</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Search results:&#34;</span><span class="p">,</span> <span class="nx">resp</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">resp</span><span class="o">?</span><span class="p">.</span><span class="nx">id</span> <span class="o">!=</span> <span class="kc">undefined</span><span class="p">)</span> <span class="k">return</span> <span class="p">{</span> <span class="nx">userExists</span><span class="o">:</span> <span class="kc">true</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="k">return</span> <span class="p">{</span> <span class="nx">userExists</span><span class="o">:</span> <span class="kc">false</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error: &#34;</span><span class="p">,</span> <span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="nx">createError</span><span class="p">(</span><span class="mi">500</span><span class="p">,</span> <span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>The code is self explanatory -</p>
<ol>
<li>We collect the <code>body</code> from incoming message to get email</li>
<li>Search for the user in the database with Drizzle. <code>dbservice</code> is a simple wrapper around Drizzle to make the connections and queries simpler</li>
<li>Return a response with <code>userExists</code> flag</li>
</ol>
<p>Create a new file <code>server/dbservice.js</code> and add below content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">drizzle</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;drizzle-orm/better-sqlite3&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Database</span> <span class="nx">from</span> <span class="s2">&#34;better-sqlite3&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">sqlite</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Database</span><span class="p">(</span><span class="s2">&#34;data/data.db&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">db</span> <span class="o">=</span> <span class="nx">drizzle</span><span class="p">(</span><span class="nx">sqlite</span><span class="p">);</span>
</span></span></code></pre></div><p>Use your favourite REST client to test the API. Pass in a JSON body with <code>email</code> and you should see a response with <code>userExists</code> flag.</p>
<p>Input -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;a@a.com&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Output -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;userExists&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h1 id="add-user-registrationlogin-page">Add User Registration/Login Page</h1>
<p>Create a new file <code>pages/signup.vue</code> and add below content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">email</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">password</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">userExists</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">async</span> <span class="kd">function</span> <span class="nx">checkUserExists</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="p">{</span> <span class="nx">data</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">useFetch</span><span class="p">(</span><span class="s1">&#39;/api/user-exists&#39;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">method</span><span class="o">:</span> <span class="s1">&#39;POST&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">body</span><span class="o">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span> <span class="nx">email</span><span class="o">:</span> <span class="nx">email</span><span class="p">.</span><span class="nx">value</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;checkUserExists data: &#39;</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">userExists</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">userExists</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">async</span> <span class="kd">function</span> <span class="nx">createUser</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="p">{</span> <span class="nx">data</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">useFetch</span><span class="p">(</span><span class="s1">&#39;/api/user-create&#39;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">method</span><span class="o">:</span> <span class="s1">&#39;POST&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">body</span><span class="o">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span> <span class="nx">email</span><span class="o">:</span> <span class="nx">email</span><span class="p">.</span><span class="nx">value</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;createUser data: &#39;</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">userExists</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">userExists</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">await</span> <span class="nx">navigateTo</span><span class="p">(</span><span class="s1">&#39;/dashboard&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;surface-ground flex align-items-center justify-content-center &#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;flex flex-column align-items-center justify-content-center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">data</span><span class="o">:</span><span class="p">{{</span> <span class="nx">data</span> <span class="p">}}</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;../assets/images/todo-logo.png&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;todo app&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;mb-5 w-6rem flex-shrink-0&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">div</span>
</span></span><span class="line"><span class="cl">                <span class="na">style</span><span class="o">=</span><span class="s">&#34;border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;w-full surface-card py-8 px-5 sm:px-8&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;border-radius: 53px&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-center mb-5&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">i</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;pi pi-user&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;font-size: 2.5rem&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">i</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-900 text-3xl font-medium mb-3&#34;</span><span class="p">&gt;</span><span class="nx">Hello</span> <span class="nx">Chief</span><span class="o">!</span><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-600 font-medium&#34;</span><span class="p">&gt;</span><span class="nx">Are</span> <span class="nx">you</span> <span class="nx">ready</span> <span class="nx">to</span> <span class="nx">get</span> <span class="nx">organized</span><span class="o">?</span><span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;email1&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;block text-900 text-xl font-medium mb-2&#34;</span><span class="p">&gt;</span><span class="nx">Email</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">InputText</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;email1&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">placeholder</span><span class="o">=</span><span class="s">&#34;Email address&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;w-full md:w-30rem&#34;</span>
</span></span><span class="line"><span class="cl">                            <span class="nt">v-model</span><span class="o">=</span><span class="s">&#34;email&#34; @change=&#34;checkUserExists&#34;</span><span class="p"> /&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;flex align-items-center justify-content-between mb-5 gap-5&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                            <span class="p">&lt;</span><span class="nt">small</span><span class="p">&gt;</span><span class="nx">Login</span> <span class="k">if</span> <span class="nx">your</span> <span class="nx">user</span><span class="o">/</span><span class="nx">email</span> <span class="nx">id</span> <span class="nx">is</span> <span class="nx">found</span><span class="p">.</span> <span class="nx">Else</span><span class="p">,</span> <span class="nx">just</span> <span class="nx">create</span> <span class="nx">one</span><span class="o">!</span><span class="p">&lt;/</span><span class="nt">small</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;password1&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;block text-900 font-medium text-xl mb-2&#34;</span>
</span></span><span class="line"><span class="cl">                            <span class="nt">v-if</span><span class="o">=</span><span class="s">&#34;userExists&#34;</span><span class="p">&gt;</span><span class="na">Password</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">Password</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;password1&#34;</span> <span class="nt">v-model</span><span class="o">=</span><span class="s">&#34;password&#34; placeholder=&#34;Password&#34; :toggleMask=&#34;true&#34;</span><span class="p">
</span></span></span><span class="line"><span class="cl">                            <span class="na">class</span><span class="o">=</span><span class="s">&#34;w-full mb-3&#34;</span> <span class="na">inputClass</span><span class="o">=</span><span class="s">&#34;w-full&#34;</span> <span class="o">:</span><span class="na">inputStyle</span><span class="o">=</span><span class="s">&#34;{ padding: &#39;1rem&#39; }&#34;</span> <span class="nt">v-if</span><span class="o">=</span><span class="s">&#34;userExists&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;/</span><span class="nt">Password</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">Button</span> <span class="na">label</span><span class="o">=</span><span class="s">&#34;Signup / Login&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;w-full p-3 text-xl&#34;</span> <span class="nt">@click</span><span class="s">=&#34;createUser&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">Button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>You now have a registration / login page.</p>
<p><img loading="lazy" src="/2023/nuxt-primevue-signup-page.png" type="" alt="nuxt-primevue-signup-page"  /></p>
<p>Go ahead and enter any email id and you are registered! We will not be adding a full-fledged login function in this post (we need to use some sort of <code>auth</code> library like <a href="https://lucia-auth.com/guidebook/github-oauth/nuxt/">Lucia</a> to do that).</p>
<p>You may be wondering on why registration and login functions are combined and not two separate pages. You cannot go wrong with either, but the common page is advantageous when you support different types of authentication (e.g., Google, Facebook, custom etc.).</p>
<h1 id="add-todo-api">Add Todo API</h1>
<p>Create two new APIs to handle <code>get</code> and <code>post</code>. We will use &ldquo;proper&rdquo; conventions this time around.</p>
<p>First, create a new file <code>server/api/todo.get.js</code> and add below content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">todo</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;~/data/schema_todo&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">db</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;../dbservice&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineEventHandler</span><span class="p">(</span><span class="kr">async</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">resp</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">select</span><span class="p">().</span><span class="nx">from</span><span class="p">(</span><span class="nx">todo</span><span class="p">).</span><span class="nx">all</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Search results - todo:&#34;</span><span class="p">,</span> <span class="nx">resp</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">resp</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error: &#34;</span><span class="p">,</span> <span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="nx">createError</span><span class="p">(</span><span class="mi">500</span><span class="p">,</span> <span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p><code>todo.get.js</code> will handle requests to get all todo&rsquo;s. If there was a need to get a specific todo, I would create a similar file <code>server/api/[id].get.js</code> and handle the request there.</p>
<p>Let us also code to handle <code>post</code> - create a new file <code>server/api/todo.post.js</code> and add below content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">todo</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;~/data/schema_todo&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">db</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;../dbservice&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">eq</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;drizzle-orm&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineEventHandler</span><span class="p">(</span><span class="kr">async</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">body</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">readBody</span><span class="p">(</span><span class="nx">event</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;todo body: &#34;</span><span class="p">,</span> <span class="nx">body</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">newTodo</span> <span class="o">=</span> <span class="p">{</span> <span class="p">...</span><span class="nx">body</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">resp</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">insert</span><span class="p">(</span><span class="nx">todo</span><span class="p">).</span><span class="nx">values</span><span class="p">(</span><span class="nx">newTodo</span><span class="p">).</span><span class="nx">run</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;inserted todo: &#34;</span><span class="p">,</span> <span class="nx">resp</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">todoResp</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">select</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="nx">todo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="nx">eq</span><span class="p">(</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span> <span class="nx">resp</span><span class="o">?</span><span class="p">.</span><span class="nx">lastInsertRowid</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">get</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">todoResp</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error: &#34;</span><span class="p">,</span> <span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="nx">createError</span><span class="p">(</span><span class="mi">500</span><span class="p">,</span> <span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Key points to note -</p>
<ol>
<li><code>const newTodo = { ...body }</code> may be useless in this situation, but is more relevant when using types or performing validations on the incoming message</li>
<li>The <code>insert</code> function returns a response with <code>lastInsertRowid</code> - we use that to get the newly created todo and return it to the caller. Calling function in client will use the data to update the UI. Again, the relevance may be lost here, but is a good practice since database commit may populate fields, add timestamps etc. and the client needs the updated info</li>
</ol>
<h1 id="add-todo-page">Add Todo Page</h1>
<p>Create a new file <code>pages/dashboard.vue</code> and add below content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">ref</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">todos</span> <span class="o">=</span> <span class="nx">reactive</span><span class="p">({});</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">async</span> <span class="kd">function</span> <span class="nx">getTodos</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="p">{</span> <span class="nx">data</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">useFetch</span><span class="p">(</span><span class="s1">&#39;/api/todo&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;getTodos data: &#39;</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">todos</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">async</span> <span class="kd">function</span> <span class="nx">createTodo</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="p">{</span> <span class="nx">data</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">useFetch</span><span class="p">(</span><span class="s1">&#39;/api/todo&#39;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">method</span><span class="o">:</span> <span class="s1">&#39;POST&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">body</span><span class="o">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span> <span class="nx">title</span><span class="o">:</span> <span class="nx">title</span><span class="p">.</span><span class="nx">value</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s1">&#39;in progress&#39;</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;createTodo data: &#39;</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">todos</span><span class="p">.</span><span class="nx">value</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// execute getTodos on mounted
</span></span></span><span class="line"><span class="cl"><span class="nx">onBeforeMount</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Fetching todos..&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">getTodos</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;grid&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;card&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">h5</span><span class="p">&gt;</span><span class="nx">Add</span> <span class="nx">Todo</span><span class="p">&lt;/</span><span class="nt">h5</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;field p-fluid&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span><span class="nx">Description</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">InputText</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;title&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="nt">v-model</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p"> /&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">Button</span> <span class="nt">@click</span><span class="s">=&#34;createTodo&#34;</span><span class="p">&gt;</span><span class="na">Add</span><span class="p">&lt;/</span><span class="nt">Button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;card p-fluid&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">h5</span><span class="p">&gt;</span><span class="nx">My</span> <span class="nx">Todos</span><span class="p">&lt;/</span><span class="nt">h5</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="nt">v-if</span><span class="o">=</span><span class="s">&#34;!todos &amp;&amp; todos.value.length &lt;= 0&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="na">No</span> <span class="na">todos</span> <span class="na">yet.</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">DataView</span> <span class="nt">:value</span><span class="o">=</span><span class="s">&#34;todos.value&#34;</span> <span class="nt">v-else</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">template</span> <span class="err">#</span><span class="na">list</span><span class="o">=</span><span class="s">&#34;slotProps&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                            <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;flex flex-column xl:flex-row xl:align-items-start p-4 gap-4&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-2xl font-bold text-900&#34;</span><span class="p">&gt;{{</span> <span class="nx">slotProps</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">title</span> <span class="p">}}&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                            <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">DataView</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>This page will allow user to create new todo&rsquo;s and also query the API for todo&rsquo;s.</p>
<p><img loading="lazy" src="/2023/nuxt-primevue-todo-page.png" type="" alt="nuxt-primevue-todo-page"  /></p>
<p>Note that-</p>
<ol>
<li>We have used <code>onBeforeMount</code> to execute the <code>getTodos</code> function on page load. While <code>onMounted</code> is the more common way to do this, <code>onBeforeMount</code> gets triggered for page refreshes as well</li>
<li><code>DataView</code> and <code>DataTable</code> in PrimeVue makes it quite easy to display list data. I have used <code>DataView</code> here, but <code>DataTable</code> can be more beneficial for larger data sets</li>
<li>Typical apps need some validation on the forms - both on the page and on the server. I have not included that here for brevity</li>
</ol>
<p>And, that&rsquo;s a wrap for today, folks.</p>
<h1 id="conclusion">Conclusion</h1>
<ul>
<li>Nuxt can easily be a full-stack app</li>
<li>I cannot get myself to like Nuxt as the go-to full stack app
<ul>
<li>I am spoilt by the ease-of-use of a server framework - middleware, routes, controller/service included</li>
<li>My typical servers include functions that are not covered here and would need separate treatment anyway - e.g., batch processing / scheduled jobs</li>
<li>Server/client architecture looks cleaner to read / code</li>
<li>I perceive the typical server/client segregation to be easier to maintain without forcing a hard push for all concerns</li>
</ul>
</li>
<li>Also in other news-
<ul>
<li>I have come to admire <code>Drizzle</code> but cannot get over the intuitiveness of <code>knex</code>. Also, I have come to fear the sometimes drastic changes happening in smaller libraries across versions</li>
<li>PrimeVue will probably be my new library of choice (was Vuetify earlier)</li>
</ul>
</li>
</ul>
<p>I keep looking for &ldquo;one perfect way&rdquo; to get things done faster (I am more of a casual developer), but that is still in the future I guess.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Go Webview Experiments and a Simple Todo Demo App</title>
      <link>https://techformist.com/go-webview-experiments/</link>
      <pubDate>Sat, 07 Oct 2023 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/go-webview-experiments/</guid>
      <description>&lt;p&gt;Applications in Electron are great, but they are also heavy and slow. I have been looking for a way to build an app that can be -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;universal (kinda - I will start with desktop experience for the masses but will eventually gravitate towards everything, everywhere, all at once)&lt;/li&gt;
&lt;li&gt;light weight - space and memory&lt;/li&gt;
&lt;li&gt;fast&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just to set the frame of reference - what I want from UI development is ease of development - html, css, and js and other such delightful technologies make things easy, GTK / Xamarin / Qt / WinForms / WPF / etc. are not so much fun.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Applications in Electron are great, but they are also heavy and slow. I have been looking for a way to build an app that can be -</p>
<ul>
<li>universal (kinda - I will start with desktop experience for the masses but will eventually gravitate towards everything, everywhere, all at once)</li>
<li>light weight - space and memory</li>
<li>fast</li>
</ul>
<p>Just to set the frame of reference - what I want from UI development is ease of development - html, css, and js and other such delightful technologies make things easy, GTK / Xamarin / Qt / WinForms / WPF / etc. are not so much fun.</p>
<p>What better way to do most of the features outlined here than in Go? This is an attempt to build a simple todo app using the combined power of Go and web technologies.</p>
<p>We will start with a simple window with webview in Golang, and then move to Wails to see how it makes the entire experience better. We will also see how to incrementally add functionality to the app.</p>
<h1 id="getting-started-installation--setup">Getting Started: Installation &amp; Setup</h1>
<p>If you intend to follow along, ensure you have Go on the system. If you don&rsquo;t, you can get it from <a href="https://golang.org/dl/">here</a>.</p>
<p>Having VSCode from <a href="https://code.visualstudio.com/download">here</a> and the Golang extension from <a href="https://marketplace.visualstudio.com/items?itemName=golang.Go">here</a> will be helpful.</p>
<p>Once the entire setup is done, create a new folder, open a terminal either in explorer or from VSCode, and create a new Go project -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">go mod init go-webview-todo
</span></span></code></pre></div><p>This will create a <code>go.mod</code> file in the project root - it will be used to manage dependencies. Open the project folder in VSCode.</p>
<p>Create a file called <code>main.go</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s">&#34;Hello World&#34;</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p>Now, run the file using the <code>Run</code> button in VSCode or using a terminal. You should see the output in the terminal.</p>
<p>Now that everything is running with your setup, we will focus on next steps.</p>
<h1 id="install-dependencies">Install Dependencies</h1>
<p>There are more than a few options to create webview apps -</p>
<ol>
<li><a href="github.com/zserge/webview">zserge/webview</a>
Simple, cross-platform, portable, and lightweight. It is a tiny cross-platform webview library for C/C++/Golang to build modern cross-platform GUIs. It supports two-way JavaScript bindings (to call JavaScript from C/C++/Go and to call C/C++/Go from JavaScript). Needs CGO and some special flags to run on Windows.</li>
<li>Go bindings for webview library <a href="https://github.com/webview/webview_go">webview/webview_go</a>
Underlying library was intended for C/C++, but has a Go wrapper around it.</li>
<li><a href="https://github.com/ImVexed/muon">ImVexed/muon</a>
Uses Ultralight, a cross-platform WebKit rewrite in C++, instead of Chrome. Lightweight alternative to Electron. Not maintained actively anymore.</li>
<li>Advanced / fully-featured libraries like <a href="https://github.com/wailsapp/wails">wailsapp/wails</a> or <a href="https://github.com/fyne-io/fyne">fyne-io/fyne</a>
May use webview libraries in the backend, but abstract away the entire setup and make the entire experience pleasant. We will get to this state at the very end.</li>
</ol>
<p>.. and more.</p>
<p>We will start with the simplest option - <code>zserge/webview</code>.</p>
<h1 id="develop-a-simple-window-with-webview-in-golang">Develop a simple window with webview in Golang</h1>
<p>Install the library using <code>go get</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">go get github.com/zserge/webview
</span></span></code></pre></div><p>Create a new file called <code>main.go</code> and add the following code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="s">&#34;github.com/zserge/webview&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">webview</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">webview</span><span class="p">.</span><span class="nx">Settings</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Title</span><span class="p">:</span><span class="w">                  </span><span class="s">&#34;My test web view app&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">URL</span><span class="p">:</span><span class="w">                    </span><span class="s">&#34;http://google.com&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Width</span><span class="p">:</span><span class="w">                  </span><span class="mi">1000</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Height</span><span class="p">:</span><span class="w">                 </span><span class="mi">800</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Resizable</span><span class="p">:</span><span class="w">              </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Debug</span><span class="p">:</span><span class="w">                  </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">ExternalInvokeCallback</span><span class="p">:</span><span class="w"> </span><span class="kc">nil</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">defer</span><span class="w"> </span><span class="nx">w</span><span class="p">.</span><span class="nf">Destroy</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="p">.</span><span class="nf">SetTitle</span><span class="p">(</span><span class="s">&#34;My App&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="p">.</span><span class="nf">Navigate</span><span class="p">(</span><span class="s">&#34;https://google.com&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="p">.</span><span class="nf">Run</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>You should see a nice window.. in theory. In practice I could not get my module to work in Windows. I gave up after a few tries.</p>
<p>Close to the webview package is webview2 - <a href="https://github.com/jchv/go-webview2">jchv/go-webview2</a>. This library does not need CGO but is Windows specific.</p>
<p>Install <code>webview2</code> with -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">go get <span class="s2">&#34;github.com/jchv/go-webview2&#34;</span>
</span></span></code></pre></div><p>Change the code in <code>main.go</code> ever so slightly -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="s">&#34;github.com/jchv/go-webview2&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">webview2</span><span class="p">.</span><span class="nf">NewWithOptions</span><span class="p">(</span><span class="nx">webview2</span><span class="p">.</span><span class="nx">WebViewOptions</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Window</span><span class="p">:</span><span class="w">        </span><span class="kc">nil</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Debug</span><span class="p">:</span><span class="w">         </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">DataPath</span><span class="p">:</span><span class="w">      </span><span class="s">&#34;&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">AutoFocus</span><span class="p">:</span><span class="w">     </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">WindowOptions</span><span class="p">:</span><span class="w"> </span><span class="nx">webview2</span><span class="p">.</span><span class="nx">WindowOptions</span><span class="p">{</span><span class="nx">Title</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;Demo View&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Width</span><span class="p">:</span><span class="w"> </span><span class="mi">1000</span><span class="p">,</span><span class="w"> </span><span class="nx">Height</span><span class="p">:</span><span class="w"> </span><span class="mi">800</span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="p">.</span><span class="nf">SetSize</span><span class="p">(</span><span class="mi">800</span><span class="p">,</span><span class="w"> </span><span class="mi">600</span><span class="p">,</span><span class="w"> </span><span class="nx">webview2</span><span class="p">.</span><span class="nx">HintFixed</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="p">.</span><span class="nf">Navigate</span><span class="p">(</span><span class="s">&#34;https://google.com&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">defer</span><span class="w"> </span><span class="nx">w</span><span class="p">.</span><span class="nf">Destroy</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="p">.</span><span class="nf">Run</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>And, voila -</p>
<p><img loading="lazy" src="/2023/golang-webview2-window.png" type="" alt="golang-webview2-window"  /></p>
<h1 id="moving-to-wails">Moving to Wails</h1>
<p>While the code above is pretty simple and straight-forward, the developer experience may not be the best. Let&rsquo;s see whether that changes with Wails.</p>
<p>First, install <a href="https://nodejs.org/en/download">Node</a> if you don&rsquo;t already have it.</p>
<p>Install Wails in your project folder.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">go install github.com/wailsapp/wails/v2/cmd/wails@latest
</span></span></code></pre></div><p>In Terminal, hit the below command to check whether Wails has been installed correctly -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wails doctor
</span></span></code></pre></div><p><img loading="lazy" src="/2023/wails-doctor-output.png" type="" alt="wails-doctor-output.png"  /></p>
<p>See the <a href="https://wails.app/gettingstarted/installing/">Wails documentation</a> if you are facing any issues.</p>
<p>Now, let&rsquo;s create a new project using Wails. Note that we will be using Vue for the frontend.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wails init -n go-webview-wails-todo -t vue
</span></span></code></pre></div><p>React, Svelte or vanilla JS are supported Wails OOB, and there are more community-supported templates for other frameworks.</p>
<p>Open the project folder in VSCode.Change the statement <code>module changeme</code> in <code>go.mod</code> to <code>module go-webview-wails-todo</code>. Update the <code>README</code> if you want.</p>
<p>Run the app -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wails dev
</span></span></code></pre></div><p>This should start your application.</p>
<p><img loading="lazy" src="/2023/wails-dev-output.png" type="" alt="wails-dev-output"  /></p>
<p>Add a simple function to <code>app.go</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">TodoList</span><span class="p">()</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;todo1&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;todo2&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;todo3&#34;</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>Include some ready styling with <a href="https://jenil.github.io/chota/">chota css</a> with the below line in <code>head</code> section of <code>frontend/index.html</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/chota@latest&#34;</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Update the <code>frontend/src/App.vue</code> file to display the list of todos -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">ListTodos</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;../wailsjs/go/main/App&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">todos</span> <span class="o">=</span> <span class="nx">reactive</span><span class="p">({</span> <span class="nx">data</span><span class="o">:</span> <span class="p">[]</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">getTodoList</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">todos</span><span class="p">.</span><span class="nx">data</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">ListTodos</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;todos.data: &#39;</span><span class="p">,</span> <span class="p">...</span><span class="nx">todos</span><span class="p">.</span><span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">onMounted</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">getTodoList</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`Fetched todos..!`</span><span class="p">,</span> <span class="nx">todos</span><span class="p">.</span><span class="nx">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">nav</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav-left&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;brand&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;#&#34;</span><span class="p">&gt;</span>Wails Todos!<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          {{todos.data}}}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>You should see the list of hard-coded <code>todos</code> in the app.</p>
<p>Couple of really cool things happened so far -</p>
<ol>
<li>The logic you wrote in Go is available in the frontend as a function. You can call it from the frontend and use the data in the frontend. All you needed to do was to add the function to the <code>App</code> struct in <code>app.go</code> and wails took care of the rest.</li>
<li>You will see <code>wails.js</code> folder with Go APIs being exposed to the frontend as JS functions. You would also see types generated out of <code>struct</code> if we had used Typescript</li>
<li><code>wails</code> command did the hot-reload for both golang and vue, and bound everything together for you. You did not have to do anything else other than focus on the app logic</li>
</ol>
<h1 id="adding-functionality-to-our-wails-app">Adding functionality to our wails app</h1>
<p>Let&rsquo;s make our app easier to read / maintain with a few changes.</p>
<p>Add the below <code>struct</code> to <code>app.go</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">todo</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Id</span><span class="w">          </span><span class="kt">int</span><span class="w">    </span><span class="s">`json:&#34;id&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Description</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:&#34;description&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Due</span><span class="w">         </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:&#34;due&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Status</span><span class="w">      </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:&#34;status&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Created</span><span class="w">     </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:&#34;created&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>Notice the capital letters for <code>Id</code>, <code>Description</code> etc. - that is Go way of making fields public and accessible from outside the package.</p>
<p>After <code>Greet</code> function, introduce the below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">ListTodos</span><span class="p">()</span><span class="w"> </span><span class="p">[]</span><span class="nx">todo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="p">[]</span><span class="nx">todo</span><span class="p">{{</span><span class="nx">Id</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nx">Description</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;Code Go&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Due</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;2023-10-15&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Status</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;In Progress&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Created</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;2023-10-01 18:30&#34;</span><span class="p">}}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">CreateTodo</span><span class="p">(</span><span class="nx">todoItem</span><span class="w"> </span><span class="nx">todo</span><span class="p">)</span><span class="w"> </span><span class="nx">todo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">todoItem</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="nx">todo</span><span class="p">{</span><span class="nx">Id</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nx">Description</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;Code Go&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Due</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;2023-10-15&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Status</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;In Progress&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Created</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;2023-10-01 18:30&#34;</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>We are yet to implement a database -</p>
<ul>
<li>The dummy data in <code>ListTodos</code> will be replaced with actual data from a database</li>
<li><code>CreateTodo</code> will be used to create a new todo item</li>
</ul>
<p>The functions just return &ldquo;some&rdquo; data to demonstrate how the <code>todo</code>, a <code>struct</code> in Golang is available to the frontend. Click on them buttons to see output in console - both in Terminal running <code>go</code> and in the browser.</p>
<p>The changes in Vue are more extensive -</p>
<ol>
<li>Create Vue components for list and new todos</li>
<li>Change <code>TodoList.vue</code> to point to the new components</li>
<li>Add some custom styling in <code>styles.css</code> (after removing the existing content)</li>
</ol>
<p>I have just included the code from <code>TodoList.vue</code> below, but you can see the entire code in the <a href="https://github.com/prashanth1k/go-webview-wails-todo">repo</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;todolist&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">v-for</span><span class="o">=</span><span class="s">&#34;todo in todos.data&#34;</span> <span class="na">:key</span><span class="o">=</span><span class="s">&#34;todo&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;todo-item row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-1&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;checkbox&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;status&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;status&#34;</span> <span class="na">:checked</span><span class="o">=</span><span class="s">&#34;todo.status == &#39;Complete&#39; ? true : false&#34;</span>
</span></span><span class="line"><span class="cl">                        <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;updateTodo(todo)&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-3 dates&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://icongr.am/feather/calendar.svg?size=14&amp;color=D3D3D3&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;&#34;</span><span class="p">&gt;</span> {{
</span></span><span class="line"><span class="cl">                        todo.due?.substring(0, 10) }}
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-7&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    {{ todo.description }}
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-1&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;button error cardaction &#34;</span> <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;deleteTodo(todo)&#34;</span><span class="p">&gt;&lt;</span><span class="nt">img</span>
</span></span><span class="line"><span class="cl">                            <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://icongr.am/feather/trash-2.svg?size=24&amp;color=FFFFFF&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nx">defineProps</span><span class="p">([</span><span class="s1">&#39;todos&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">UpdateTodo</span><span class="p">,</span> <span class="nx">DeleteTodo</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;../../wailsjs/go/main/App&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">emit</span> <span class="o">=</span> <span class="nx">defineEmits</span><span class="p">([</span><span class="s1">&#39;updateTodo&#39;</span><span class="p">,</span> <span class="s1">&#39;deleteTodo&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">updateTodo</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">todo</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`Emitting updateTodo event..!`</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">todo</span><span class="p">.</span><span class="nx">status</span> <span class="o">=</span> <span class="nx">todo</span><span class="p">.</span><span class="nx">status</span> <span class="o">==</span> <span class="s2">&#34;Complete&#34;</span> <span class="o">?</span> <span class="s2">&#34;In Progress&#34;</span> <span class="o">:</span> <span class="s2">&#34;Complete&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">todoResponse</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">UpdateTodo</span><span class="p">(</span><span class="nx">todo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;todoResponse: &#39;</span><span class="p">,</span> <span class="nx">todoResponse</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;updateTodo&#39;</span><span class="p">,</span> <span class="nx">todo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">deleteTodo</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">todo</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`Emitting deleteTodo event..!`</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">todoResponse</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">DeleteTodo</span><span class="p">(</span><span class="nx">todo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;todoResponse: &#39;</span><span class="p">,</span> <span class="nx">todoResponse</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;deleteTodo&#39;</span><span class="p">,</span> <span class="nx">todo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>And.. tada..
<img loading="lazy" src="/2023/go-webview-wails-todo-app.png" type="" alt="go-webview-wails-todo-app"  /></p>
<p>You can also see the output in a browser - just navigate to <code>http://localhost:34115/</code>. The browser window will be useful to refresh on demand and also see errors in the console faster.</p>
<h1 id="adding-the-database">Adding the database</h1>
<p>We will use SQLite and <a href="https://gorm.io/">gorm</a> as the ORM for our app. Include the below libraries in <code>app.go</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">import</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="c1">// ...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="s">&#34;github.com/glebarez/sqlite&#34;</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="s">&#34;gorm.io/gorm&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p>On VSCode, you can follow editor prompts to <code>go get</code> both packages.</p>
<p>Now, include <code>db</code> in <code>App</code> struct -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">App</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">ctx</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">db</span><span class="w">  </span><span class="nx">gorm</span><span class="p">.</span><span class="nx">DB</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>Modify the <code>todo</code> struct to make it special -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">todo</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Id</span><span class="w">          </span><span class="kt">int</span><span class="w">       </span><span class="s">`json:&#34;id&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Description</span><span class="w"> </span><span class="kt">string</span><span class="w">    </span><span class="s">`json:&#34;description&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Due</span><span class="w">         </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"> </span><span class="s">`json:&#34;due&#34; gorm:&#34;type:datetime&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Status</span><span class="w">      </span><span class="kt">string</span><span class="w">    </span><span class="s">`json:&#34;status&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Created</span><span class="w">     </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"> </span><span class="s">`json:&#34;created&#34; gorm:&#34;autoCreateTime;type:datetime&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Updated</span><span class="w">     </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"> </span><span class="s">`json:&#34;updated&#34; gorm:&#34;autoUpdateTime;type:datetime&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>In the <code>startup</code> function (<code>func (a *App) startup(...)</code>), add the below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">startup</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nx">db</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">gorm</span><span class="p">.</span><span class="nf">Open</span><span class="p">(</span><span class="nx">sqlite</span><span class="p">.</span><span class="nf">Open</span><span class="p">(</span><span class="s">&#34;data.db&#34;</span><span class="p">),</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">gorm</span><span class="p">.</span><span class="nx">Config</span><span class="p">{})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="s">&#34;failed to connect database&#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nf">Error</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">a</span><span class="p">.</span><span class="nx">db</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="o">*</span><span class="nx">db</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Connected to database. db exists: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;%t&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">db</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="c1">// AutoMigrate will create the todos table if it does not exist</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">if</span><span class="w"> </span><span class="p">!</span><span class="nx">db</span><span class="p">.</span><span class="nf">Table</span><span class="p">(</span><span class="s">&#34;todos&#34;</span><span class="p">).</span><span class="nf">Migrator</span><span class="p">().</span><span class="nf">HasTable</span><span class="p">(</span><span class="s">&#34;todos&#34;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">err</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">db</span><span class="p">.</span><span class="nf">AutoMigrate</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">todo</span><span class="p">{})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">			</span><span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="s">&#34;Failed to migrate database&#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nf">Error</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>The <code>startup</code> function is called when the app starts. We are using it to connect to the database and create the <code>todos</code> table if it does not exist.</p>
<p>Modify the previous functions to manipulate the DB.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">ListTodos</span><span class="p">()</span><span class="w"> </span><span class="p">[]</span><span class="nx">todo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="c1">// return []todo{{Id: 1, Description: &#34;Code Go&#34;, Due: &#34;2023-10-15&#34;, Status: &#34;In Progress&#34;, Created: &#34;2023-10-01 18:30&#34;}}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="kd">var</span><span class="w"> </span><span class="nx">todos</span><span class="w"> </span><span class="p">[]</span><span class="nx">todo</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">result</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">a</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nf">Find</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">todos</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">if</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nb">panic</span><span class="p">(</span><span class="s">&#34;Failed to retrieve todos: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="p">.</span><span class="nf">Error</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="nx">todos</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">CreateTodo</span><span class="p">(</span><span class="nx">todoItem</span><span class="w"> </span><span class="nx">todo</span><span class="p">)</span><span class="w"> </span><span class="nx">todo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Create: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">todoItem</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="c1">// todoItem.Due, _ = time.Parse(time.RFC3339, todoItem.Due.String())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">result</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">a</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">todoItem</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">if</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Failed to create todo item: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="p">.</span><span class="nf">Error</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">return</span><span class="w"> </span><span class="nx">todo</span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;db result: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">result</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="nx">todoItem</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">UpdateTodo</span><span class="p">(</span><span class="nx">todoItem</span><span class="w"> </span><span class="nx">todo</span><span class="p">)</span><span class="w"> </span><span class="nx">todo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Update: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">todoItem</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">result</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">a</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nf">Save</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">todoItem</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">if</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Failed to update todo item: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="p">.</span><span class="nf">Error</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">return</span><span class="w"> </span><span class="nx">todo</span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;update result: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">todoItem</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="nx">todoItem</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">DeleteTodo</span><span class="p">(</span><span class="nx">todoItem</span><span class="w"> </span><span class="nx">todo</span><span class="p">)</span><span class="w"> </span><span class="nx">todo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Delete: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">todoItem</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">result</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">a</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="s">&#34;id = ?&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">todoItem</span><span class="p">.</span><span class="nx">Id</span><span class="p">).</span><span class="nf">Delete</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">todoItem</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">if</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Failed to delete todo item: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="p">.</span><span class="nf">Error</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">return</span><span class="w"> </span><span class="nx">todo</span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;delete result: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">todoItem</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="nx">todoItem</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">i</span><span class="w"> </span><span class="kd">interface</span><span class="p">{})</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">s</span><span class="p">,</span><span class="w"> </span><span class="nx">_</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">json</span><span class="p">.</span><span class="nf">MarshalIndent</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;\t&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="nb">string</span><span class="p">(</span><span class="nx">s</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>That is it! You now have a fully functional todo app with a database backend.</p>
<h1 id="building-your-app">Building your app</h1>
<p>Building the app is as simple as -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wails build
</span></span></code></pre></div><p>You should now see a fully decked up, single executable file in <code>build\bin</code> folder. Key points to note -</p>
<ul>
<li>the file measures some 13 MB</li>
<li>uses ~18 - 25 MB RAM</li>
</ul>
<p>The above measures should provide you a quick idea of the size compared to Electron-based apps (starts from ~85 MB - easily 100 MB+ on disk, 100-200 MB RAM) and native apps (may be in kb&rsquo;s - to a few MBs, and a couple of MBs of RAM).</p>
<p>Note that the db file is not included in the build - the program will just create the database file in the same folder as the executable (&amp; that may be different from the time you were developing the app).</p>
<h1 id="conclusion">Conclusion</h1>
<p>The todo app is a good start, but there are many features of Wails that I am yet to look into including real-time events and using deskop APIs.  You can see/ play around with the complete code on <a href="https://github.com/prashanth1k/go-webview-wails-todo">Github</a>.</p>
<p>Overall, Wails is a great way to build apps with Go and web technologies. It is easy to get started, and the developer experience is great.</p>
<p>Of course, this post would not be complete without mentioning the power of the web and how a few talented individuals (<a href="https://github.com/leaanthony">Lea Anthony</a> in this case) and supportive communities can do for the ecosystem.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Learn Go and HTMX with a Simple Book Tracker</title>
      <link>https://techformist.com/go-htmx-book-tracker/</link>
      <pubDate>Sun, 24 Sep 2023 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/go-htmx-book-tracker/</guid>
      <description>&lt;p&gt;I have not been a fan of server-driven frontend experiences, but HTMX renaissance has piqued my interest. And yes, that only gets amplified with BunJS claims of astronomical speed for server and what it means for my choice of technologies moving forward. That is for a future post, but here we explore how Golang and HTMX can work together to create a &amp;ldquo;SPA-like&amp;rdquo; experience.&lt;/p&gt;
&lt;p&gt;Features that are of interest here -&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have not been a fan of server-driven frontend experiences, but HTMX renaissance has piqued my interest. And yes, that only gets amplified with BunJS claims of astronomical speed for server and what it means for my choice of technologies moving forward. That is for a future post, but here we explore how Golang and HTMX can work together to create a &ldquo;SPA-like&rdquo; experience.</p>
<p>Features that are of interest here -</p>
<ol>
<li>Go and Go templates</li>
<li>How to get HTMX working with Go templates</li>
<li>How will static files co-exist with the dynamic behavior of HTMX (well, this is just me)</li>
</ol>
<p>What is not considered -</p>
<ol>
<li>Authentication / user handling and all the good stuff</li>
<li>Database and persistence of books</li>
</ol>
<h1 id="install">Install</h1>
<p><a href="https://go.dev/doc/install">Download Go</a> and click on button and tab to install Go on your machine.</p>
<p><a href="https://htmx.org/">HTMX</a> needs no install. We will just reference it with a CDN in the HTML.</p>
<p>Install <code>nodemon</code> globally since Go&rsquo;s <code>go run</code> does not watch for changes.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install -g nodemon
</span></span></code></pre></div><p>If you are stuck anywhere while writing code, refer to the repository on <a href="https://github.com/prashanth1k/go-htmx-playground/">Github</a>.</p>
<h1 id="create-a-new-project">Create a New Project</h1>
<p>Create a new project folder and initialize a Go module.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir go-htmx-playground
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> go-htmx-playground
</span></span><span class="line"><span class="cl">go mod init example.com/go-htmx-playground
</span></span></code></pre></div><p>Your <code>go.mod</code> file should look like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">module</span><span class="w"> </span><span class="nx">example</span><span class="p">.</span><span class="nx">com</span><span class="o">/</span><span class="k">go</span><span class="o">-</span><span class="nx">htmx</span><span class="o">-</span><span class="nx">playground</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">go</span><span class="w"> </span><span class="mf">1.21</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c1">// or whatever the version is </span><span class="w">
</span></span></span></code></pre></div><p>Create a simple server with a new file called <code>main.go</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="s">&#34;log&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="s">&#34;net/http&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="s">&#34;io&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Starting server at http://localhost:8080&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nx">http</span><span class="p">.</span><span class="nf">HandleFunc</span><span class="p">(</span><span class="s">&#34;/hello&#34;</span><span class="p">,</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	  </span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;hello&#34;</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nx">io</span><span class="p">.</span><span class="nf">WriteString</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;Hello, World&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> 	</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nf">ListenAndServe</span><span class="p">(</span><span class="s">&#34;:8080&#34;</span><span class="p">,</span><span class="w"> </span><span class="kc">nil</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>You may have noted that you don&rsquo;t particularly need to type in the <code>import</code>.</p>
<p>Run the server with <code>go run main.go</code> and visit <code>http://localhost:8080/hello</code> to see the output.</p>
<p>It is time to reload server automatically when any changes are made to files.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># install nodemon globally</span>
</span></span><span class="line"><span class="cl">nodemon --exec go run main.go
</span></span></code></pre></div><p>Create a <code>nodemon.json</code> file to specify which folders need to be watched.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;verbose&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;execMap&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;go&#34;</span><span class="p">:</span> <span class="s2">&#34;go&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;html&#34;</span><span class="p">:</span> <span class="s2">&#34;html&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;ignore&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;node_modules/*&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>If you are into auto formatting using <code>prettier</code> and I don&rsquo;t see why you shouldn&rsquo;t, add <code>prettier</code> to work smoothly with Go and Go templates:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm i prettier prettier-plugin-go-template --save-dev
</span></span></code></pre></div><h1 id="modularizing-the-code-and-adding-html">Modularizing the Code and Adding HTML</h1>
<p>We don&rsquo;t want to stuff everything in <code>main.go</code>. Let us create a folder <code>pages</code> and serve all pages from there.</p>
<p>But before creating the HTML page, we want to make sure things work.</p>
<p>Create a new file <code>pages/hello.go</code> and add the following code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">pages</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="s">&#34;io&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="s">&#34;net/http&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">HelloHandler</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">io</span><span class="p">.</span><span class="nf">WriteString</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;Hello, World&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>Update <code>main.go</code> to use the new handler.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="s">&#34;io&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="s">&#34;net/http&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nx">P</span><span class="w"> </span><span class="s">&#34;example.com/go-htmx-playground/pages&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Starting server at http://localhost:8080&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">http</span><span class="p">.</span><span class="nf">HandleFunc</span><span class="p">(</span><span class="s">&#34;/hello&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">P</span><span class="p">.</span><span class="nx">HelloHandler</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nf">ListenAndServe</span><span class="p">(</span><span class="s">&#34;:8080&#34;</span><span class="p">,</span><span class="w"> </span><span class="kc">nil</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>This works as expected. Now, let us create a new file <code>pages/hello.html</code> and add the following code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;UTF-8&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;viewport&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;width=device-width, initial-scale=1.0&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/chota@latest&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/static/css/main.css&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>Booksie<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">nav</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav-center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;brand&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;#&#34;</span><span class="p">&gt;</span>Booksie<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;tabs&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;active&#34;</span><span class="p">&gt;</span>Home<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/help&#34;</span><span class="p">&gt;</span>Help<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">main</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h2</span><span class="p">&gt;</span>My Books<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 card bg-light&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 col-6-md &#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;title-id&#34;</span><span class="p">&gt;</span>Title<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;title&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;title-id&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 col-6-md &#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;author-id&#34;</span><span class="p">&gt;</span>Author<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;author&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;author-id&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 is-right&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;button primary&#34;</span><span class="p">&gt;</span>Add<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="c">&lt;!-- Sample books --&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;</span>The Great Gatsby<span class="p">&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 col-6-md&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        🖋️ F. Scott Fitzgerald   
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>You should now see the glorious HTML page with a form and a sample book.</p>
<p><img loading="lazy" src="/2023/htmx-go-book-tracker-app.png" type="" alt="htmx-go-book-tracker-app"  /></p>
<p>You will notice a couple of things off the bat:</p>
<ol>
<li><a href="https://jenil.github.io/chota/">chota.css</a> for styling. It is a tiny CSS framework that I like to use for simple projects and demos. You can use any CSS framework of your choice.</li>
<li>Custom CSS referenced in the html page does not exist, we will get to that in a bit.</li>
<li>The form does not do anything. We will get to that in a bit as well.</li>
</ol>
<h1 id="serving-static-assets">Serving Static Assets</h1>
<p>We need to serve static files like CSS, JS, and images. Create a new folder <code>static</code> and add a new file <code>static/css/main.css</code> with the following code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">label</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">block</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin-bottom</span><span class="p">:</span> <span class="mf">0.5</span><span class="kt">rem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-weight</span><span class="p">:</span> <span class="kc">bold</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mf">0.9</span><span class="kt">rem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="kc">grey</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">letter-spacing</span><span class="p">:</span> <span class="mf">0.1</span><span class="kt">em</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">h2</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin-top</span><span class="p">:</span> <span class="mi">2</span><span class="kt">em</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Add the below line to <code>main.go</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">http</span><span class="p">.</span><span class="nf">Handle</span><span class="p">(</span><span class="s">&#34;/static/&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nf">StripPrefix</span><span class="p">(</span><span class="s">&#34;/static/&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nf">FileServer</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nf">Dir</span><span class="p">(</span><span class="s">&#34;./static&#34;</span><span class="p">))))</span><span class="w">
</span></span></span></code></pre></div><p>The <code>http.FileServer</code> part is evident. <code>http.StripPrefix(...)</code> is needed to remove the <code>/static/</code> prefix from the URL since -</p>
<ol>
<li>Go http will see <code>static</code> as a directory and try to serve it</li>
<li><code>/static/</code> will get directed to a route <code>../static</code> which does not exist</li>
</ol>
<p>Production sites often have static files or ready content to serve. We will take an example of <code>help</code> page to demonstrate. Create a new file <code>pages/help.html</code> and add any sample content.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="w">  </span><span class="nx">http</span><span class="p">.</span><span class="nf">Handle</span><span class="p">(</span><span class="s">&#34;/help/&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nf">StripPrefix</span><span class="p">(</span><span class="s">&#34;/help/&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nf">FileServer</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nf">Dir</span><span class="p">(</span><span class="s">&#34;./help&#34;</span><span class="p">))))</span><span class="w">
</span></span></span></code></pre></div><h1 id="using-go-templates">Using Go Templates</h1>
<p>With Go templates we separate the content from the presentation.</p>
<p>Add below code to <code>main.go</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">Book</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Title</span><span class="w">  </span><span class="kt">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Author</span><span class="w"> </span><span class="kt">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nx">http</span><span class="p">.</span><span class="nf">HandleFunc</span><span class="p">(</span><span class="s">&#34;/&#34;</span><span class="p">,</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;/ request received&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">path</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&#34;pages/index.html&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">if</span><span class="w"> </span><span class="nx">r</span><span class="p">.</span><span class="nx">URL</span><span class="p">.</span><span class="nx">Path</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s">&#34;/&#34;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">			</span><span class="nx">path</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">&#34;pages&#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">strings</span><span class="p">.</span><span class="nf">TrimSuffix</span><span class="p">(</span><span class="nx">r</span><span class="p">.</span><span class="nx">URL</span><span class="p">.</span><span class="nx">Path</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;/&#34;</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s">&#34;.html&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">books</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">][]</span><span class="nx">Book</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">			</span><span class="s">&#34;Books&#34;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">				</span><span class="p">{</span><span class="nx">Title</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;The Great Gatsby&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Author</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;F. Scott Fitzgerald&#34;</span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">				</span><span class="p">{</span><span class="nx">Title</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;To Kill a Mockingbird&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Author</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;Harper Lee&#34;</span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">				</span><span class="p">{</span><span class="nx">Title</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;1984&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Author</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;George Orwell&#34;</span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">			</span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">tmpl</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">template</span><span class="p">.</span><span class="nf">Must</span><span class="p">(</span><span class="nx">template</span><span class="p">.</span><span class="nf">ParseFiles</span><span class="p">(</span><span class="nx">path</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">tmpl</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="nx">books</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">})</span><span class="w">
</span></span></span></code></pre></div><p><code>books</code> is a just a map of strings to slice of <code>Book</code> struct. We will refer <code>Books</code> within the <code>map</code> in <code>html</code> to render the books in the HTML page. In real world, books will come from a database query.</p>
<p>Replace the hard-coded books in <code>index.html</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"> <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;row&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;books-list&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{ range .Books}}
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 col-6-md card&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;</span>{{ .Title }} <span class="p">&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 col-6-md&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          🖋️ {{ .Author }}   
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    {{ end }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>You will now see books on the site, but the information is coming from the Go server.
All of this is good but it provides a fairly static experience. Importantly, we have not added any functionality to add books.</p>
<p>Enter HTMX.</p>
<h1 id="add-htmx">Add HTMX</h1>
<p>Add the following script to the bottom of the <code>head</code> tag in <code>index.html</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/htmx.org/dist/htmx.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Modify the form to add <code>hx-post</code> and <code>hx-target</code> attributes.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">form</span> <span class="na">hx-post</span><span class="o">=</span><span class="s">&#34;book-add&#34;</span> <span class="na">hx-target</span><span class="o">=</span><span class="s">&#34;#books-list&#34;</span> <span class="na">hx-swap</span><span class="o">=</span><span class="s">&#34;beforeend&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">hx-on::after-request</span><span class="o">=</span><span class="s">&#34; if(event.detail.successful) this.reset()&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 col-6-md &#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;title-id&#34;</span><span class="p">&gt;</span>Title<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;title&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;title-id&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 col-6-md &#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;author-id&#34;</span><span class="p">&gt;</span>Author<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;author&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;author-id&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 is-right&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;button primary&#34;</span><span class="p">&gt;</span>Add<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>You will see that -</p>
<ol>
<li><code>hx-post=&quot;book-add&quot;</code> is meant to call the <code>/book-add</code> route in the Go server</li>
<li><code>hx-target=&quot;#books-list&quot;</code> will update the <code>#books-list</code> element with the response from the server. The response is in the form of HTML and will be added to the <code>#books-list</code> element.</li>
<li><code>hx-swap=&quot;beforeend&quot;</code> will add the response to the end of the <code>#books-list</code> element. We are not replacing the entire book list with the server response, rather just add the new book at the very end of the list. See more on these methods in <a href="https://htmx.org/attributes/hx-swap/">HTMX docs</a></li>
<li>We reset form on successful submission with <code>hx-on::after-request=&quot; if(event.detail.successful) this.reset()</code></li>
</ol>
<p>Add a template reference in the book data rendering code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;row&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;books-list&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{ range .Books}}
</span></span><span class="line"><span class="cl">  {{ block &#34;book-item&#34; . }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 col-6-md card&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;</span>{{ .Title }} <span class="p">&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12 col-6-md&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        🖋️ {{ .Author }}   
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{ end }}
</span></span><span class="line"><span class="cl">  {{ end }}
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The only change you see is the <code>{{ block &quot;book-item&quot; . }}</code> reference. We have used <code>block</code> to create a template reference. Go code will refer to this template reference so that you can just pass in the data and rest of the HTML + CSS will be reused from the HTML file. There are of course more mature ways of handling this in real-world apps including creation of separate template files for individual components.</p>
<p>Add the following code to <code>main.go</code> to handle the <code>book-add</code> request.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">http</span><span class="p">.</span><span class="nf">HandleFunc</span><span class="p">(</span><span class="s">&#34;/book-add&#34;</span><span class="p">,</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nx">title</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">r</span><span class="p">.</span><span class="nf">PostFormValue</span><span class="p">(</span><span class="s">&#34;title&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nx">author</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">r</span><span class="p">.</span><span class="nf">PostFormValue</span><span class="p">(</span><span class="s">&#34;author&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;html request received.. &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">title</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s">&#34; &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">author</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nx">tmpl</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">template</span><span class="p">.</span><span class="nf">Must</span><span class="p">(</span><span class="nx">template</span><span class="p">.</span><span class="nf">ParseFiles</span><span class="p">(</span><span class="s">&#34;pages/index.html&#34;</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nx">tmpl</span><span class="p">.</span><span class="nf">ExecuteTemplate</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;book-item&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Book</span><span class="p">{</span><span class="nx">Title</span><span class="p">:</span><span class="w"> </span><span class="nx">title</span><span class="p">,</span><span class="w"> </span><span class="nx">Author</span><span class="p">:</span><span class="w"> </span><span class="nx">author</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">})</span><span class="w">
</span></span></span></code></pre></div><p>Here -</p>
<ol>
<li>We just receive the <code>post</code> request</li>
<li>Parse and update the content</li>
</ol>
<p>We would have written to a database in real-world apps.</p>
<p>That is it. You have a working app with HTMX and Go, which does not need any refreshes and behaves like a single page app.</p>
<p>See the complete code is on <a href="https://github.com/prashanth1k/go-htmx-playground/">Github</a>.</p>
<h1 id="conclusion">Conclusion</h1>
<ul>
<li>The simplicity of <code>htmx</code> is awesome. It is a great way to add interactivity to the page without having to deal with JavaScript.</li>
<li>HTMX will reduce a lot of code that we have all come to write and love(?)</li>
<li>Javascript will not go anywhere. I find it more intuitive to write JS than Go templates + HTMX (or any other template engine for that matter).</li>
<li>If you take the Javascript part out of the equation, writing future web apps in languages like Go, C#, etc. may in fact be enjoyable.</li>
</ul>
<p>While I continue to not be a fan of <code>server-driven</code> frontend and templates (like Go templates, Pug), I am excited to see how <code>htmx</code> will evolve and what it means for the future of frontend development.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Zoomit - Light-weight presentation and draw tool for Windows</title>
      <link>https://techformist.com/zoomit-annotate-draw-present-tool/</link>
      <pubDate>Sun, 28 May 2023 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/zoomit-annotate-draw-present-tool/</guid>
      <description>&lt;p&gt;I continue to be amazed by the depth of tools created by Sysinternals even after all the tools I have used over years. Zoomit is certainly one of them.&lt;/p&gt;
&lt;p&gt;Now, how many times have you wondered about making things a weebit exciting by drawing something on the screen while you are presenting stuff. Not taking screenshots and pasting in other programs, not using Powerpoint tools and not using video tools - just plain old &lt;code&gt;do things live&lt;/code&gt; and switch context, quickly.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I continue to be amazed by the depth of tools created by Sysinternals even after all the tools I have used over years. Zoomit is certainly one of them.</p>
<p>Now, how many times have you wondered about making things a weebit exciting by drawing something on the screen while you are presenting stuff. Not taking screenshots and pasting in other programs, not using Powerpoint tools and not using video tools - just plain old <code>do things live</code> and switch context, quickly.</p>
<p>Enter Zoomit, a lightweight gem that allows users to effortlessly zoom in, annotate, and draw on their screens, bringing presentations to life.</p>
<ul>
<li>light-weight program, super performant</li>
<li>requires less context switching &amp; shuffling windows</li>
<li>no additional devices needed - all you need is a keyboard &amp; mouse</li>
<li>free</li>
</ul>
<p>ZoomIt&rsquo;s superpower is its ability to annotate anything on your screen with ease. Whether you&rsquo;re giving a coding demo, dissecting complex diagrams, or discussing intricate details, you can effortlessly highlight and explain concepts.</p>
<p>Just hit the shortcut <code>Ctrl + 2</code> and you can -</p>
<ul>
<li>draw lines, shapes, &amp; arrows</li>
<li>Zoom to pointer</li>
<li>write directly on your slides or other applications in real-time</li>
<li>save a screenshot / recording with all the annotations</li>
</ul>
<p>Hit <code>Esc</code> and you can continue the amazing thing that you were doing.</p>
<p><img loading="lazy" src="/2023/annotate-using-zoomit.gif" type="" alt="annotate-using-zoomit"  /></p>
<p>Of course, you take more time when you get started since there is no window to interact with (except for the icon in the system tray). Once you get over that bump, you are going to be as productive as one can be.</p>
<p><a href="https://learn.microsoft.com/en-us/sysinternals/downloads/zoomit">See more / download Zoomit</a> from Microsoft site.</p>
<p>Annoyances -</p>
<ol>
<li>Initial curve may put off people</li>
<li>Getting over the muscle memory of using <code>Ctrl+1</code> / <code>Ctrl+2</code> / etc. in many programs (especially tabs in browsers or in VSCode)</li>
</ol>
<p>Alternatives -</p>
<ul>
<li><a href="https://epicpen.com/">Epic Pen</a> has a free version &amp; looks great. You need a pro version for something basic like drawing rectangles</li>
<li><a href="https://apps.microsoft.com/store/detail/snipping-tool/9MZ95KL8MR0L">Microsoft Snip &amp; Sketch</a>: Comes with windows, or download from Appstore. Free, but the experience is not as pleasant - opens up a new window</li>
</ul>
<p>You can also choose to use <a href="https://support.microsoft.com/en-au/office/draw-and-write-with-ink-in-office-6d76c674-7f4b-414d-b67f-b3ffef6ccf53">Ink tools</a> from Microsoft on supported devices.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Create a simple contact database with Express &amp; Xata</title>
      <link>https://techformist.com/simple-contact-database-xata-express/</link>
      <pubDate>Mon, 19 Dec 2022 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/simple-contact-database-xata-express/</guid>
      <description>&lt;p&gt;I am quite excited with all the developments in the database world. While hosted database is not a new concept, we now have services that are -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;far more focused on usability - support intuitive data types, have spreadsheet-like experience&lt;/li&gt;
&lt;li&gt;have schema editors :)&lt;/li&gt;
&lt;li&gt;support simple migrations&lt;/li&gt;
&lt;li&gt;support more advanced functions like caching without need for black magic&lt;/li&gt;
&lt;li&gt;.. probably include more predictable pricing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://xata.io/&#34;&gt;Xata&lt;/a&gt; is one such database service that ticks a few boxes and is fairly new. In this post, let us look at how easy it is to create a simple contact application with Express and Xata.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I am quite excited with all the developments in the database world. While hosted database is not a new concept, we now have services that are -</p>
<ul>
<li>far more focused on usability - support intuitive data types, have spreadsheet-like experience</li>
<li>have schema editors :)</li>
<li>support simple migrations</li>
<li>support more advanced functions like caching without need for black magic</li>
<li>.. probably include more predictable pricing</li>
</ul>
<p><a href="https://xata.io/">Xata</a> is one such database service that ticks a few boxes and is fairly new. In this post, let us look at how easy it is to create a simple contact application with Express and Xata.</p>
<h2 id="1-setup-the-project">1. Setup the project</h2>
<p>Let us start by setting up the skeleton Express server.</p>
<p>Make sure you have <a href="https://nodejs.org/en/">Node</a> installed on the computer. Create a folder for your project - I will call it <code>crm-express-xata</code>.</p>
<p>Install Express and Typescript with a few commands.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"><span class="k">cd</span> crm-express-xata
</span></span><span class="line"><span class="cl">npm init -y
</span></span><span class="line"><span class="cl">npm i express <span class="s2">&#34;@xata.io/cli&#34;</span> dotenv
</span></span><span class="line"><span class="cl">npm i -d rollup typescript esbuild <span class="s2">&#34;@types/node&#34;</span> ts-node nodemon <span class="s2">&#34;@types/express&#34;</span>
</span></span><span class="line"><span class="cl">node_modules/.bin/tsc --init
</span></span></code></pre></div><p>Here&rsquo;s everything we installed -</p>
<ol>
<li><code>express</code> - Express server</li>
<li><code>dotenv</code> - Import environment variables in the project</li>
<li><code>xata cli</code> - Utility that simplifies creation of tables, and run various other commands</li>
<li><code>rollup</code>, <code>esbuild</code> - Xata dependencies</li>
<li><code>typescript</code> - We will use typescript with Express</li>
<li><code>ts-node</code>, <code>nodemon</code> - Automatically restart Express and appply changes as they happen (&ldquo;hot reload&rdquo;)</li>
<li><code>@types/express</code> and <code>@types/node</code> to install types (and help ease our typing!)</li>
</ol>
<p>You may want to install <code>@xata.io/cli</code> globally if you are planning to use the Xata CLI in multiple projects.</p>
<p>We round up the installation with <code>tsc --init</code> that will create a default <code>tsconfig.json</code> used by Typescript. Observe the file content until your head reels, and replace it with -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;compilerOptions&#34;</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* Language and Environment */</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;target&#34;</span><span class="o">:</span> <span class="s2">&#34;es2016&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;moduleDetection&#34;</span><span class="o">:</span> <span class="s2">&#34;auto&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Modules */</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;module&#34;</span><span class="o">:</span> <span class="s2">&#34;commonjs&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;rootDir&#34;</span><span class="o">:</span> <span class="s2">&#34;src&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;moduleResolution&#34;</span><span class="o">:</span> <span class="s2">&#34;node&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;allowSyntheticDefaultImports&#34;</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;lib&#34;</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;esnext&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Emit */</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;outDir&#34;</span><span class="o">:</span> <span class="s2">&#34;dist&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;sourceMap&#34;</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Interop Constraints */</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;esModuleInterop&#34;</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;forceConsistentCasingInFileNames&#34;</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Type Checking */</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;strict&#34;</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Completeness */</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;skipLibCheck&#34;</span><span class="o">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Create a new file called <code>nodemon.json</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;watch&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;src&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;ext&#34;</span><span class="p">:</span> <span class="s2">&#34;ts,json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;ignore&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;src/**/*.spec.ts&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;exec&#34;</span><span class="p">:</span> <span class="s2">&#34;ts-node ./src/index.ts&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>nodemon</code> along with <code>ts-node</code> will ensure that our changes are reflected as we develop the application. You can simply navigate to your project directory in a terminal, and call <code>nodemon</code> for the hot reloading to work.</p>
<p>Or, better yet - change the <code>scripts</code> section in <code>package.json</code> file to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;scripts&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;dev&#34;</span><span class="p">:</span> <span class="s2">&#34;nodemon&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;test&#34;</span><span class="p">:</span> <span class="s2">&#34;echo \&#34;Error: no test specified\&#34; &amp;&amp; exit 1&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="err">,</span>
</span></span></code></pre></div><p>Create a new file called <code>src/index.ts</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="p">(</span><span class="s2">&#34;hello world&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>You can now type in <code>npm dev</code> to see your application in action.</p>
<p><img loading="lazy" src="/2022/npm-run-dev-express-ts.png" type="" alt="npm-run-dev-express-ts"  /></p>
<p>Before we forget, let us create a <code>.gitignore</code> file to version control only those files that make sense. Use the below content for <code>.gitignore</code> for now -</p>
<pre tabindex="0"><code>node_modules
dist
.env
</code></pre><p>Alternatively, copy over the <code>.gitignore</code> content from the <a href="https://github.com/prashanth1k/crm-express-xata">crm-express-xata repo</a>.</p>
<p>If you don&rsquo;t mind seeing more code in a demo project and want to simplify the setup, you can always use a starter template with this command - <code>pnpx typescript-express-starter crm-express-xata</code>. You can avoid all the manual steps of setting up Express and Typescript with that single command (you can then ignore the majority of steps in this section!).</p>
<h2 id="2-setup-xata">2. Setup Xata</h2>
<p>Head over to <a href="https://app.xata.io/workspaces">Xata</a> and sign up for the free plan. With support for 750k records and 75 requests per second, we should be more than able to test the service in a pilot project.</p>
<p>You will land up on a home page with a blank workspace.
<img loading="lazy" src="/2022/xata-home-workspace.png" type="" alt="xata-home-workspace"  /></p>
<p>Create a database <code>contactdb</code> in your favourite region. Click on <code>Schema</code> link on the left navigation bar to visualize all tables (only one at this time), fields, and their relationships.</p>
<p><img loading="lazy" src="/2022/xata-schema-view.png" type="" alt="xata-schema-view"  /></p>
<p>Add a table called <code>contact</code> with the following columns -</p>
<ul>
<li>name - of type <code>string</code>, <code>not null</code></li>
<li>email - of type <code>email</code></li>
</ul>
<p>Column types are self explanatory and &ldquo;linking&rdquo; of the user table allows you to tag user records from the <code>contact</code> table.</p>
<p>Add other table(s) by clicking like crazy in your Xata workspace, and create the below table/columns.</p>
<ul>
<li>activity
<ul>
<li>description | <code>string</code>, <code>not null</code></li>
<li>type</li>
<li>status</li>
<li>contact | link to <code>contact</code> table</li>
</ul>
</li>
</ul>
<p>Click on any table from the left navigation bar under <code>Tables</code> header to see records in the table. Click on <code>Get code snippet</code> to see instructions on installing xata library and code snippets for accessing the table.</p>
<p><img loading="lazy" src="/2022/xata-table-setup-script.png" type="" alt="/2022/xata-table-setup-script.png"  /></p>
<p>I will install Xata library as dev depedency since I don&rsquo;t need them elsewhere.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm install -d @xata.io/cli
</span></span></code></pre></div><p>Copy the URL from the init snippet.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">xata init --db https://demo.us-east-1.xata.sh/db/contactdb
</span></span></code></pre></div><h2 id="3-code-the-foundation-for-express">3. Code the foundation for Express</h2>
<p>Create a <code>.env</code> file in your project root directory -</p>
<pre tabindex="0"><code>PORT=3000
</code></pre><p>The contents of the file will be used at various stages in the project.</p>
<p>Change the content of <code>src/index.ts</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">express</span><span class="p">,</span> <span class="p">{</span> <span class="nx">Express</span><span class="p">,</span> <span class="nx">Request</span><span class="p">,</span> <span class="nx">Response</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;express&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">dotenv</span> <span class="kr">from</span> <span class="s2">&#34;dotenv&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// read env file
</span></span></span><span class="line"><span class="cl"><span class="nx">dotenv</span><span class="p">.</span><span class="nx">config</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// initialize
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">app</span>: <span class="kt">Express</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">port</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">PORT</span> <span class="o">||</span> <span class="mi">3001</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/api&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span>: <span class="kt">Request</span><span class="p">,</span> <span class="nx">res</span>: <span class="kt">Response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">({</span> <span class="nx">msg</span><span class="o">:</span> <span class="s2">&#34;hello&#34;</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="nx">port</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Express server listening on port&#34;</span><span class="p">,</span> <span class="nx">port</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Here&rsquo;s what we are doing here -</p>
<ol>
<li>Import <code>express</code>, <code>dotenv</code></li>
<li>Initiate <code>express</code></li>
<li>Create a simple test api at <code>/api</code> that responds with a simple JSON message</li>
<li>Start the server</li>
</ol>
<p>Start the program with <code>npm dev</code>. Use your favourite API client to invoke a <code>get</code> request to <code>http://localhost:3000/api</code> to see the below response -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;msg&#34;</span><span class="p">:</span> <span class="s2">&#34;hello&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Now that we know the Express server is working, let us setup Xata in Express.
Go back to the project directory in terminal and enter -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node_modules/.bin/xata init --db https://demo.us-east-1.xata.sh/db/contactdb
</span></span></code></pre></div><p>If you have installed the CLI globally, you just use <code>xata init</code> without prefix. You must replace the URL here with the one copied over from the code snippet from Xata website.</p>
<p>The <code>init</code> command will -</p>
<ul>
<li>prompt you to enter your credentials</li>
<li>generate a secret key and update your key in <code>.env</code> file</li>
<li>create a <code>xata.ts</code> file that will provide the types for your database / tables</li>
</ul>
<p>Neat.</p>
<h2 id="4-code-the-contact-route">4. Code the Contact Route</h2>
<p>Create <code>/services/contact.ts</code> with one route -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">express</span><span class="p">,</span> <span class="p">{</span> <span class="nx">Router</span><span class="p">,</span> <span class="nx">Request</span><span class="p">,</span> <span class="nx">Response</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;express&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">XataClient</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;../xata&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">dotenv</span> <span class="kr">from</span> <span class="s2">&#34;dotenv&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">dotenv</span><span class="p">.</span><span class="nx">config</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span>: <span class="kt">Router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">xata</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">XataClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span>: <span class="kt">Request</span><span class="p">,</span> <span class="nx">res</span>: <span class="kt">Response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Trying to get contact records..&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">query</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">rec</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">xata</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nx">contact</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">query</span><span class="p">).</span><span class="nx">getMany</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="nx">rec</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;..done&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><p><code>xata.db.contact.filter(query).getMany()</code> queries Xata for contact records.</p>
<p>In <code>index.js</code>, add -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">contact</span> <span class="kr">from</span> <span class="s2">&#34;./services/contact&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// .. other code
</span></span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">json</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="s2">&#34;/api/contact/&#34;</span><span class="p">,</span> <span class="nx">contact</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// .. other code
</span></span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="nx">port</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Express server listening on port&#34;</span><span class="p">,</span> <span class="nx">port</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Save files to restart server and you should now be able to get all contact records at <code>http://localhost:3000/api/contact</code>.</p>
<p>You don&rsquo;t need to code contact routes in a separate file, but this structure reduces some clutter in <code>main.js</code> (&amp; helps to scale in future).</p>
<p>Let us code in other methods in <code>contact.ts</code> as well and the entire file should like this -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">express</span><span class="p">,</span> <span class="p">{</span> <span class="nx">Router</span><span class="p">,</span> <span class="nx">Request</span><span class="p">,</span> <span class="nx">Response</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;express&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">XataClient</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;../xata&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">dotenv</span> <span class="kr">from</span> <span class="s2">&#34;dotenv&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">dotenv</span><span class="p">.</span><span class="nx">config</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span>: <span class="kt">Router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">xata</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">XataClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span>: <span class="kt">Request</span><span class="p">,</span> <span class="nx">res</span>: <span class="kt">Response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Trying to get contact records..&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">query</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">rec</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">xata</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nx">contact</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">query</span><span class="p">).</span><span class="nx">getMany</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="nx">rec</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;..done&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/:id&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span>: <span class="kt">Request</span><span class="p">,</span> <span class="nx">res</span>: <span class="kt">Response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">recId</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Trying to query for&#34;</span><span class="p">,</span> <span class="nx">recId</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">recId</span> <span class="o">===</span> <span class="s2">&#34;undefined&#34;</span><span class="p">)</span> <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">&#34;Id is undefined&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="k">await</span> <span class="nx">xata</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nx">contact</span><span class="p">.</span><span class="nx">read</span><span class="p">(</span><span class="nx">recId</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span>: <span class="kt">Request</span><span class="p">,</span> <span class="nx">res</span>: <span class="kt">Response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Creating contact:&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="k">await</span> <span class="nx">xata</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nx">contact</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">patch</span><span class="p">(</span><span class="s2">&#34;/:id&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span>: <span class="kt">Request</span><span class="p">,</span> <span class="nx">res</span>: <span class="kt">Response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Updating contact:&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="k">await</span> <span class="nx">xata</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nx">contact</span><span class="p">.</span><span class="nx">update</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="s2">&#34;/:id&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span>: <span class="kt">Request</span><span class="p">,</span> <span class="nx">res</span>: <span class="kt">Response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Deleting contact:&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="k">await</span> <span class="nx">xata</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nx">contact</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><p>You should now be able to invoke the below methods.</p>
<ol>
<li>Create a new contact: <code>POST</code>: <code>http://localhost:3000/api/contact</code>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Jane Doe&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;jane@doe.com&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>Update a contact: <code>PATCH</code>: <code>http://localhost:3000/api/contact/rec_ceq4gkr6bfqmhh8thsdg</code>, where <code>rec_ceq4gkr6bfqmhh8thsdg</code> is the contact id to update
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Jane Doe&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;jane@doe1.com&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>Delete a contact <code>DELETE</code>: <code>http://localhost:3000/api/contact/rec_ceq4gkr6bfqmhh8thsdg</code></li>
</ol>
<p>We are also interested in getting activities for the contact. In other words, we want to get activities for a given contact id.</p>
<p>Add a different route handler in the same <code>contact.ts</code> file at the very end (just before the <code>export</code> statement)-</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// other code
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/:id/activity&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span>: <span class="kt">Request</span><span class="p">,</span> <span class="nx">res</span>: <span class="kt">Response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">recId</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Trying to query for&#34;</span><span class="p">,</span> <span class="nx">recId</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">recId</span> <span class="o">===</span> <span class="s2">&#34;undefined&#34;</span><span class="p">)</span> <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">&#34;Id is undefined&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">query</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">contact</span><span class="o">:</span> <span class="p">{</span> <span class="nx">id</span>: <span class="kt">recId</span> <span class="p">}</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">rec</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">xata</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nx">activity</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">query</span><span class="p">).</span><span class="nx">getMany</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="nx">rec</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><p>You should now be able to invoke <code>http://localhost:3000/api/contact/rec_cepc3ptvjen51bb31gig/activity</code> to get all activities for the contact id <code>rec_cepc3ptvjen51bb31gig</code>.</p>
<h2 id="5-code-the-activity-route">5. Code the Activity Route</h2>
<p>Add code to handle Activity methods similar to Contact.</p>
<p>Create a new file <code>/services/activity.ts</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">express</span><span class="p">,</span> <span class="p">{</span> <span class="nx">Router</span><span class="p">,</span> <span class="nx">Request</span><span class="p">,</span> <span class="nx">Response</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;express&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">XataClient</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;../xata&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">dotenv</span> <span class="kr">from</span> <span class="s2">&#34;dotenv&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">dotenv</span><span class="p">.</span><span class="nx">config</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span>: <span class="kt">Router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">xata</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">XataClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/:id&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span>: <span class="kt">Request</span><span class="p">,</span> <span class="nx">res</span>: <span class="kt">Response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">recId</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Trying to query for&#34;</span><span class="p">,</span> <span class="nx">recId</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">recId</span> <span class="o">===</span> <span class="s2">&#34;undefined&#34;</span><span class="p">)</span> <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">&#34;Id is undefined&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="k">await</span> <span class="nx">xata</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nx">activity</span><span class="p">.</span><span class="nx">read</span><span class="p">(</span><span class="nx">recId</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span>: <span class="kt">Request</span><span class="p">,</span> <span class="nx">res</span>: <span class="kt">Response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Creating activity:&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="k">await</span> <span class="nx">xata</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nx">activity</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">patch</span><span class="p">(</span><span class="s2">&#34;/:id&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span>: <span class="kt">Request</span><span class="p">,</span> <span class="nx">res</span>: <span class="kt">Response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Updating activity:&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="k">await</span> <span class="nx">xata</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nx">activity</span><span class="p">.</span><span class="nx">update</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="s2">&#34;/:id&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span>: <span class="kt">Request</span><span class="p">,</span> <span class="nx">res</span>: <span class="kt">Response</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Deleting activity:&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="k">await</span> <span class="nx">xata</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nx">activity</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><p>Add pointer to this handler in <code>index.ts</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="s2">&#34;/api/activity/&#34;</span><span class="p">,</span> <span class="nx">activity</span><span class="p">);</span>
</span></span></code></pre></div><p>You should now be able to invoke activity methods as easily -</p>
<ol>
<li><code>POST</code>: <code>http://localhost:3000/api/activity</code></li>
<li><code>PATCH</code>: <code>http://localhost:3000/api/activity/some_activity_id</code></li>
<li><code>DELETE</code>: <code>http://localhost:3000/api/activity/some_activity_id</code></li>
</ol>
<h2 id="6-conclusion">6. Conclusion</h2>
<p>Congratulations, you have built your own CRM app that can track contacts and activities.
Find the complete code on this <a href="https://github.com/prashanth1k/crm-express-xata">Github repository</a>.</p>
<p>In summary, you have seen how simple it is to use Xata in Express.</p>
<p>You can further explore -</p>
<ul>
<li>Xata support to apply changes and learn how DB changes can tag along the branches - <a href="https://xata.io/docs/api-reference/dbs/db_name#list-branches">https://xata.io/docs/api-reference/dbs/db_name#list-branches</a></li>
<li>Import CSV file to your DB with CLI - <a href="https://xata.io/docs/cli/import-data">https://xata.io/docs/cli/import-data</a></li>
<li>Adding basic auth - <a href="https://xata.io/docs/quickstart/adding-basic-auth-with-xata">https://xata.io/docs/quickstart/adding-basic-auth-with-xata</a></li>
</ul>
<p>Overall Xata, while quite new, has a few positives going for it -</p>
<ul>
<li>Easy to use ORM experience, similar to that in Prisma</li>
<li>Easy to use, but powerful search &amp; analytics features</li>
<li>Combines the power of PostgreSQL (which is the DB backend for Xata) with Elastic search for proven search functions. See <a href="https://xata.io/docs/intro/how-it-works">https://xata.io/docs/intro/how-it-works</a></li>
<li>Cool branching &amp; migration features</li>
</ul>
<p>Be prepared for a few downsides -</p>
<ul>
<li>Lack of help in the wild</li>
<li>While the documentation is decent, has limited examples. I don&rsquo;t see the current documentation structure to be intuitive, but that may be just me</li>
<li>Not fully tested in real-world</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Create a blog on Sveltekit</title>
      <link>https://techformist.com/create-blog-sveltekit/</link>
      <pubDate>Mon, 14 Nov 2022 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/create-blog-sveltekit/</guid>
      <description>&lt;p&gt;In this post let us create a simple blog using Sveltekit.&lt;/p&gt;
&lt;p&gt;Why Sveltekit if you ask -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Because it&amp;rsquo;s cool&lt;/li&gt;
&lt;li&gt;Make your pages interactive without a big JS payload for the client&lt;/li&gt;
&lt;li&gt;Fast&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Get started with the following command in your favorite terminal -&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmd&#34; data-lang=&#34;cmd&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pnpm create svelte@latest avix-blog-sveltekit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should initiate the folder with basic sveltekit structure and initiate a few files.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://techformist.com/2022/create-sveltekit-app-blog.png&#34; type=&#34;&#34; alt=&#34;create-sveltekit-app-blog&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;Choose &lt;code&gt;Skeleteon project&lt;/code&gt; as an option and select/de-select Javascript, Prettier and ESLint options based on your preferences.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In this post let us create a simple blog using Sveltekit.</p>
<p>Why Sveltekit if you ask -</p>
<ol>
<li>Because it&rsquo;s cool</li>
<li>Make your pages interactive without a big JS payload for the client</li>
<li>Fast</li>
</ol>
<p>Get started with the following command in your favorite terminal -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">pnpm create svelte@latest avix-blog-sveltekit
</span></span></code></pre></div><p>This should initiate the folder with basic sveltekit structure and initiate a few files.</p>
<p><img loading="lazy" src="/2022/create-sveltekit-app-blog.png" type="" alt="create-sveltekit-app-blog"  /></p>
<p>Choose <code>Skeleteon project</code> as an option and select/de-select Javascript, Prettier and ESLint options based on your preferences.</p>
<p>Install dependencies, open the project in an editor of your choice and run the project.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"><span class="k">cd</span> avix-blog-sveltekit
</span></span><span class="line"><span class="cl">pnpm i
</span></span><span class="line"><span class="cl">code .
</span></span><span class="line"><span class="cl">pnpm run dev
</span></span></code></pre></div><p>Navigate to <code>http://localhost:5173/</code> to see this beautiful page.</p>
<p><img loading="lazy" src="/2022/sveltekit-skeleton-starting-page.png" type="" alt="sveltekit-skeleton-starting-page"  /></p>
<p>We will use a small CSS library called <a href="https://jenil.github.io/chota/">chota</a> - not fussing on styling in this example.</p>
<p>Include the below line in <code>src/app.html</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/chota@latest&#34;</span><span class="p">&gt;</span>
</span></span></code></pre></div><h2 id="routing-and-static-pages">Routing and Static Pages</h2>
<p>Sveltekit enables easy and dynamic routing.</p>
<ul>
<li>Any page within <code>src/routes</code> folder is a route in the app</li>
<li>Define the page content using <code>+page.svelte</code> within the specific route folder</li>
</ul>
<p>Create an <code>about</code> route -</p>
<ol>
<li>Create a folder <code>src/routes/about</code></li>
<li>Create a file called <code>src/routes/about/+page.svelte</code></li>
</ol>
<p>Use below content for the new <code>+page.svelte</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  About
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">b</span><span class="p">&gt;</span>This is the greatest blog that has ever been written<span class="p">&lt;/</span><span class="nt">b</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam hendrerit nisi sed sollicitudin pellentesque. Nunc posuere purus rhoncus pulvinar aliquam. Ut aliquet tristique nisl vitae volutpat. Nulla aliquet porttitor venenatis. Donec a dui et dui fringilla consectetur id nec massa. Aliquam erat volutpat. 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Sed ut dui ut lacus dictum fermentum vel tincidunt neque. Sed sed lacinia lectus. Duis sit amet sodales felis. Duis nunc eros, mattis at dui ac, convallis semper risus. In adipiscing ultrices tellus, in suscipit massa vehicula eu.
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The convention of using <code>+</code> in file names is picked up by Sveltekit.</p>
<ol>
<li>We have already established that <code>about</code> folder signifies a route. <code>+page.svelte</code> in that folder is the &ldquo;root page&rdquo; that gets rendered when you go to <code>example.com/about</code>. This page gets server rendered for the first request, and rendered in client for subsequent requests</li>
<li>Other files of interest in the same <code>about</code> folder (all files optional) -</li>
</ol>
<ul>
<li><code>+page.js</code> - Do stuff before <code>+page.svelte</code> gets rendered</li>
<li><code>+page.server.js</code> - Run this JS only on server (e.g. fetch data from DB)</li>
<li><code>+error.svelte</code> - Custom error page</li>
</ul>
<ol>
<li>See the <a href="https://kit.svelte.dev/docs/routing">sveltekit routing docs</a> to understand more on the different file name conventions</li>
</ol>
<p>While I have nothing but admiration for the <a href="https://github.com/sveltejs/kit/discussions/5748">thinking that has gone in the routing structure</a>, I was happier with the older, simpler file structure.</p>
<p>Create another file called <code>blog/+page.svelte</code> with the below content -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>Blog<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>My blog will be written here.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Visit <code>http://localhost:5173/about</code> and <code>http://localhost:5173/blog</code> to see the pages.</p>
<p><img loading="lazy" src="/2022/sveltekit-blog-about-page.png" type="" alt="sveltekit-blog-about-page"  /></p>
<p>While this content is great and everything, the pages need a bit more work to bring consistent styling and to avoid using HTML for every new post.</p>
<h2 id="create-layouts">Create layouts</h2>
<p>Layouts help us define styling and structure at a root level, or for every page.</p>
<p>Get started with a common layout that is applicable for all pages. Create <code>+layout.svelte</code> in <code>src/routes</code> folder.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">nav</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav-center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">			<span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/&#34;</span><span class="p">&gt;</span>Home<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">			<span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;active&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog&#34;</span><span class="p">&gt;</span>Blog<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">			<span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/about&#34;</span><span class="p">&gt;</span>About<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">main</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">slot</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;&#34;</span><span class="p">&gt;</span>(c) My blog<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">main</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">margin-bottom</span><span class="p">:</span> <span class="mi">50</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nt">footer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">font-size</span><span class="p">:</span> <span class="kc">smaller</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">padding-top</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">position</span><span class="p">:</span> <span class="kc">fixed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">height</span><span class="p">:</span> <span class="mi">50</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">background-color</span><span class="p">:</span> <span class="kc">gainsboro</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">bottom</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">left</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">right</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">margin-bottom</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The blog looks much better.</p>
<p><img loading="lazy" src="/2022/sveltekit-blog-with-layout.png" type="" alt="sveltekit-blog-with-layout"  /></p>
<p>Click on the navigation links to see some SPA action.</p>
<p>Take note of a couple of interesting things..</p>
<ul>
<li>CSS is included in the layout itself, which is also a Svelte component. This CSS is scoped to the layout, but can manifest itself across the apps because of its nature (e.g., you see the layout across pages)</li>
<li><code>slot</code> houses the components that gets rendered as pages. For e.g, the <code>About</code> page HTML replaces <code>&lt;slot&gt;</code></li>
</ul>
<p>Let us improve this layout a bit. Instead of typing in header in the same layout, let us all header info in a separate component.</p>
<p>Create a new file <code>src/lib/Header.svelte</code> and move header content from <code>+layout.svelte</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">nav</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav-center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">			<span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/&#34;</span><span class="p">&gt;</span>Home<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">			<span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;active&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog&#34;</span><span class="p">&gt;</span>Blog<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">			<span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/about&#34;</span><span class="p">&gt;</span>About<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create a new file for styles at <code>src/lib/styles/custom.css</code> and move style content from <code>+layout.svelte</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">main</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">margin-bottom</span><span class="p">:</span> <span class="mi">50</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nt">footer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">font-size</span><span class="p">:</span> <span class="kc">smaller</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">padding-top</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">position</span><span class="p">:</span> <span class="kc">fixed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">height</span><span class="p">:</span> <span class="mi">50</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">background-color</span><span class="p">:</span> <span class="kc">gainsboro</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">bottom</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">left</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">right</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">margin-bottom</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The folder <code>src/lib</code> can contain the internal library of the app (which is a blog in our case). <code>$lib</code> is processed internally by Svelte to point to the right location of the components, styles or anything that you need to reuse across your app.</p>
<p>Import <code>Header.svelte</code> and <code>custom.css</code> in the the layout file <code>src/routes/+layout.svelte</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="kr">import</span> <span class="nx">Header</span> <span class="nx">from</span> <span class="s1">&#39;$lib/components/Header.svelte&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kr">import</span> <span class="s1">&#39;$lib/styles/custom.css&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">Header</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">main</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">slot</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;&#34;</span><span class="p">&gt;</span>(c) My blog<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Well, we are no accomplishing much by moving 5 lines of code, but the technique demonstrates using reusable components in Svelte. You can add global styles in <code>layout</code> or in <code>app.html</code> - we did the latter for the chota css library.</p>
<p>The end result will be the same as earlier, but also note that -</p>
<ul>
<li>View the page source to see the CSS embedded in the HTML page</li>
<li>HTML + CSS is mixed and sent by server, not rendered on client</li>
</ul>
<p>Let us change <code>src/blog/+page.svelte</code> in a similar way.
Create a new file <code>src/lib/styles/blog.css</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">ul</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">list-style</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">padding-left</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">sidebar-content</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">margin-top</span><span class="p">:</span> <span class="mi">4</span><span class="kt">em</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">position</span><span class="p">:</span> <span class="kc">fixed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">padding</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">width</span><span class="p">:</span> <span class="mi">180</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">border</span><span class="p">:</span> <span class="mi">1</span><span class="kt">px</span> <span class="kc">silver</span> <span class="kc">solid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You can now change <code>src/blog/+page.svelte</code> to include the new <code>blog-sidebar</code> class.. Or, do something even better using our knowledge layouts.</p>
<p>Create a new file <code>src/blog/+layout.svelte</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="kr">import</span> <span class="s1">&#39;$lib/styles/blog.css&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kd">let</span> <span class="nx">featLinks</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">		<span class="p">{</span> <span class="nx">url</span><span class="o">:</span> <span class="s1">&#39;/about&#39;</span><span class="p">,</span> <span class="nx">title</span><span class="o">:</span> <span class="s1">&#39;About&#39;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">		<span class="p">{</span> <span class="nx">url</span><span class="o">:</span> <span class="s1">&#39;/blog/hello-world&#39;</span><span class="p">,</span> <span class="nx">title</span><span class="o">:</span> <span class="s1">&#39;Hello World&#39;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-8&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">			<span class="p">&lt;</span><span class="nt">slot</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-4&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">			<span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;sidebar-content&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">				<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">					<span class="p">&lt;</span><span class="nt">strong</span><span class="p">&gt;</span>Featured Links<span class="p">&lt;/</span><span class="nt">strong</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">				<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">				<span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">					{#each featLinks as featLink}
</span></span><span class="line"><span class="cl">						<span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">							<span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">{featLink.url}</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">								{featLink.title}
</span></span><span class="line"><span class="cl">							<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">						<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">					{/each}
</span></span><span class="line"><span class="cl">				<span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">			<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Note that -</p>
<ul>
<li>This layout file is automatically included for all routes under <code>blog</code>. In other words - the layout is used for the blog home page and all blog posts.</li>
<li>The class <code>row</code>, <code>column</code> etc. are provided by chota css and makes the page is fully responsive.
Also, you can modify fetching the featured content in real-time - we are not going there at the moment.</li>
</ul>
<p>Lo and behold - your new blog layout. Resize the window to see the side bar move to the side or to the bottom.</p>
<p><img loading="lazy" src="/2022/blog-layout-sidebar.png" type="" alt="blog-layout-sidebar"  /></p>
<h2 id="support-markdown">Support Markdown</h2>
<p>We can continue to write HTML in each of the blog pages, or we could make things easier for writing content using markdown. We will do the latter, of course.</p>
<p>Handle markdown using a library called <code>mdsvex</code>, which will preprocess markdown files and convert them to render to web pages.</p>
<p>Install <code>mdsvex</code> to get started.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">pnpm i -D mdsvex
</span></span></code></pre></div><p>Open <code>svelte.config.js</code> in the root folder. Change <code>config</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">config</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">kit</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">adapter</span><span class="o">:</span> <span class="nx">adapter</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">	<span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="nx">preprocess</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">		<span class="nx">mdsvex</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">			<span class="nx">extensions</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;.md&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">		<span class="p">})</span>
</span></span><span class="line"><span class="cl">	<span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>This config tells <code>mdsvex</code> to handle <code>md</code> files and convert them to HTML. It will also enable us to use Svelte components within markdown.</p>
<p>Now, there is more than one way to read Markdown files and serve content to the client. We will -</p>
<ol>
<li>Write server logic to read markdown files and convert the title/path to JSON, and retrieve list of files to show the list of blog posts</li>
<li>Write even more server logic to read markdown file content for a single post and show content on the blog post page</li>
</ol>
<h2 id="serve-list-of-blog-posts">Serve List of Blog Posts</h2>
<p>Create a new file <code>routes/api/posts/server.js</code> in the root folder.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">json</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;@sveltejs/kit&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">GET</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;GET invoked..&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">allPosts</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetchPosts</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">sortedPosts</span> <span class="o">=</span> <span class="nx">allPosts</span><span class="p">.</span><span class="nx">sort</span><span class="p">((</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="nx">b</span><span class="p">.</span><span class="nx">meta</span><span class="p">.</span><span class="nx">date</span><span class="p">)</span> <span class="o">-</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="nx">a</span><span class="p">.</span><span class="nx">meta</span><span class="p">.</span><span class="nx">date</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">});</span>
</span></span><span class="line"><span class="cl">	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Posts:&#39;</span><span class="p">,</span> <span class="nx">sortedPosts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;.. GET done&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nx">json</span><span class="p">(</span><span class="nx">sortedPosts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">fetchPosts</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">postFiles</span> <span class="o">=</span> <span class="kr">import</span><span class="p">.</span><span class="nx">meta</span><span class="p">.</span><span class="nx">glob</span><span class="p">(</span><span class="s1">&#39;/src/routes/blog/*.md&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">entries</span><span class="p">(</span><span class="nx">postFiles</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">allPosts</span> <span class="o">=</span> <span class="kr">await</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">		<span class="nx">posts</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="kr">async</span> <span class="p">([</span><span class="nx">path</span><span class="p">,</span> <span class="nx">resolver</span><span class="p">])</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="kr">const</span> <span class="p">{</span> <span class="nx">metadata</span> <span class="p">}</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">resolver</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">			<span class="kr">const</span> <span class="nx">postPath</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="o">-</span><span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="nx">meta</span><span class="o">:</span> <span class="nx">metadata</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				<span class="nx">path</span><span class="o">:</span> <span class="nx">postPath</span>
</span></span><span class="line"><span class="cl">			<span class="p">};</span>
</span></span><span class="line"><span class="cl">		<span class="p">})</span>
</span></span><span class="line"><span class="cl">	<span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nx">allPosts</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>In this file -</p>
<ol>
<li>We just read all files</li>
<li>Retrieve metadata (markdown frontmatter) within the <code>---</code> lines to check title and date</li>
<li>Support <code>GET</code> request to serve the list of posts sorted by date</li>
</ol>
<p>Sveltekit runs this logic only on the server. Navigate to <code>http://localhost:5173/api/posts</code> to see the JSON content</p>
<p>Change <code>routes/blog/+page.svelte</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">script</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="kd">let</span> <span class="nx">posts</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kd">let</span> <span class="nx">promise</span> <span class="o">=</span> <span class="nx">getPosts</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="kr">async</span> <span class="kd">function</span> <span class="nx">getPosts</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;blog loading..&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span><span class="s1">&#39;http://localhost:5173/api/posts&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">posts</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;posts&#39;</span><span class="p">,</span> <span class="nx">posts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;.. blog loading done&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="nx">posts</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">/script&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">h1</span><span class="o">&gt;</span><span class="nx">Blog</span><span class="o">&lt;</span><span class="err">/h1&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="nx">This</span> <span class="nx">is</span> <span class="nx">an</span> <span class="nx">awesome</span> <span class="nx">blog</span> <span class="nx">about</span> <span class="nx">sveltekit</span><span class="p">.</span><span class="o">&lt;</span><span class="err">/p&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="err">#</span><span class="kr">await</span> <span class="nx">promise</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="nx">fetching</span> <span class="nx">posts</span><span class="p">..</span><span class="o">&lt;</span><span class="err">/p&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="o">:</span><span class="nx">then</span> <span class="nx">posts</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">{</span><span class="err">#</span><span class="nx">each</span> <span class="nx">posts</span> <span class="nx">as</span> <span class="nx">post</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="o">&lt;</span><span class="nx">div</span> <span class="kr">class</span><span class="o">=</span><span class="s2">&#34;list-post&#34;</span><span class="o">&gt;&lt;</span><span class="nx">a</span> <span class="nx">href</span><span class="o">=</span><span class="p">{</span><span class="nx">post</span><span class="o">?</span><span class="p">.</span><span class="nx">path</span><span class="p">}</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">post</span><span class="o">?</span><span class="p">.</span><span class="nx">meta</span><span class="o">?</span><span class="p">.</span><span class="nx">title</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/a&gt;&lt;/div&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">{</span><span class="err">/each}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="err">/await}</span>
</span></span></code></pre></div><ol>
<li><code>getPosts</code> fetches post metadata from API</li>
<li>Rest of the content including <code>await</code>/<code>then</code> is standard svelte to support promises (more details <a href="https://svelte.dev/docs#template-syntax-await">here</a>)</li>
</ol>
<p>You should now be able to see blog posts at <code>http://localhost:5173/blog</code>.</p>
<p><img loading="lazy" src="/2022/sveltekit-blog-list-markdown.png" type="" alt="sveltekit-blog-list-markdown"  /></p>
<h2 id="display-a-single-blog-post">Display a Single Blog Post</h2>
<p>Create a new file <code>routes/[blog]/[slug]/page.js]</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">load</span><span class="p">({</span> <span class="nx">params</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">post</span> <span class="o">=</span> <span class="kr">await</span> <span class="kr">import</span><span class="p">(</span><span class="sb">`../</span><span class="si">${</span><span class="nx">params</span><span class="p">.</span><span class="nx">slug</span><span class="si">}</span><span class="sb">.md`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="p">{</span> <span class="nx">title</span><span class="p">,</span> <span class="nx">date</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">post</span><span class="p">.</span><span class="nx">metadata</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="nx">post</span><span class="p">.</span><span class="k">default</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">date</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This will help us to -</p>
<ol>
<li>Get the parameter passed by the client (for e.g. when the user navigates to a particular blog post)</li>
<li>Get the markdown file in the provided path</li>
<li>Retrieve content, title and date, and return them</li>
</ol>
<p>The corresponding <code>routes/[blog]/[slug]/page.svelte]</code> will display content-</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">script</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm">	 * @type {{ title: any; date: any; content?: any; }}
</span></span></span><span class="line"><span class="cl"><span class="cm">	 */</span>
</span></span><span class="line"><span class="cl">	<span class="kr">export</span> <span class="kd">let</span> <span class="nx">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="p">{</span> <span class="nx">title</span><span class="p">,</span> <span class="nx">date</span><span class="p">,</span> <span class="nx">content</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">/script&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">article</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="o">&lt;</span><span class="nx">h1</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">data</span><span class="p">.</span><span class="nx">title</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/h1&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="o">&lt;</span><span class="nx">p</span> <span class="kr">class</span><span class="o">=</span><span class="s2">&#34;subdued&#34;</span><span class="o">&gt;</span><span class="nx">Published</span><span class="o">:</span> <span class="p">{</span><span class="nx">data</span><span class="p">.</span><span class="nx">date</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/p&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="o">&lt;</span><span class="nx">svelte</span><span class="o">:</span><span class="nx">component</span> <span class="k">this</span><span class="o">=</span><span class="p">{</span><span class="nx">data</span><span class="p">.</span><span class="nx">content</span><span class="p">}</span> <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">/article&gt;</span>
</span></span></code></pre></div><p>Create a few markdown files in <code>routes/[blog]/</code> - their names are used in the URL (for e.g. I created <code>latest.md</code> with sample content).</p>
<p>Navigate to <code>http://localhost:5173/blog/latest</code> to see the blog post.</p>
<p><img loading="lazy" src="/2022/sveltekit-blogpost.png" type="" alt="sveltekit-blogpost"  /></p>
<p>That is it - play around to see all the magic that sveltekit can do for you.
You will find the complete code on <a href="https://github.com/prashanth1k/avix-blog-sveltekit">Github</a>.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Sveltekit provides a structured way to develop a full stack application. Coding in svelte feels intuitive for me, but Sveltekit may take some getting used to.</p>
<ol>
<li>The hundred files that we have to deal with is a confusing start in Sveltekit. Is moving away from something like <code>getServerSideProps</code> method on the same page to distinct set of pages an advantage? Maybe, but it&rsquo;s sure weird</li>
<li>Navigation b/w methods in the same file is simpler than navigating files for simple use cases. We could always separate out code to different files if a specific file is turning out to be too complex</li>
<li>The naming conventions - <code>+page.svelte</code>, <code>+page.js</code>, <code>+page.server.js</code>, <code>+server.js</code>, <code>+layout.svelte</code> etc. may provide a structured approach to code while keeping us from making mistakes, but it sure is confusing. Decisions like &ldquo;do I code this logic in <code>page</code>, <code>page.server</code>, <code>server</code> or even <code>layout</code> (?)&rdquo; for a few use cases may be a turn off</li>
</ol>
<p>Probably all of this comes down to developing the muscle memory to do things in a different way. That and enough people talking about and agreeing to conventions and best practices will certainly help.</p>
<p>For now the go to choice for the simple applications I code will continue to be Vue/Nuxt.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>NextJS 13 is a good step forward</title>
      <link>https://techformist.com/nextjs-13-good-step-forward/</link>
      <pubDate>Wed, 02 Nov 2022 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/nextjs-13-good-step-forward/</guid>
      <description>&lt;p&gt;I am quite excited about the possibilities offered by NextJS 13. Announced in Oct &amp;lsquo;22, the most popular JavaScript framework has set fantastic standards for rest of the world.&lt;/p&gt;
&lt;p&gt;I particularly liked the below features -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;React Server Components that makes life simpler, but the coding process is much more efficient&lt;/li&gt;
&lt;li&gt;The new directory structure that simplifies routes. Layouts are intuitive and simple&lt;/li&gt;
&lt;li&gt;Love the new links (yes, I had to say this)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What lays hidden in the first statement is all the power hidden in React Server Component itself and that of streaming SSR. Combined with the new way of writing pages, I think this came closest for me to reconsider coding in React.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I am quite excited about the possibilities offered by NextJS 13. Announced in Oct &lsquo;22, the most popular JavaScript framework has set fantastic standards for rest of the world.</p>
<p>I particularly liked the below features -</p>
<ul>
<li>React Server Components that makes life simpler, but the coding process is much more efficient</li>
<li>The new directory structure that simplifies routes. Layouts are intuitive and simple</li>
<li>Love the new links (yes, I had to say this)</li>
</ul>
<p>What lays hidden in the first statement is all the power hidden in React Server Component itself and that of streaming SSR. Combined with the new way of writing pages, I think this came closest for me to reconsider coding in React.</p>
<ul>
<li>Write server and client code in context of a component</li>
<li>Do not worry about writing an entire backend infrastructure</li>
<li>Smaller JS download sizes</li>
<li>Execute faster with streaming SSR - UI that loads instantly and maintains performance for all the magical stuff in your app</li>
</ul>
<p>With easy deployment options and the ability to serve many things from edge, NextJS is compelling for any new apps in the React world.</p>
<h2 id="time-for-a-to-do-app">Time for a To-do app</h2>
<p>Let us try out the new features with a simple to-do app written with -</p>
<ol>
<li>NextJS</li>
<li>Pico CSS for styling</li>
<li>PocketBase for backend</li>
</ol>
<h3 id="setup">Setup</h3>
<p>Create the NextJS app.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"><span class="k">cd</span> c:\dev\myprojects
</span></span><span class="line"><span class="cl">pnpm create next-app todo-next13 --experimental-app
</span></span></code></pre></div><p>You may not want the experimental flag once the &ldquo;app&rdquo; directory and associated functions are main stream.</p>
<h5 id="install-pico-css">Install Pico CSS</h5>
<p>You can just CDN into Pico CSS, a lightweight, easy-to-use CSS library that is perfect for experimental projects.</p>
<p>I just installed it for later use..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">pnpm install pico-css
</span></span></code></pre></div><h5 id="setup-pocketbase">Setup PocketBase</h5>
<p>PocketBase is turning out to be a God send for me to quickly try out applications with a robust backend. PocketBase is written in Go, is extensible since it can also act as a framework, and has a good database (uses SQLite).</p>
<p>As the first step, <a href="https://pocketbase.io/docs/">download PocketBase executable</a>. Store the exe in <code>&lt;_root-folder_ &gt; db</code>.</p>
<p>You can serve PocketBase with -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">./pocketbase serve
</span></span></code></pre></div><p>You can access the database using automatic REST APIs, or use the <a href="https://github.com/pocketbase/js-sdk">JS SDK</a>. We will use the SDK since we never know when our To do app will blow up.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">pnpm install pocketbase
</span></span></code></pre></div><h3 id="define-data-model-in-pocketbase">Define data model in PocketBase</h3>
<p>Once installed, you should be able to access the admin UI to create tables and enter dummy records in the database before you take your next gulp of your favourite drink.</p>
<p>Point your browser to <code>http://127.0.0.1:8090/_/</code>.</p>
<p>Click on them shiny buttons to create a table and a few columns.</p>
<h3 id="code-the-todo-app">Code the Todo app</h3>
<p>It is time to write some magic.</p>
<h5 id="create-layout-and-home-page">Create layout and home page</h5>
<p>In the <code>_root-folder_ &gt; app</code> directory create a new file called &rsquo;layout.tsx&rsquo;.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Link</span> <span class="kr">from</span> <span class="s2">&#34;next/link&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;@picocss/pico/css/pico.min.css&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;../app/css/custom.css&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">RootLayout</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">children</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">children</span>: <span class="kt">React.ReactNode</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">main</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">Link</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/&#34;</span><span class="p">&gt;</span><span class="nx">Home</span><span class="p">&lt;/</span><span class="nt">Link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">Link</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/todos&#34;</span><span class="p">&gt;</span><span class="nx">Todo</span><span class="p">&lt;/</span><span class="nt">Link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span><span class="nx">children</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>layout.tsx</code> will serve as our home page container. You can code in-</p>
<ol>
<li>All the elements that are common across components - e.g. Nav, etc.</li>
<li>Include CSS - Pico CSS and any custom CSS that you fancy</li>
</ol>
<p>Don&rsquo;t forget to create <code>custom.css</code> in <code>css</code> directory if you have included a custom CSS statement.</p>
<p>Create another file called <code>page.tsx</code>, which will serve as the root page of your app.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Link</span> <span class="kr">from</span> <span class="s2">&#34;next/link&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">HomePage() {</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span><span class="nx">Home</span><span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span><span class="nx">Awesome</span> <span class="nx">Next</span> <span class="nx">Todo</span><span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;padding-top: 3em&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">Link</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/todos&#34;</span><span class="p">&gt;</span><span class="nx">View</span> <span class="nx">Todos</span><span class="p">&lt;/</span><span class="nt">Link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Execute your Next app if you are have not already done so and see your beautiful app..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">pnpm run dev
</span></span></code></pre></div><p><img loading="lazy" src="/2022/todo-app-nextjs13-pico-css-pocketbase.png" type="" alt="todo-app-nextjs13-pico-css-pocketbase"  /></p>
<p>You are now ready to add the core functionality.</p>
<h5></h5>
<p>Create a folder called <code>todos</code> in <code>_root-folder</code>.</p>
<p>Add a new files called <code>page.tsx</code>..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">fetchCache</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Link</span> <span class="kr">from</span> <span class="s2">&#34;next/link&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">PocketBase</span> <span class="kr">from</span> <span class="s2">&#34;pocketbase&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">CreateTodo</span> <span class="kr">from</span> <span class="s2">&#34;./CreateTodo&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PocketBase</span><span class="p">(</span><span class="s2">&#34;http://127.0.0.1:8090&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">getTodos</span><span class="p">(</span><span class="nx">fromRec</span>: <span class="kt">number</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">filter</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">client</span><span class="p">.</span><span class="nx">records</span><span class="p">.</span><span class="nx">getList</span><span class="p">(</span><span class="s2">&#34;todos&#34;</span><span class="p">,</span> <span class="nx">fromRec</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">filter</span>: <span class="kt">filter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">res</span><span class="o">?</span><span class="p">.</span><span class="nx">items</span> <span class="kr">as</span> <span class="kt">any</span><span class="p">[];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">TodosPage() {</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todos</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">getTodos</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span><span class="nx">Todos</span><span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="nx">todos</span><span class="o">?</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">todo</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">Todo</span> <span class="na">key</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span> <span class="na">todo</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">}&gt;&lt;/</span><span class="nt">Todo</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">))}</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;padding-top: 1em;padding-bottom: 1em;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">CreateTodo</span><span class="p">&gt;&lt;/</span><span class="nt">CreateTodo</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Todo</span><span class="p">({</span> <span class="nx">todo</span> <span class="p">}</span><span class="o">:</span> <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">Link</span> <span class="na">href</span><span class="o">=</span><span class="p">{</span><span class="sb">`/todos/</span><span class="si">${</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="si">}</span><span class="sb">`</span><span class="p">}&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;grid&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;todo-status&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">input</span>
</span></span><span class="line"><span class="cl">            <span class="na">type</span><span class="o">=</span><span class="s">&#34;checkbox&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">name</span><span class="o">=</span><span class="s">&#34;status&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">id</span><span class="o">=</span><span class="s">&#34;status&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">checked</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">status</span> <span class="o">==</span> <span class="s2">&#34;Complete&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="na">value</span><span class="o">=</span><span class="s">&#34;Complete&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;todo-desc&#34;</span><span class="p">&gt;{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">description</span><span class="p">}</span> <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;todo-date&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">input</span>
</span></span><span class="line"><span class="cl">            <span class="na">name</span><span class="o">=</span><span class="s">&#34;todo-date&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">id</span><span class="o">=</span><span class="s">&#34;todo-date&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">className</span><span class="o">=</span><span class="s">&#34;todo-date-input&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">value</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">planned_date</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="na">readOnly</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">status</span> <span class="o">==</span> <span class="s2">&#34;Complete&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">          <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">Link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>page.tsx</code> is the root page when you navigate to <code>localhost:3000/todos</code>. There is simple code here to -</p>
<ol>
<li>Query todos from database</li>
<li>Display the todos</li>
<li>Enable creation of new todo through the <code>CreateTodo</code> component (which we will create next)</li>
</ol>
<p>Create another file called <code>CreateTodo.tsx</code> in the same folder -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="s2">&#34;use client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Link</span> <span class="kr">from</span> <span class="s2">&#34;next/link&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useState</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;react&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">PocketBase</span> <span class="kr">from</span> <span class="s2">&#34;pocketbase&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useRouter</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;next/navigation&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PocketBase</span><span class="p">(</span><span class="s2">&#34;http://127.0.0.1:8090&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">CreateNote() {</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">desc</span><span class="p">,</span> <span class="nx">setDesc</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">status</span><span class="p">,</span> <span class="nx">setStatus</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">plannedDate</span><span class="p">,</span> <span class="nx">setPlannedDate</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">useRouter</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">createTodo</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">await</span> <span class="nx">client</span><span class="p">.</span><span class="nx">records</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="s2">&#34;todos&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">description</span>: <span class="kt">desc</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">status</span>: <span class="kt">status</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setStatus</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setDesc</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">router</span><span class="p">.</span><span class="nx">refresh</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">form</span> <span class="na">onSubmit</span><span class="o">=</span><span class="p">{</span><span class="nx">createTodo</span><span class="p">}&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">i</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;margin-bottom: 1em;&#34;</span><span class="p">&gt;</span><span class="nx">Create</span> <span class="nx">New</span> <span class="nx">Todo</span><span class="p">..&lt;/</span><span class="nt">i</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">label</span> <span class="na">htmlFor</span><span class="o">=</span><span class="s">&#34;desc&#34;</span><span class="p">&gt;</span><span class="nx">Description</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">input</span>
</span></span><span class="line"><span class="cl">            <span class="na">name</span><span class="o">=</span><span class="s">&#34;desc&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">value</span><span class="o">=</span><span class="p">{</span><span class="nx">desc</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="na">onChange</span><span class="o">=</span><span class="p">{(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">setDesc</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">)}&gt;&lt;/</span><span class="nt">input</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">label</span> <span class="na">htmlFor</span><span class="o">=</span><span class="s">&#34;status&#34;</span><span class="p">&gt;</span><span class="nx">Status</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">input</span>
</span></span><span class="line"><span class="cl">            <span class="na">name</span><span class="o">=</span><span class="s">&#34;status&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">value</span><span class="o">=</span><span class="p">{</span><span class="nx">status</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="na">onChange</span><span class="o">=</span><span class="p">{(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">setStatus</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">)}&gt;&lt;/</span><span class="nt">input</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span><span class="p">&gt;</span><span class="nx">Create</span> <span class="nx">Todo</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>use client</code> denotes that the <code>CreateTodo</code> component needs to be interactive on the client. All the earlier components can execute code on server and send the results to the client, while <code>CreateTodo</code> has to be pushed as Javascript to client and the form needs to accept user inputs.</p>
<p>Other than the client interaction, <code>CreateTodo</code> is &lsquo;more or less&rsquo; standard React.</p>
<p>The code described so far should be good enough to complete all the things that the app needs to do. However, let us add a dynamic route just because we can. (Also, this will eliminate the errors if you have copied the code as is).</p>
<p>Create a directory <code>[id]</code> under <code>todos</code> directory. Create a new file <code>page.tsx</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Link</span> <span class="kr">from</span> <span class="s2">&#34;next/link&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">PocketBase</span> <span class="kr">from</span> <span class="s2">&#34;pocketbase&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PocketBase</span><span class="p">(</span><span class="s2">&#34;http://127.0.0.1:8090&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">getTodo</span><span class="p">(</span><span class="nx">todoId</span>: <span class="kt">string</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="nx">todoId</span>
</span></span><span class="line"><span class="cl">    <span class="o">?</span> <span class="k">await</span> <span class="nx">client</span><span class="p">.</span><span class="nx">records</span><span class="p">.</span><span class="nx">getOne</span><span class="p">(</span><span class="s2">&#34;todos&#34;</span><span class="p">,</span> <span class="nx">todoId</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">:</span> <span class="p">{</span> <span class="nx">id</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;&#34;</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">res</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">TodoPage</span><span class="p">({</span> <span class="nx">params</span> <span class="p">}</span><span class="o">:</span> <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todo</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">getTodo</span><span class="p">(</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span><span class="nx">Todo</span><span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;padding-bottom: 1em;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">Link</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/todos&#34;</span><span class="p">&gt;</span><span class="nx">Back</span> <span class="nx">to</span> <span class="nx">todos</span><span class="p">&lt;/</span><span class="nt">Link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">label</span> <span class="na">htmlFor</span><span class="o">=</span><span class="s">&#34;id&#34;</span><span class="p">&gt;</span><span class="nx">Id</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">input</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;id&#34;</span> <span class="na">value</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="p">}&gt;&lt;/</span><span class="nt">input</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">label</span> <span class="na">htmlFor</span><span class="o">=</span><span class="s">&#34;desc&#34;</span><span class="p">&gt;</span><span class="nx">Description</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">input</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;desc&#34;</span> <span class="na">value</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">description</span><span class="p">}&gt;&lt;/</span><span class="nt">input</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">label</span> <span class="na">htmlFor</span><span class="o">=</span><span class="s">&#34;status&#34;</span><span class="p">&gt;</span><span class="nx">Status</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">input</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;status&#34;</span> <span class="na">value</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">status</span><span class="p">}&gt;&lt;/</span><span class="nt">input</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You would have probably logged out by now, or know the drill..</p>
<ol>
<li><code>page.tsx</code> is the root page</li>
<li>The component accepts a parameter from the caller to query for a particular todo record</li>
<li>Display the todo</li>
</ol>
<p>What is different is the <code>[id]</code> tag that indicates that the component is dynamic (spare me the suprise look).</p>
<p>Lo &amp; behold, you now have a to do app that can make the next million dollar SaaS app.</p>
<p>See complete code for this incomplete app on <a href="https://github.com/prashanth1k/todo-next13">GitHub</a>.</p>
<h2 id="why-i-will-not-switch-to-nextjs">Why I will not switch to NextJS</h2>
<p>I really like where NextJS is going. I see compelling reasons for using Next - the tooling, ease of deployment, and the massive community that tells me how my code is completely wrong and how I should be thinking about solving world hunger.</p>
<p>But again, ReactJS is not exactly my favourite way to write apps (yes, that&rsquo;s me being stupid). Also -</p>
<ul>
<li>I still think ReactJS is a lot of boilerplate</li>
<li>I don&rsquo;t quite enjoy writing a lot of code to maintain state, render a list or do the thousand things that every web app has to do</li>
<li>I don&rsquo;t have to answer to anyone or collaborate with 100 people for my side projects</li>
<li>I don&rsquo;t have a massive library of UI components built out in React that can help me speed up the development process</li>
</ul>
<p>Till I can check at least three of the above boxes, I will continue to code in either Vue or Svelte.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Reactivity for Arrays &amp; Objects in Vue vs. Svelte</title>
      <link>https://techformist.com/reactivity-svelte-vue-arrays-objects/</link>
      <pubDate>Mon, 02 May 2022 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/reactivity-svelte-vue-arrays-objects/</guid>
      <description>&lt;p&gt;Coming from the Vue world, Reactivity in Svelte for anything more than simple strings feels.. a bit different.&lt;/p&gt;
&lt;p&gt;Vue has made me lazy when handling &lt;a href=&#34;https://techformist.com/break-reactivity-vue-array-object/&#34;&gt;reactive arrays or objects&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All I have to do with the older Object API is -&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// nums: [1, 2]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;addToNum&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;nums&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;push&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;nums&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Directly modifying an element (e.g. &lt;code&gt;this.nums[1] = &#39;a&#39;&lt;/code&gt;) would not work though, and that was perfectly fine.&lt;/p&gt;
&lt;p&gt;It is more tricky for objects - &lt;code&gt;this.planets[&amp;quot;jupiter&amp;quot;] = 5&lt;/code&gt; will not trigger reactivity. We could work around this by &lt;code&gt;this.planets = { ...this.planets, jupiter: 5 }&lt;/code&gt;. (Or, use &lt;code&gt;$add&lt;/code&gt; if you are weird).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Coming from the Vue world, Reactivity in Svelte for anything more than simple strings feels.. a bit different.</p>
<p>Vue has made me lazy when handling <a href="/break-reactivity-vue-array-object/">reactive arrays or objects</a>.</p>
<p>All I have to do with the older Object API is -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="c1">// nums: [1, 2]
</span></span></span><span class="line"><span class="cl"><span class="nx">addToNum</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">this</span><span class="p">.</span><span class="nx">nums</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">nums</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Directly modifying an element (e.g. <code>this.nums[1] = 'a'</code>) would not work though, and that was perfectly fine.</p>
<p>It is more tricky for objects - <code>this.planets[&quot;jupiter&quot;] = 5</code> will not trigger reactivity. We could work around this by <code>this.planets = { ...this.planets, jupiter: 5 }</code>. (Or, use <code>$add</code> if you are weird).</p>
<p>In Composition API, this seemingly became simpler and, verbose?..</p>
<p>From the example in Vue docs ..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">v-for</span><span class="o">=</span><span class="s">&#34;(item, i) in list&#34;</span> <span class="na">:ref</span><span class="o">=</span><span class="s">&#34;el =&gt; { if (el) divs[i] = el }&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{ item }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="p">{</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">reactive</span><span class="p">,</span> <span class="nx">onBeforeUpdate</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;vue&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setup</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">list</span> <span class="o">=</span> <span class="nx">reactive</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">divs</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">([])</span>
</span></span><span class="line"><span class="cl">      <span class="nx">onBeforeUpdate</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">divs</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">      <span class="p">})</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">list</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">divs</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Jumping back to Svelte, simple variables work as easily.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  let clicks = 0;
</span></span><span class="line"><span class="cl">  function addNumber() { 
</span></span><span class="line"><span class="cl">    clicks += 1;
</span></span><span class="line"><span class="cl">  }
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">button</span> <span class="na">on:click</span><span class="o">=</span><span class="s">{addNumber}</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	Add a number
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span> {clicks}
</span></span></code></pre></div><p>But we cannot simply drop-in anything more complicated.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  let clicks = 0;
</span></span><span class="line"><span class="cl">  let numbers = [1, 2, 3, 4];
</span></span><span class="line"><span class="cl">  function addNumber() { 
</span></span><span class="line"><span class="cl">    clicks += 1;
</span></span><span class="line"><span class="cl">    numbers.push(numbers.length + 1); 
</span></span><span class="line"><span class="cl">    // will change array, but not trigger reactivity
</span></span><span class="line"><span class="cl">  }
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>{numbers.join(&#39; + &#39;)} = {sum}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">button</span> <span class="na">on:click</span><span class="o">=</span><span class="s">{addNumber}</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	Add a number
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">{count}
</span></span></code></pre></div><p>An additional statement will fix the problem -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">addNumber</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">numbers</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">numbers</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="nx">numbers</span> <span class="o">=</span> <span class="nx">numbers</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Or, do this -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl">	<span class="nx">numbers</span> <span class="o">=</span> <span class="p">[...</span><span class="nx">numbers</span><span class="p">,</span> <span class="nx">numbers</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">];</span>
</span></span></code></pre></div><p>The below code also works, but I feel somewhat bad using it -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">numbers</span> <span class="p">[</span><span class="nx">numbers</span><span class="p">.</span><span class="nx">length</span><span class="p">]</span> <span class="o">=</span> <span class="nx">numbers</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
</span></span></code></pre></div><p>Variables dependent on other variables need special treatment -</p>
<p>From the example in Svelte docs -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="kd">let</span> <span class="nx">numbers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="kd">function</span> <span class="nx">addNumber</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">numbers</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">numbers</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">$</span><span class="o">:</span> <span class="nx">sum</span> <span class="o">=</span> <span class="nx">numbers</span><span class="p">.</span><span class="nx">reduce</span><span class="p">((</span><span class="nx">t</span><span class="p">,</span> <span class="nx">n</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">t</span> <span class="o">+</span> <span class="nx">n</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>{numbers.join(&#39; + &#39;)} = {sum}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">button</span> <span class="na">on:click</span><span class="o">=</span><span class="s">{addNumber}</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	Add a number
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Objects work in a similar way as arrays. Assignment to a variable on the left hand side will trigger reactivity for that variable -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">numObj</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="o">:</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="o">:</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="o">:</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="o">:</span><span class="mi">4</span><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">clicks</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">addNumber</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kd">let</span> <span class="nx">nxtNum</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">values</span><span class="p">(</span><span class="nx">numObj</span><span class="p">)[</span><span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">numObj</span><span class="p">).</span><span class="nx">length</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">numObj</span> <span class="p">[</span><span class="nx">nxtNum</span><span class="p">]</span><span class="o">=</span> <span class="nx">nxtNum</span><span class="p">;</span> <span class="c1">//this!
</span></span></span><span class="line"><span class="cl">	<span class="nx">clicks</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	{Object.entries(numObj)}
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">button</span> <span class="na">on:click</span><span class="o">=</span><span class="s">{addNumber}</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	Add a number
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>However, the below will not work as-is -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">planet</span> <span class="o">=</span> <span class="p">{</span><span class="nx">earth</span><span class="o">:</span> <span class="p">{</span><span class="nx">postn</span><span class="o">:</span><span class="mi">3</span><span class="p">}};</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">earth</span> <span class="o">=</span> <span class="nx">planet</span><span class="p">.</span><span class="nx">earth</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">addColor</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">earth</span><span class="p">.</span><span class="nx">color</span><span class="o">=</span><span class="s2">&#34;blue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">{JSON.stringify(planet)}	
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">button</span> <span class="na">on:click</span><span class="o">=</span><span class="s">{addColor}</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	Add Color
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Add a line to trigger reactivity -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">addColor</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">earth</span><span class="p">.</span><span class="nx">color</span><span class="o">=</span><span class="s2">&#34;blue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">planet</span> <span class="o">=</span> <span class="nx">planet</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Object API was intuitive. But, I think I prefer the Svelte solution in comparison with the Composition API in Vue.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Dotnet 6 is Refreshingly Simple</title>
      <link>https://techformist.com/dotnet6-refreshingly-simple/</link>
      <pubDate>Mon, 07 Feb 2022 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/dotnet6-refreshingly-simple/</guid>
      <description>&lt;p&gt;There are numerous things to love about the new .NET 6, but for me one key thing stands out - .NET now seems more approachable than ever!&lt;/p&gt;
&lt;p&gt;Take a straight-forward example. A new .NET Web API project would look like this -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;startup.cs&lt;/code&gt; file with generated code&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Program.cs&lt;/code&gt; file with more lines of code&lt;/li&gt;
&lt;li&gt;A lot of other files&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The two file dependencies induced that warm fuzzy feeling in ASP.NET developers for sometime now.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>There are numerous things to love about the new .NET 6, but for me one key thing stands out - .NET now seems more approachable than ever!</p>
<p>Take a straight-forward example. A new .NET Web API project would look like this -</p>
<ol>
<li>A <code>startup.cs</code> file with generated code</li>
<li>A <code>Program.cs</code> file with more lines of code</li>
<li>A lot of other files</li>
</ol>
<p>The two file dependencies induced that warm fuzzy feeling in ASP.NET developers for sometime now.</p>
<p>In addition, you have code that uses a wierd <code>using</code> syntax everywhere with brackets. Sure, it creates better compartmentalized &amp; namespaced code, but did not help calm my nerves when I was evaluating ten different back end technologies to make a quick start (a while ago).</p>
<p>C# 10 and the new ASP.NET 6 will do wonders in the &ldquo;make code look deceptively simple&rdquo; area.</p>
<p>There is no <code>startup.cs</code>. The <code>Program.cs</code> file now looks cool with the new features -</p>
<ul>
<li>top-level statements</li>
<li>global <code>using</code> directives</li>
<li>file scope namespace declarations (bear with me here)</li>
</ul>
<p>A minimal API structure now looks like this (<code>Program.cs</code> file) -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cs" data-lang="cs"><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">WebApplication</span><span class="p">.</span><span class="n">CreateBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="n">Build</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">app</span><span class="p">.</span><span class="n">MapGet</span><span class="p">(</span><span class="s">&#34;/&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="s">&#34;Hello World!&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">app</span><span class="p">.</span><span class="n">Run</span><span class="p">();</span>
</span></span></code></pre></div><p>A full-blown MVC web API application from the new template in .NET 6 looks like this..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cs" data-lang="cs"><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">WebApplication</span><span class="p">.</span><span class="n">CreateBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Add services to the container.</span>
</span></span><span class="line"><span class="cl"><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddControllers</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddEndpointsApiExplorer</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="n">Build</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">app</span><span class="p">.</span><span class="n">UseHttpsRedirection</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="n">app</span><span class="p">.</span><span class="n">UseAuthorization</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="n">app</span><span class="p">.</span><span class="n">MapControllers</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">app</span><span class="p">.</span><span class="n">Run</span><span class="p">();</span>
</span></span></code></pre></div><p>&ldquo;Whoa..!&rdquo; is right.</p>
<p>I am not proud of the fact that the additional statements &amp; brackets were putting me off a long time. While I love C# for what it can do, I seldom choose C# for personal projects for all the silly reasons - I did not need the complexity, did not like to do lot of typing or &ldquo;auto filling&rdquo;, and did not have a lot of patience for code scrolling tens of pages.</p>
<p>NodeJS simply offered a better alternative, was way simpler to start (especially in Fastify or Express), and came at a cost that did not quite matter to me. And, I am a happy Javascript user - no one will take that away from me.</p>
<p>I am a fan of the new ASP.NET structure - for probably all the wrong reasons for a &ldquo;real&rdquo; developer. I will probably delve more into how a further &ldquo;simplified&rdquo; folder structure can make the ASP.NET world more exciting to work on. The &ldquo;traditional&rdquo; structure has been full of folders and a lot of files. See the <a href="https://github.com/dotnet-architecture/eShopOnWeb/tree/main/src/Web">eShopOnWeb example on Github</a>. The <a href="https://gist.github.com/davidfowl/ff1addd02d239d2d26f4648a06158727">minimal API structure at a glance by Martin Fowler</a> is a good start for a new approach to build Web APIs on .NET 6, but what is even more interesting to me is the <a href="https://timdeschryver.dev/blog/maybe-its-time-to-rethink-our-project-structure-with-dot-net-6">module-based architecture</a> outlined in this post by Tim Deschryver.</p>
<pre tabindex="0"><code>WebApplication
│   appsettings.json
│   Program.cs
│   GlobalImports.cs
│   WebApplication.csproj
│
├───Modules
│   ├───Cart
│   │      CartModule.cs
│   └───Orders
│       │   OrdersModule.cs
│       ├───Endpoints
│       │       GetOrders.cs
│       │       PostOrder.cs
│       ├───Core
│       │       Order.cs
│       │───Ports
│       │       IOrdersRepository.cs
│       │       IPaymentService.cs
│       └───Adapters
│               OrdersRepository.cs
│               PaymentService.cs
</code></pre><p>Awesome time this.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Teleport in VueJS</title>
      <link>https://techformist.com/teleport-vuejs/</link>
      <pubDate>Wed, 20 Jan 2021 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/teleport-vuejs/</guid>
      <description>&lt;p&gt;Teleport is a new feature introduced in Vue 3. Teleport provides better control to developers on where exactly an element is rendered.&lt;/p&gt;
&lt;h2 id=&#34;get-teleporting&#34;&gt;Get Teleporting&lt;/h2&gt;
&lt;p&gt;Let us create a new Vue 3 app to start playing around with teleport. We will use Vite, because it is 2021.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmd&#34; data-lang=&#34;cmd&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;npm init @vitejs/app
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Provide a project name (&lt;code&gt;teleport&lt;/code&gt;) and select &lt;code&gt;vue&lt;/code&gt; as the template.&lt;/p&gt;
&lt;p&gt;Install dependencies and start the app.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmd&#34; data-lang=&#34;cmd&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;cd&lt;/span&gt; teleport
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;npm i
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;npm run dev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Navigate to &lt;code&gt;http://localhost:3000&lt;/code&gt; to see your new app.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Teleport is a new feature introduced in Vue 3. Teleport provides better control to developers on where exactly an element is rendered.</p>
<h2 id="get-teleporting">Get Teleporting</h2>
<p>Let us create a new Vue 3 app to start playing around with teleport. We will use Vite, because it is 2021.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm init @vitejs/app
</span></span></code></pre></div><p>Provide a project name (<code>teleport</code>) and select <code>vue</code> as the template.</p>
<p>Install dependencies and start the app.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"><span class="k">cd</span> teleport
</span></span><span class="line"><span class="cl">npm i
</span></span><span class="line"><span class="cl">npm run dev
</span></span></code></pre></div><p>Navigate to <code>http://localhost:3000</code> to see your new app.</p>
<p>Replace the <code>&lt;template&gt;</code> section in <code>src/components/HelloWorld.vue</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>{{ msg }}<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create a new component <code>src/components/Messages.vue</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">HelloWorld</span> <span class="na">msg</span><span class="o">=</span><span class="s">&#34;Hello&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">HelloWorld</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">HelloWorld</span> <span class="na">msg</span><span class="o">=</span><span class="s">&#34;Hi&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">HelloWorld</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">HelloWorld</span> <span class="na">msg</span><span class="o">=</span><span class="s">&#34;Goodbye&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">HelloWorld</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="nx">HelloWorld</span> <span class="nx">from</span> <span class="s2">&#34;./HelloWorld.vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Replace <code>&lt;template&gt;</code> section in <code>src/App.vue</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">Messages</span><span class="p">&gt;&lt;/</span><span class="nt">Messages</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">img</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;Vue logo&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;./assets/logo.png&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;height: 100px&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>We are just rearranging a couple of things and setting the stage for demonstrating teleport.</p>
<p>You will see output as expected -</p>
<p><img loading="lazy" src="/2021/vue-simple-app-no-teleport.jpg" type="" alt="vue-simple-app-no-teleport"  /></p>
<p>This makes absolute sense -</p>
<ol>
<li>You create a component and build up UI with components</li>
<li>You use the components in the parent component/view exactly in the place you need it</li>
</ol>
<p>Teleport helps us to write code in a logical fashion but have more control over where the component is rendered.</p>
<p>For e.g., we can change the code in <code>Messages.vue</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">HelloWorld</span> <span class="na">msg</span><span class="o">=</span><span class="s">&#34;Hello&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">HelloWorld</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">HelloWorld</span> <span class="na">msg</span><span class="o">=</span><span class="s">&#34;Hi&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">HelloWorld</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">teleport</span> <span class="na">to</span><span class="o">=</span><span class="s">&#34;#startapp&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">HelloWorld</span> <span class="na">msg</span><span class="o">=</span><span class="s">&#34;Goodbye&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">HelloWorld</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">teleport</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Now, change <code>App.vue</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;startapp&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">Messages</span><span class="p">&gt;&lt;/</span><span class="nt">Messages</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">img</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;Vue logo&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;./assets/logo.png&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;height: 100px&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The third message is moved to the first position, i.e, the rendering of the component will be teleported to the tag with id <code>startapp</code>.</p>
<p>You may in fact transport anything outside of the entire Vue render tree. For e.g., change <code>index.html</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="cp">&lt;!DOCTYPE html&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;UTF-8&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;icon&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/favicon.ico&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;viewport&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;width=device-width, initial-scale=1.0&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>Vite App<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;startapp&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;app&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;module&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;/src/main.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p><img loading="lazy" src="/2021/vue-simple-app-teleport.jpg" type="" alt="vue-simple-app-teleport"  /></p>
<h2 id="where-to-use-teleport">Where to use teleport?</h2>
<p>Teleport offers a cleaner segregation from the &ldquo;coding&rdquo; side of things as compared to where a component/element is rendered.</p>
<p>Here are a couple of use cases where teleport can help-</p>
<ul>
<li>High degree of control over positioning of elements: Display elements like status bar always at the bottom of page - no matter where they are used. You are not constrained to code in those components at the very end</li>
<li>Modals: You can have a conditional display of modal dialog anywhere in the app, but you may want to move it to end. Or, you may move a full-screen modal to the <code>body</code> tag and have a cleaner UI</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Create a Task Management App with ReactJS in 2021</title>
      <link>https://techformist.com/task-management-app-reactjs-2021/</link>
      <pubDate>Wed, 13 Jan 2021 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/task-management-app-reactjs-2021/</guid>
      <description>&lt;p&gt;In this post let us see how we can easily build a task management app (which is totally &amp;amp; completely different from a todo app) using ReactJS. We will be using React Hooks, Chota CSS for styling and a lot of ES6+. We will not look at any centralised state management, or deal with a backend to store the tasks in this post.&lt;/p&gt;
&lt;h2 id=&#34;get-started&#34;&gt;Get Started&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;create-react-app&lt;/code&gt; to structure your project like any sane person would do -&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In this post let us see how we can easily build a task management app (which is totally &amp; completely different from a todo app) using ReactJS. We will be using React Hooks, Chota CSS for styling and a lot of ES6+. We will not look at any centralised state management, or deal with a backend to store the tasks in this post.</p>
<h2 id="get-started">Get Started</h2>
<p>Use <code>create-react-app</code> to structure your project like any sane person would do -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npx create-react-app tasker-react-sample-app
</span></span></code></pre></div><p>Proceed to have a dozen cups of coffee while your app gets initialised. Open the project root folder in VSCode to see this beautiful structure.</p>
<p><img loading="lazy" src="/2021/create-react-app-structure.jpg" type="" alt="create-react-app-structure"  /></p>
<p>Start your app..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm run start
</span></span></code></pre></div><p>Navigate to <code>http://localhost:3000</code> in your browser to see the app.</p>
<p>While the create-react-app seems to do a lot of things (it does), you only need to care about a few things at this time -</p>
<ul>
<li>The app gets anchored with one HTML file <code>public/index.html</code> and in a single node <code>&lt;div id=&quot;root&quot;&gt;&lt;/div&gt;</code> (for the most part, bear with me). The file itself will not have direct reference to the javascript - that will be done through a build step</li>
<li><code>src/index.js</code> refers to the <code>root</code> element
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">ReactDOM</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="o">&lt;</span><span class="nx">React</span><span class="p">.</span><span class="nx">StrictMode</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">App</span> <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="o">&lt;</span><span class="err">/React.StrictMode&gt;,</span>
</span></span><span class="line"><span class="cl">  <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;root&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span></code></pre></div></li>
<li><code>App</code> in <code>index.js</code> is where you will start coding React magic. You shall use JSX in the React components to do all that magic, or you shall perish -
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">App</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;App&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">header</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;App-header&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
<p>Read more about JSX <a href="https://reactjs.org/docs/introducing-jsx.html">here</a>, or just follow along by keeping mind two things -</p>
<ul>
<li>You can code all the HTML you want within JSX</li>
<li>Use <code>className</code> instead of <code>class</code> to reference css classes</li>
<li>Use <code>{ }</code> notation within JSX for expressions, variables etc.</li>
</ul>
<p>Let&rsquo;s do a quick take on how the components work. Create a new file <code>src/components/HelloWorld.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h3</span><span class="p">&gt;</span><span class="nx">Hello</span> <span class="nx">World</span><span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>JSX can have only one root - <code>&lt;&gt;&lt;/&gt;</code> tags take care of that. Rest is just plain HTML.</p>
<p>Include <code>HelloWorld</code> in <code>App.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">logo</span> <span class="nx">from</span> <span class="s2">&#34;./logo.svg&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;./App.css&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">HelloWorld</span> <span class="nx">from</span> <span class="s2">&#34;./components/HelloWorld&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">App</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;App&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">header</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;App-header&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span><span class="cm">/* - existing code goes here - */</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">HelloWorld</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">App</span><span class="p">;</span>
</span></span></code></pre></div><p>You can see the bold words in your app almost immediately.</p>
<p>Before we proceed, install a few things to make your React development easier -</p>
<ol>
<li>Install <a href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en">React Developer Tools</a>. This will add a couple of tabs in your Chrome Developer Tools to view components. By default you should see <code>Components</code> and <code>Profiler</code></li>
<li>Install VSCode extension <a href="https://marketplace.visualstudio.com/itemdetails?itemName=dsznajder.es7-react-js-snippets">ES7 React/Redux/GraphQL/React-Native snippets</a> that will give you a bunch of useful snippets</li>
</ol>
<p>You can use Emmet scripts to quickly create boilerplate and scripts - for e.g. create a new file and type in <code>rfce</code> and tab to see it in action.</p>
<p>Let us also include some styles, because well, we&rsquo;re not cave-men.</p>
<p>Include the below line in your <code>index.html</code> to include a small, class-light library called <code>chota.css</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/chota@latest&#34;</span> <span class="p">/&gt;</span>
</span></span></code></pre></div><p>Create a new file <code>src/assets/styles.css</code> and leave it blank for now. We will use it for custom styling. Include the file in <code>App.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;./assets/styles.css&#34;</span><span class="p">;</span>
</span></span></code></pre></div><p>I will not really touch upon this topic again - but you can see the CSS code in the Github repo.</p>
<h2 id="creating-structure-for-your-app">Creating Structure for your App</h2>
<p>Let us create the basic elements for our app. First, the header - create a new file called <code>src/components/Header.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Header</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">nav</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;nav&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;nav-left&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">a</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;brand&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;#&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Tasker</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;nav-right&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;tabs&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://techformist.com&#34;</span><span class="p">&gt;</span><span class="nx">Techformist</span><span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Header</span><span class="p">;</span>
</span></span></code></pre></div><p>We have seen this earlier - JSX and stuff. The only difference is the CSS classes. Let&rsquo;s include this <code>Header</code> in <code>App.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Header</span> <span class="nx">from</span> <span class="s2">&#34;./components/Header&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// ... other code
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">App</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;App&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="cm">/* .. */</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">Header</span><span class="p">&gt;&lt;/</span><span class="nt">Header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="cm">/* .. */</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The above changes should give you a good idea about where we are going. We create a <code>Header</code> component, and include it in the main <code>App</code> so that it&rsquo;s available everywhere in the app.</p>
<p>We can now include the main content just below <code>Header</code>.</p>
<h2 id="create-tasks-component">Create Tasks Component</h2>
<p>The simplest way to create a task component is familiar to us by now. Create a new file <code>src/components/Tasks.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Tasks</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span><span class="nx">Learn</span> <span class="nx">React</span><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span><span class="nx">Profit</span><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Tasks</span><span class="p">;</span>
</span></span></code></pre></div><p>Include <code>Tasks</code> in <code>App</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Tasks</span> <span class="nx">from</span> <span class="s2">&#34;./components/Tasks&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// ... other code
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">App</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;App&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="cm">/* .. */</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">Header</span><span class="p">&gt;&lt;/</span><span class="nt">Header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">button</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;button&#34;</span><span class="p">&gt;</span><span class="nx">New</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">Tasks</span><span class="p">&gt;&lt;/</span><span class="nt">Tasks</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="cm">/* .. */</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You should now be able to see the tasks and a button &ldquo;New&rdquo; that doesn&rsquo;t do anything.</p>
<p>Let&rsquo;s level up. We will create a state variable <code>tasks</code> that will store tasks and can be accessible from different components. We could eventually use this variable to store tasks retrieved from a database or a file.</p>
<p>In the simplest design we could create <code>tasks</code> in <code>Tasks</code> component, but that would make it difficult to access in a different component. For example, we need <code>tasks</code> in both <code>Tasks</code>, which is a list of tasks, and <code>TaskDetail</code>, which shows the detail task and allows user to edit tasks. So, let&rsquo;s create <code>tasks</code> in <code>App.js</code> for now.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;./App.css&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;./assets/styles.css&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Header</span> <span class="nx">from</span> <span class="s2">&#34;./components/Header&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Tasks</span> <span class="nx">from</span> <span class="s2">&#34;./components/Tasks&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useState</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;react&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">App</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">tasks</span><span class="p">,</span> <span class="nx">setTasks</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span> <span class="nx">desc</span><span class="o">:</span> <span class="s2">&#34;Learn React&#34;</span><span class="p">,</span> <span class="nx">id</span><span class="o">:</span> <span class="mi">1</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span> <span class="nx">desc</span><span class="o">:</span> <span class="s2">&#34;Profit&#34;</span><span class="p">,</span> <span class="nx">id</span><span class="o">:</span> <span class="mi">2</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;App&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">Header</span><span class="p">&gt;&lt;/</span><span class="nt">Header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">Tasks</span> <span class="na">tasks</span><span class="o">=</span><span class="p">{</span><span class="nx">tasks</span><span class="p">}&gt;&lt;/</span><span class="nt">Tasks</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">App</span><span class="p">;</span>
</span></span></code></pre></div><p>We have done a couple of cool things here -</p>
<ol>
<li>Import <code>useState</code> from React</li>
<li>Create <code>tasks</code> and initialize it. <code>tasks</code> is the variable name and <code>setTasks</code> is used to set this variable with a value. We will not be using <code>setTasks</code> right now, but directly provide the initial value as a param to <code>useState</code>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">[</span><span class="nx">tasks</span><span class="p">,</span> <span class="nx">setTasks</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">desc</span><span class="o">:</span> <span class="s2">&#34;Learn React&#34;</span><span class="p">,</span> <span class="nx">id</span><span class="o">:</span> <span class="mi">1</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">desc</span><span class="o">:</span> <span class="s2">&#34;Profit&#34;</span><span class="p">,</span> <span class="nx">id</span><span class="o">:</span> <span class="mi">2</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">]);</span>
</span></span></code></pre></div></li>
<li>Pass <code>tasks</code> as props to the <code>Tasks</code> component</li>
</ol>
<p>Let us receive <code>tasks</code> prop in our <code>Tasks</code> component.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Tasks</span><span class="p">({</span> <span class="nx">tasks</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;col-12 text-right&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">button</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;button primary&#34;</span><span class="p">&gt;</span><span class="nx">New</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="nx">tasks</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">task</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;col-12 text-left&#34;</span> <span class="na">key</span><span class="o">=</span><span class="p">{</span><span class="nx">task</span><span class="p">.</span><span class="nx">id</span><span class="p">}&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;{</span><span class="nx">task</span><span class="p">.</span><span class="nx">desc</span><span class="p">}&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">})}</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Tasks</span><span class="p">;</span>
</span></span></code></pre></div><p>As you can see -</p>
<ol>
<li>We receive a destructured <code>tasks</code> prop in the function. You could also define param as simply <code>props</code> (no brackets, no destructuring), and refer to tasks as <code>props.tasks</code></li>
<li>We cycle through <code>tasks</code> and display individual task using <code>h3</code> element. The brackets contain the overall expression in JSX
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">tasks</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">task</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;col-12 text-left&#34;</span> <span class="na">key</span><span class="o">=</span><span class="p">{</span><span class="nx">task</span><span class="p">.</span><span class="nx">id</span><span class="p">}&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;{</span><span class="nx">task</span><span class="p">.</span><span class="nx">desc</span><span class="p">}&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ol>
<p>You should now see..</p>
<h2 id="create-task-component">Create Task Component</h2>
<p><code>Tasks</code> component is doing too many things -</p>
<ol>
<li>List tasks</li>
<li>Show task</li>
<li>er.. that&rsquo;s about it, but it has the potential to much more</li>
</ol>
<p>Let&rsquo;s break the component so that display of a task becomes concern of a different component.</p>
<p>Create a new file <code>src/components/Task.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Task</span><span class="p">({</span> <span class="nx">task</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;col-12 text-left&#34;</span> <span class="na">key</span><span class="o">=</span><span class="p">{</span><span class="nx">task</span><span class="p">.</span><span class="nx">id</span><span class="p">}&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;{</span><span class="nx">task</span><span class="p">.</span><span class="nx">desc</span><span class="p">}&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Task</span><span class="p">;</span>
</span></span></code></pre></div><p>The code is a direct copy of the fragment responsible to display a specific task in <code>Tasks</code> component.</p>
<p>Include <code>Task</code> in <code>Tasks</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Task</span> <span class="nx">from</span> <span class="s2">&#34;./Task&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Tasks</span><span class="p">({</span> <span class="nx">tasks</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;col-12 text-right&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">button</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;button primary&#34;</span><span class="p">&gt;</span><span class="nx">New</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="nx">tasks</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">task</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">Task</span> <span class="na">task</span><span class="o">=</span><span class="p">{</span><span class="nx">task</span><span class="p">}</span> <span class="na">key</span><span class="o">=</span><span class="p">{</span><span class="nx">task</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">))}</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Tasks</span><span class="p">;</span>
</span></span></code></pre></div><p>This is very similar to last time when we included one component in another. We are just using an additional attribute called <code>key</code>, which denotes the unique identifier of each element in the array (and that will be <code>task.id</code> in our case).</p>
<p>The added advantage of segregating task display is that we can use this <code>Task</code> component to display individual task anywhere in the application.</p>
<p>Fantastic.</p>
<p>Let us add more attributes to the task and beautify this a bit. Afterall, a task is not simply about the description.</p>
<p>Add more attributes to the task in <code>App</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">[</span><span class="nx">tasks</span><span class="p">,</span> <span class="nx">setTasks</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">desc</span><span class="o">:</span> <span class="s2">&#34;Learn React&#34;</span><span class="p">,</span> <span class="nx">id</span><span class="o">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">date</span><span class="o">:</span> <span class="s2">&#34;2021-01-03 10:00&#34;</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;Complete&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">desc</span><span class="o">:</span> <span class="s2">&#34;Profit&#34;</span><span class="p">,</span> <span class="nx">id</span><span class="o">:</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">date</span><span class="o">:</span> <span class="s2">&#34;2021-01-05 15:00&#34;</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;Open&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">]);</span>
</span></span></code></pre></div><p>Change <code>Task.js</code> to make tasks come alive -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Task</span><span class="p">({</span> <span class="nx">task</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;card text-left&#34;</span> <span class="na">key</span><span class="o">=</span><span class="p">{</span><span class="nx">task</span><span class="p">.</span><span class="nx">id</span><span class="p">}&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;col-10&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;{</span><span class="nx">task</span><span class="p">.</span><span class="nx">desc</span><span class="p">}&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;task-meta&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">img</span>
</span></span><span class="line"><span class="cl">              <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://icongr.am/feather/calendar.svg?size=12&amp;color=b5b5b5&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">alt</span><span class="o">=</span><span class="s">&#34;calendar&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span><span class="nx">task</span><span class="p">.</span><span class="nx">date</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;col-2 is-center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">button</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;button icon-only clear&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">img</span>
</span></span><span class="line"><span class="cl">              <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://icongr.am/feather/check-circle.svg?size=24&amp;color=11d054&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">alt</span><span class="o">=</span><span class="s">&#34;Open&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;{</span><span class="nx">task</span><span class="p">.</span><span class="nx">remarks</span><span class="p">}&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Task</span><span class="p">;</span>
</span></span></code></pre></div><p>And, voila..</p>
<p><img loading="lazy" src="/2021/tasker-task-lists-simple.jpg" type="" alt="tasker-task-lists-simple"  /></p>
<h2 id="add-functionality-complete-task">Add Functionality: Complete Task</h2>
<p>We have successfully displayed a task so far, but we don&rsquo;t have any functionality enabled on the task. We will change that by inserting a button to toggle the task status.</p>
<p>Add a function that can get called to change status. If we had a global state (e.g. Redux), we would have more independence to decide where this function has to reside. Since we are using a simple state at <code>App</code> level, we will introduce the function to change that state also within <code>App</code>. Create a new function -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">onTglStatus</span> <span class="o">=</span> <span class="p">(</span><span class="nx">task</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;completing task&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>The child component (<code>Tasks</code> in our case) does not know about this method. We have to pass the function to the inner-most component that will call it for some greater good.</p>
<p>Change <code>App.js</code> to pass <code>onTglStatus</code> as a prop -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">Tasks</span> <span class="na">tasks</span><span class="o">=</span><span class="p">{</span><span class="nx">tasks</span><span class="p">}</span> <span class="na">onTglStatus</span><span class="o">=</span><span class="p">{</span><span class="nx">onTglStatus</span><span class="p">}&gt;&lt;/</span><span class="nt">Tasks</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">//  ...
</span></span></span></code></pre></div><p>Repeat the above code in <code>Tasks.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Tasks</span><span class="p">({</span> <span class="nx">tasks</span><span class="p">,</span> <span class="nx">onTglStatus</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">Task</span> <span class="na">task</span><span class="o">=</span><span class="p">{</span><span class="nx">task</span><span class="p">}</span> <span class="na">onTglStatus</span><span class="o">=</span><span class="p">{</span><span class="nx">onTglStatus</span><span class="p">}</span> <span class="p">/&gt;;</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Call the function in <code>Task.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Task</span><span class="p">({</span> <span class="nx">task</span><span class="p">,</span> <span class="nx">onTglStatus</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">button</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;button icon-only clear&#34;</span> <span class="na">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="p">=&gt;</span> <span class="nx">onTglStatus</span><span class="p">(</span><span class="nx">task</span><span class="p">)}&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&gt;</span> <span class="s2">&#34;⬜&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;;</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Click the button to see the debug statement in developer console.</p>
<p>We have moved props including variables(state) and functions that act on the state down the chain, and events get surfaced up the component chain!</p>
<p>Add the function to do something beyond just a debug statement in <code>App.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">onTglStatus</span> <span class="o">=</span> <span class="p">(</span><span class="nx">task</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;completing task&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">setTasks</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nx">tasks</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">chkTask</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">chkTask</span><span class="p">.</span><span class="nx">complete</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">        <span class="nx">task</span><span class="p">.</span><span class="nx">id</span> <span class="o">===</span> <span class="nx">chkTask</span><span class="p">.</span><span class="nx">id</span> <span class="o">?</span> <span class="o">!</span><span class="nx">chkTask</span><span class="p">.</span><span class="nx">complete</span> <span class="o">:</span> <span class="nx">chkTask</span><span class="p">.</span><span class="nx">complete</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="nx">chkTask</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>In the above code we use <code>Array.map</code> function to change status for the matching record. The matching record (<code>task</code>) is supplied by the function called by button click event.</p>
<p>Let us change the checkbox/button in indicate completed tasks in <code>Task.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">button</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;button icon-only clear&#34;</span> <span class="na">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="p">=&gt;</span> <span class="nx">onTglStatus</span><span class="p">(</span><span class="nx">task</span><span class="p">)}&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="nx">task</span><span class="p">.</span><span class="nx">complete</span> <span class="o">&amp;&amp;</span> <span class="s2">&#34;✅&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="o">!</span><span class="nx">task</span><span class="p">.</span><span class="nx">complete</span> <span class="o">&amp;&amp;</span> <span class="s2">&#34;⬜&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span></code></pre></div><p>We use one of the old Javascript tricks to display <code>✅</code> when task is complete.</p>
<ul>
<li><code>{task.complete &amp;&amp; &quot;✅&quot;}</code> evaluates to <code>✅</code> when <code>task.complete</code> is true. Else this returns nothing</li>
<li>The next expression <code>{!task.complete &amp;&amp; &quot;⬜&quot;}</code> returns <code>⬜</code> when <code>task.complete</code> is false</li>
</ul>
<p>Since our application is reactive to changes and the button label gets driven by data, we see the below behaviour.</p>
<p><img loading="lazy" src="/2021/reactive-buttons-data-react.gif" type="" alt="reactive-buttons-data-react"  /></p>
<h2 id="add-functionality-add-task">Add Functionality: Add Task</h2>
<p>We need to get task data from user and save new tasks. To that end, add the function to save tasks <code>onSaveTask</code> in <code>App.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">onSaveTask</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">desc</span><span class="p">,</span> <span class="nx">date</span> <span class="p">})</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;saving tasks&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">setTasks</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span> <span class="nx">desc</span><span class="o">:</span> <span class="nx">desc</span><span class="p">,</span> <span class="nx">date</span><span class="o">:</span> <span class="nx">date</span><span class="p">,</span> <span class="nx">id</span><span class="o">:</span> <span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">(),</span> <span class="nx">complete</span><span class="o">:</span> <span class="kc">false</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">...</span><span class="nx">tasks</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>We are using <code>setTasks</code> like before, but this time we are adding a new element to the array. Again, we don&rsquo;t add the element directly to array since the state variable is immutable. We rather do this -</p>
<ol>
<li>create a new variable</li>
<li>Add <code>{ desc: desc, date: date, id: Date.now(), complete: false },</code> as the first element. <code>desc</code> and <code>date</code> are passed along by the form used to create new tasks. <code>Date.now()</code> is a simple way to make the id unique</li>
<li>Add the existing array elements to the new array variable <code>...tasks</code></li>
</ol>
<p>Next, add a new form to collect data. Let&rsquo;s create a new component <code>src/components/TaskEdit.js</code>. This component will receive the function <code>onSaveTask</code> as props and call it on button click.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useState</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;react&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">TaskEdit</span><span class="p">({</span> <span class="nx">task</span><span class="p">,</span> <span class="nx">onSaveTask</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">desc</span><span class="p">,</span> <span class="nx">setDesc</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">date</span><span class="p">,</span> <span class="nx">setDate</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">saveTask</span> <span class="o">=</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">onSaveTask</span><span class="p">({</span> <span class="nx">desc</span><span class="o">:</span> <span class="nx">desc</span><span class="p">,</span> <span class="nx">date</span><span class="o">:</span> <span class="nx">date</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">setDesc</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setDate</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;card&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h3</span><span class="p">&gt;</span><span class="nx">Add</span> <span class="nx">Task</span><span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">htmlFor</span><span class="o">=</span><span class="s">&#34;desc&#34;</span><span class="p">&gt;</span><span class="nx">Description</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">input</span>
</span></span><span class="line"><span class="cl">          <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">name</span><span class="o">=</span><span class="s">&#34;desc&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">id</span><span class="o">=</span><span class="s">&#34;desc&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">value</span><span class="o">=</span><span class="p">{</span><span class="nx">desc</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">          <span class="na">onChange</span><span class="o">=</span><span class="p">{(</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">setDesc</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">)}</span>
</span></span><span class="line"><span class="cl">        <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">htmlFor</span><span class="o">=</span><span class="s">&#34;date&#34;</span><span class="p">&gt;</span><span class="nb">Date</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">input</span>
</span></span><span class="line"><span class="cl">          <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">name</span><span class="o">=</span><span class="s">&#34;date&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">id</span><span class="o">=</span><span class="s">&#34;date&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">value</span><span class="o">=</span><span class="p">{</span><span class="nx">date</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">          <span class="na">onChange</span><span class="o">=</span><span class="p">{(</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">setDate</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">)}</span>
</span></span><span class="line"><span class="cl">        <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;text-right&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">button</span> <span class="na">className</span><span class="o">=</span><span class="s">&#34;button dark&#34;</span> <span class="na">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">saveTask</span><span class="p">}&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Save</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">TaskEdit</span><span class="p">;</span>
</span></span></code></pre></div><p>We have gone through some of the functions implemented here, while rest are mostly HTML -</p>
<ol>
<li><code>const [desc, setDesc] = useState(&quot;&quot;);</code> creates a new state variale local to <code>TaskEdit</code> and initiates it to <code>&quot;&quot;</code></li>
<li>a standard HTML form displays a couple of text boxes to collect <code>desc</code> and <code>date</code></li>
<li><code>Save</code> button calls a local method <code>saveTask</code>, which will call the <code>onSaveTask</code> function in <code>App.js</code> and resets form</li>
</ol>
<p>Add functionality to <code>New</code> button so that it displays the <code>TaskEdit</code> component and associated form (and can also toggle to hide the form).</p>
<p>In <code>App.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">[</span><span class="nx">showTaskEdit</span><span class="p">,</span> <span class="nx">setShowTaskEdit</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">button</span>
</span></span><span class="line"><span class="cl">  <span class="na">className</span><span class="o">=</span><span class="s">&#34;button outline&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="p">=&gt;</span> <span class="nx">setShowTaskEdit</span><span class="p">(</span><span class="o">!</span><span class="nx">showTaskEdit</span><span class="p">)}&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="o">!</span><span class="nx">showTaskEdit</span> <span class="o">&amp;&amp;</span> <span class="s2">&#34;New&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="nx">showTaskEdit</span> <span class="o">&amp;&amp;</span> <span class="s2">&#34;➖&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">showTaskEdit</span> <span class="o">&amp;&amp;</span> <span class="p">&lt;</span><span class="nt">TaskEdit</span> <span class="na">task</span><span class="o">=</span><span class="p">{{}}</span> <span class="na">onSaveTask</span><span class="o">=</span><span class="p">{</span><span class="nx">onSaveTask</span><span class="p">}</span> <span class="p">/&gt;;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">//  ...
</span></span></span></code></pre></div><p>We conditionally show <code>TaskEdit</code> only if <code>showTaskEdit</code> is <code>true</code>.</p>
<p>Time to see the complete application in action -</p>
<p><img loading="lazy" src="/2021/react-task-manager--simple-app-demo.gif" type="" alt="react-task-manager&ndash;simple-app-demo"  /></p>
<h2 id="next-steps">Next Steps</h2>
<ul>
<li>Enable user to edit tasks to change description and dates</li>
<li>Add a backend for your task manager</li>
</ul>
<p>Code for this project is available in the <a href="https://github.com/prashanth1k/tasker-react-sample-app">Github repo</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Get Started on NextJS</title>
      <link>https://techformist.com/get-started-nextjs/</link>
      <pubDate>Wed, 06 Jan 2021 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/get-started-nextjs/</guid>
      <description>&lt;p&gt;Welcome to 2021. For me this will be an exciting year when I embrace ReactJS and Svelte as friends. And, what better way to start with React than NextJS..? In this post, we will see why and how we can get started on NextJS, and a few good learning resources.&lt;/p&gt;
&lt;h2 id=&#34;but-why&#34;&gt;But, why?&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;React continues to be a leader with ~50% market share. It enjoys a lot of developer confidence, community contribution and widespread adoption&lt;/li&gt;
&lt;li&gt;More users have meant more support for the smallest of issues&lt;/li&gt;
&lt;li&gt;React and associated frameworks have been at the forefront of new developments - that may be in the way pages interact with data (Hooks, Suspense), in how front-end gets/updates data (React Server Components), or how the latest technologies can speed up development and enable you to use hybrid frameworks to get things done (Next)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Vue will not be completely replaced in my toolbox - not unless I find a shiny new thing that can completely replace it. In today&amp;rsquo;s world everyone learns from each other and adapts rather quickly - so that scenario is not likely to play out.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Welcome to 2021. For me this will be an exciting year when I embrace ReactJS and Svelte as friends. And, what better way to start with React than NextJS..? In this post, we will see why and how we can get started on NextJS, and a few good learning resources.</p>
<h2 id="but-why">But, why?</h2>
<ol>
<li>React continues to be a leader with ~50% market share. It enjoys a lot of developer confidence, community contribution and widespread adoption</li>
<li>More users have meant more support for the smallest of issues</li>
<li>React and associated frameworks have been at the forefront of new developments - that may be in the way pages interact with data (Hooks, Suspense), in how front-end gets/updates data (React Server Components), or how the latest technologies can speed up development and enable you to use hybrid frameworks to get things done (Next)</li>
</ol>
<p>Vue will not be completely replaced in my toolbox - not unless I find a shiny new thing that can completely replace it. In today&rsquo;s world everyone learns from each other and adapts rather quickly - so that scenario is not likely to play out.</p>
<h2 id="why-next">Why Next?</h2>
<ul>
<li>Next is a hybrid framework. From the same code base you can -
<ul>
<li>fetch content and generate pages on the server-side at runtime. Rapidly changing sites incl. eCommerce sites.</li>
<li>enable client-side data fetching for classic single page applications</li>
<li>generate static sites. Just fetch data and create final HTML pages at build time. Useful for Blogs, documentation sites. Oor, go rogue with incremental static files that can generate pages and hold on to them for specified time (I love this!)</li>
</ul>
</li>
<li>Built-in router that needs you to just create pages to enable routing. Not really a problem in the Vue world (Vue router becomes second nature), but I see React as more fragmented. Router in Next is easy to understand and scale</li>
<li>Many features that optimize applications incl. code splitting, ability to use HTML or JSON to deliver pages, and so on</li>
<li>Many, many features that make development of large apps easier</li>
<li>Super active development and large community.</li>
</ul>
<h2 id="how-to-get-started">How to get started?</h2>
<p>Here&rsquo;s the complicated ceremonty to initiate a Next project.</p>
<ol>
<li>Install NodeJS</li>
<li>Enter command <code>npx create-next-app do-awesome</code></li>
</ol>
<p>Run your app with <code>npm run dev</code> to meet this screen.</p>
<p><img loading="lazy" src="/2021/create-next-app-starting-page.jpg" type="" alt="create-next-app-starting-page"  /></p>
<p>You have the standard SPA development experience - change page content to see the changes reflected immediately.</p>
<ol>
<li>Add new page <code>pages/todo.js</code></li>
<li>Enter below code -
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">Todo</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="o">&lt;</span><span class="nx">h3</span><span class="o">&gt;</span><span class="nx">Todo</span> <span class="nx">Awesome</span><span class="o">&lt;</span><span class="err">/h3&gt;;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ol>
<p>Navigate to <code>http://localhost:3000/todo</code> to see the new page.</p>
<p>Let&rsquo;s write some simple code in <code>todos</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Todo</span><span class="p">({</span> <span class="nx">todos</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">h2</span><span class="o">&gt;</span><span class="nx">Todo</span> <span class="nx">Awesome</span><span class="o">&lt;</span><span class="err">/h2&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="nx">todos</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">todo</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">li</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">index</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">description</span><span class="p">}</span><span class="o">&amp;</span><span class="nx">emsp</span><span class="p">;</span><span class="err">⇋</span> <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">status</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="err">/li&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">))}</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kd">function</span> <span class="nx">getServerSideProps</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todos</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span> <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;Write blog post&#34;</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;Open&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span> <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;Learn magic trick&#34;</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;Open&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span> <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;Profit from blog&#34;</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;Cancelled&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span> <span class="nx">todos</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Todo</span><span class="p">;</span>
</span></span></code></pre></div><p>We did good in a few lines of code -</p>
<ol>
<li>Created some static data in <code>todos</code> as part of <code>getServerSideProps</code> and returned that as <code>props</code></li>
<li><code>getServerSideProps</code> gets executed for every function call, i.e., everytime we visit the route <code>/todos</code>. Rendering function <code>Todo</code> gets the data passed in as props</li>
<li><code>Todo</code> takes care of rendering the todos</li>
</ol>
<p>Rather simple and elegant.</p>
<p><img loading="lazy" src="/2021/next-page-basic-todo.jpg" type="" alt="next-page-basic-todo"  /></p>
<h2 id="add-styles">Add Styles</h2>
<p>There is more than one way to do things in Next, just like in React - unfortunately.
I follow three distinct patterns.</p>
<h4 id="global-or-module-level-styles">Global or Module Level Styles</h4>
<p>Include CSS in <code>styles &gt; global.css</code> for all styles applicable globally. Similarly, <code>&lt;your-page&gt;.module.css</code> gets applied to <code>&lt;your-page&gt;</code>.</p>
<p>There&rsquo;s nothing preventing you from going old school and simple do -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;../styles.css&#34;</span><span class="p">;</span>
</span></span></code></pre></div><p>.. in any component, but the previous pattern is simpler to use.</p>
<h4 id="global-or-module-level-css-with-cdn">Global or Module Level CSS with CDN</h4>
<p>Use the Next <code>&lt;Head&gt;&lt;/Head&gt;</code> tag anywhere - in <code>_app</code> for global styles or in any modules. Introduce CSS within the <code>HEAD</code> component.</p>
<p>Let us go ahead and do this for our app. Change <code>_app.js</code> to-</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;../styles/globals.css&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Head</span> <span class="nx">from</span> <span class="s2">&#34;next/head&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">MyApp</span><span class="p">({</span> <span class="nx">Component</span><span class="p">,</span> <span class="nx">pageProps</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">Head</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">link</span> <span class="nx">rel</span><span class="o">=</span><span class="s2">&#34;stylesheet&#34;</span> <span class="nx">href</span><span class="o">=</span><span class="s2">&#34;https://unpkg.com/chota&#34;</span> <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="err">/Head&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;row&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-1&#34;</span><span class="o">&gt;&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-10&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="nx">Component</span> <span class="p">{...</span><span class="nx">pageProps</span><span class="p">}</span> <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-1&#34;</span><span class="o">&gt;&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">MyApp</span><span class="p">;</span>
</span></span></code></pre></div><p><code>chota</code> is a small CSS framework that provides you some cool things like class-less styling, grids, out-of-the-box icons - good enough for our small project.</p>
<p>Remember that we are dealing with JSX, so we use <code>className</code> instead of <code>class</code> in normal HTML.</p>
<h4 id="style-libraries-from-npm">Style Libraries from NPM</h4>
<p>Install any CSS library through NPM. You can now include the library in <code>_app.js</code> for global styles.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;bootstrap/dist/css/bootstrap.css&#34;</span><span class="p">;</span>
</span></span></code></pre></div><h2 id="add-a-db">Add a DB!</h2>
<p>Our <code>todo</code> page is static and shows the same data each time. Let us change that.</p>
<p>First, let us add prisma to our project to make database access a breeze.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i -D @prisma/cli
</span></span><span class="line"><span class="cl">npm i @prisma/client
</span></span></code></pre></div><p>Create a new folder <code>data</code> under project root.</p>
<p>Initialize prisma -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npx prisma init
</span></span></code></pre></div><p>Prisma CLI creates a few files including -</p>
<ul>
<li><code>.env</code> file (if it doesn&rsquo;t exist) with a database URL</li>
<li><code>prisma/schema.prisma</code> contains the database connection parameters and DB models</li>
</ul>
<p>Open <code>prisma/schema.prisma</code> and replace its contents with the below code -</p>
<pre tabindex="0"><code>datasource db {
  provider = &#34;sqlite&#34;
  url      = &#34;file:../data/data.db&#34;
}

generator client {
  provider = &#34;prisma-client-js&#34;
}

model todo {
  id Int @id @default(autoincrement())
  description String
  status String
}
</code></pre><p>Run the below command to create migration and sync model to database.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npx prisma migrate dev --preview-feature
</span></span></code></pre></div><p><code>preview-feature</code> flag may not be required in later versions of prisma. You can provide any name for the migration.</p>
<p>Finally, run the <code>generate</code> command to generate client that can be used in your application.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npx prisma generate
</span></span></code></pre></div><p>You can connect to the SQLite database using a client like <a href="https://www.heidisql.com/">HeidiSQL</a> and verify whether all your changes are applied to the table.</p>
<p><img loading="lazy" src="/2021/heidi-sql-sqlite.jpg" type="" alt="heidi-sql-sqlite"  /></p>
<p>Or, you could simply do -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npx prisma studio
</span></span></code></pre></div><p>.. to open the database with a simple UI.</p>
<p><img loading="lazy" src="/2021/prisma-studio.jpg" type="" alt="prisma-studio"  /></p>
<p>You are all set to work with the SQLite database from Next using Prisma!</p>
<h2 id="get-todos">Get Todos</h2>
<p>Change <code>pages/todos.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">PrismaClient</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;@prisma/client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">prisma</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PrismaClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Todo</span><span class="p">({</span> <span class="nx">todos</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;row&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">h2</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-12 list-title is-center&#34;</span><span class="o">&gt;</span><span class="nx">My</span> <span class="nx">Todos</span><span class="o">&lt;</span><span class="err">/h2&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-12&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span><span class="nx">todoArr</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">todo</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;row&#34;</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">index</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-1 list-desc&#34;</span> <span class="nx">name</span><span class="o">=</span><span class="s2">&#34;id&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-5 list-desc&#34;</span> <span class="nx">name</span><span class="o">=</span><span class="s2">&#34;description&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">description</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-4&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="nx">select</span>
</span></span><span class="line"><span class="cl">                <span class="nx">name</span><span class="o">=</span><span class="s2">&#34;status&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="nx">id</span><span class="o">=</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">status</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">handleStatusChange</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="nx">onBlur</span><span class="o">=</span><span class="p">{</span><span class="nx">handleSubmit</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">option</span> <span class="nx">value</span><span class="o">=</span><span class="s2">&#34;Open&#34;</span><span class="o">&gt;</span><span class="nx">Open</span><span class="o">&lt;</span><span class="err">/option&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">option</span> <span class="nx">value</span><span class="o">=</span><span class="s2">&#34;In Progress&#34;</span><span class="o">&gt;</span><span class="nx">In</span> <span class="nx">Progress</span><span class="o">&lt;</span><span class="err">/option&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">option</span> <span class="nx">value</span><span class="o">=</span><span class="s2">&#34;Cancelled&#34;</span><span class="o">&gt;</span><span class="nx">Cancelled</span><span class="o">&lt;</span><span class="err">/option&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="err">/select&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">))}</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">getServerSideProps</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todos</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">prisma</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="nx">findMany</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">orderBy</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">id</span><span class="o">:</span> <span class="s2">&#34;desc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;todos: &#34;</span><span class="p">,</span> <span class="nx">todos</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span> <span class="nx">todos</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Todo</span><span class="p">;</span>
</span></span></code></pre></div><p>The above code is straight-forward -</p>
<ul>
<li><code>getServerSideProps</code> includes logic that executes on the server side when a request is made to <code>http://localhost:3000/todos</code> (remember that the file is at <code>pages/todos.js</code>)</li>
<li>Next passes the data from <code>getServerSideProps</code> to render function <code>function Todo({ todos })</code></li>
<li>We display the <code>todos</code> data using JSX</li>
</ul>
<h2 id="createedit-todos">Create/Edit Todos</h2>
<p>We need Prisma (i.e., any DB operations) to run on the server. Next makes an easy task of creating backend APIs - no separate server needed (you could have your custom server though).</p>
<h3 id="create-apis">Create APIs</h3>
<h4 id="api-new-todo">API: New Todo</h4>
<p>Create new file <code>pages/api/todos/index.js</code> with below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">PrismaClient</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;@prisma/client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">prisma</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PrismaClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">handle</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Processing todo request..&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">id</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">method</span> <span class="o">==</span> <span class="s2">&#34;GET&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s2">&#34;hello&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">method</span> <span class="o">==</span> <span class="s2">&#34;POST&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">newTodo</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">prisma</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="nx">create</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">data</span><span class="o">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="nx">newTodo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Open the Developer Console in Chrome (<code>Ctrl+Shift+i</code>) and enter -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">await</span> <span class="nx">fetch</span> <span class="p">(</span><span class="s1">&#39;http://localhost:3000/api/todos&#39;</span><span class="p">)</span><span class="sb">`
</span></span></span></code></pre></div><p>.. to see &ldquo;hello&rdquo; returned. And oh.. we added the actual method to accept data from frontend and create a new record using Prisma. All it took was a couple of lines of code.</p>
<h4 id="api-updatedelete-todo">API: Update/Delete Todo</h4>
<p>While we are here, we will also handle -</p>
<ol>
<li>Record-specific deletes (<code>DELETE</code> method that will use <code>/api/todos/1</code> to delete record with <code>id</code>=1)</li>
<li>Record-specific updates (<code>PATCH</code> method to <code>/api/todos/2</code> to update record with <code>id</code>=2)</li>
</ol>
<p>The depicted URLs are standard REST resource URLs - nothing fancy here.</p>
<p>Create new file <code>pages/api/todos/index.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">PrismaClient</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;@prisma/client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">prisma</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PrismaClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">handle</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">id</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">method</span> <span class="o">==</span> <span class="s2">&#34;DELETE&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Processing todo delete..&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">todo</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">prisma</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="k">delete</span><span class="p">({</span> <span class="nx">where</span><span class="o">:</span> <span class="p">{</span> <span class="nx">id</span><span class="o">:</span> <span class="nb">Number</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">}</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="nx">todo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">method</span> <span class="o">==</span> <span class="s2">&#34;PATCH&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Processing todo update..&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">newTodo</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">prisma</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="nx">update</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">data</span><span class="o">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="nx">newTodo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You might have noticed one key difference between the <code>GET</code> and <code>POST/DELETE/PATCH</code>. While we coded <code>GET</code> within the page itself, we used <code>api</code> folder to house update operations.</p>
<ul>
<li>While <code>prisma</code> was used in the <code>todos.js</code> page, <code>getServerSideProps</code> executes on server. So, we did not have any issues placing backend-specific logic there</li>
<li>Updates are not tied to backend in such fashion. Instead we create APIs in the <code>api</code> folder and call them using <code>fetch</code></li>
</ul>
<h3 id="change-ui-to-call-apis">Change UI to Call APIs</h3>
<p>Before we go ahead with UI changes, you would have noticed a problem with our file structure. While APIs had <code>index</code> and <code>[id]</code> files grouped under a parent <code>todos</code>, we do not have this structure in the frontend yet. Let&rsquo;s change that.</p>
<p>Create a new folder <code>pages/todos</code> - this will house all functions for <code>todos</code>. Move <code>pages/todos.js</code> to <code>pages/todos/</code> and rename it to <code>index.js</code>.</p>
<h4 id="todo-list">Todo List</h4>
<p>Replace current code in <code>pages/todos/index.js</code> with -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useState</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;react&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">PrismaClient</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;@prisma/client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Link</span> <span class="nx">from</span> <span class="s2">&#34;next/link&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">prisma</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PrismaClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Todo</span><span class="p">({</span> <span class="nx">todos</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">todoIn</span><span class="p">,</span> <span class="nx">setTodoIn</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">todoArr</span><span class="p">,</span> <span class="nx">setTodoArr</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="nx">todos</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">handleNewTodoChange</span> <span class="o">=</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setTodoIn</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">handleSubmit</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span><span class="s2">&#34;/api/todos&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">method</span><span class="o">:</span> <span class="s2">&#34;POST&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">body</span><span class="o">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span> <span class="nx">description</span><span class="o">:</span> <span class="nx">todoIn</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;Open&#34;</span> <span class="p">}),</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">newTodo</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setTodoArr</span><span class="p">([</span><span class="nx">newTodo</span><span class="p">,</span> <span class="p">...</span><span class="nx">todoArr</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setTodoIn</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">handleStatusChange</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;target&#34;</span><span class="p">,</span> <span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span><span class="s2">&#34;/api/todos&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">method</span><span class="o">:</span> <span class="s2">&#34;POST&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">body</span><span class="o">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span> <span class="nx">description</span><span class="o">:</span> <span class="nx">todoIn</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;Open&#34;</span> <span class="p">}),</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">newTodo</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setTodoArr</span><span class="p">([</span><span class="nx">newTodo</span><span class="p">,</span> <span class="p">...</span><span class="nx">todoArr</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">deleteTodo</span> <span class="o">=</span> <span class="p">(</span><span class="nx">todo</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span><span class="sb">`/api/todos/</span><span class="si">${</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="si">}</span><span class="sb">`</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">method</span><span class="o">:</span> <span class="s2">&#34;DELETE&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">index</span> <span class="o">=</span> <span class="nx">todoArr</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">todo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setTodoArr</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">      <span class="p">...</span><span class="nx">todoArr</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">index</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">      <span class="p">...</span><span class="nx">todoArr</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="nx">index</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">todoArr</span><span class="p">.</span><span class="nx">length</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">]);</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;row&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">h2</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-12 list-title is-center&#34;</span><span class="o">&gt;</span><span class="nx">My</span> <span class="nx">Todos</span><span class="o">&lt;</span><span class="err">/h2&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">form</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-12&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;row&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="nx">span</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-1 list-desc&#34;</span><span class="o">&gt;</span><span class="nx">Add</span><span class="o">&lt;</span><span class="err">/span&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="nx">input</span>
</span></span><span class="line"><span class="cl">            <span class="nx">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">onBlur</span><span class="o">=</span><span class="p">{</span><span class="nx">handleNewTodoChange</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-5&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">handleNewTodoChange</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">todoIn</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">          <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;button col-2&#34;</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">handleSubmit</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Save</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="err">/button&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="err">/form&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-12&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span><span class="nx">todoArr</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">todo</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;row&#34;</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">index</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-1 list-desc&#34;</span> <span class="nx">name</span><span class="o">=</span><span class="s2">&#34;id&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-5 list-desc&#34;</span> <span class="nx">name</span><span class="o">=</span><span class="s2">&#34;description&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">description</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-4&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="nx">select</span>
</span></span><span class="line"><span class="cl">                <span class="nx">name</span><span class="o">=</span><span class="s2">&#34;status&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="nx">id</span><span class="o">=</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">status</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">handleStatusChange</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="nx">onBlur</span><span class="o">=</span><span class="p">{</span><span class="nx">handleSubmit</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">option</span> <span class="nx">value</span><span class="o">=</span><span class="s2">&#34;Open&#34;</span><span class="o">&gt;</span><span class="nx">Open</span><span class="o">&lt;</span><span class="err">/option&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">option</span> <span class="nx">value</span><span class="o">=</span><span class="s2">&#34;In Progress&#34;</span><span class="o">&gt;</span><span class="nx">In</span> <span class="nx">Progress</span><span class="o">&lt;</span><span class="err">/option&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">option</span> <span class="nx">value</span><span class="o">=</span><span class="s2">&#34;Cancelled&#34;</span><span class="o">&gt;</span><span class="nx">Cancelled</span><span class="o">&lt;</span><span class="err">/option&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="err">/select&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-2 icon&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;button icon-only&#34;</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">deleteTodo</span><span class="p">(</span><span class="nx">todo</span><span class="p">)}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">img</span>
</span></span><span class="line"><span class="cl">                  <span class="nx">src</span><span class="o">=</span><span class="s2">&#34;https://icongr.am/feather/delete.svg?size=16&amp;color=93939a&#34;</span>
</span></span><span class="line"><span class="cl">                  <span class="nx">alt</span><span class="o">=</span><span class="s2">&#34;delete&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="err">/button&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="nx">Link</span> <span class="nx">href</span><span class="o">=</span><span class="p">{</span><span class="sb">`/todos/</span><span class="si">${</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="si">}</span><span class="sb">`</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;button icon-only&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="o">&lt;</span><span class="nx">img</span>
</span></span><span class="line"><span class="cl">                    <span class="nx">src</span><span class="o">=</span><span class="s2">&#34;https://icongr.am/feather/edit-2.svg?size=16&amp;color=93939a&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="nx">alt</span><span class="o">=</span><span class="s2">&#34;edit&#34;</span>
</span></span><span class="line"><span class="cl">                  <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="err">/button&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="err">/Link&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">))}</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">getServerSideProps</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todos</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">prisma</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="nx">findMany</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">orderBy</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">id</span><span class="o">:</span> <span class="s2">&#34;desc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;todos: &#34;</span><span class="p">,</span> <span class="nx">todos</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span> <span class="nx">todos</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Todo</span><span class="p">;</span>
</span></span></code></pre></div><p>We have added below features -</p>
<ul>
<li>Add an input box and a button to add a new <code>todo</code> record. Add functions to handle changes to input and to respond to the click event</li>
<li>Add functions to handle changes to call backend APIs for inserts and deletes, and make corresponding changes on the UI</li>
<li>Create a button to delete a <code>todo</code> and call API DELETE method</li>
<li>Create a button to navigate to a detail page upon clicking on any todo (the detail page is implemented in the next section)</li>
</ul>
<h4 id="todo-detail">Todo Detail</h4>
<p>With a couple of functions you have created an app to query ( &amp; display), create and delete todos!</p>
<p>Create a new page <code>pages/todos/[id].js</code> and input below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useRouter</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;next/router&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">PrismaClient</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;@prisma/client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">prisma</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PrismaClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">Todo</span><span class="p">({</span> <span class="nx">todo</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">useRouter</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">{</span> <span class="nx">id</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">router</span><span class="p">.</span><span class="nx">query</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;text-center&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">h3</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">strong</span><span class="o">&gt;</span><span class="p">{</span><span class="o">!!</span><span class="nx">todo</span> <span class="o">&amp;&amp;</span> <span class="nx">todo</span><span class="p">.</span><span class="nx">description</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/strong&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="err">/h3&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="p">{</span><span class="o">!</span><span class="nx">todo</span> <span class="o">&amp;&amp;</span> <span class="s2">&#34;This todo has migrated to the next universe.&#34;</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/p&gt;</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;&lt;</span><span class="err">/p&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">getServerSideProps</span><span class="p">({</span> <span class="nx">params</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todo</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">prisma</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="nx">findFirst</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">where</span><span class="o">:</span> <span class="p">{</span> <span class="nx">id</span><span class="o">:</span> <span class="nb">Number</span><span class="p">(</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;todo: &#34;</span><span class="p">,</span> <span class="nx">todo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span> <span class="nx">todo</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This page just demonstrates how we could display a single <code>todo</code> on the frontend. We have not added any functionality to it.</p>
<h2 id="what-next">What Next?</h2>
<p>Find the app code at this <a href="https://github.com/prashanth1k/do-awesome-nextjs-sample-app">Github repo</a>.</p>
<p>You could extend the current app by -</p>
<ol>
<li>Introducing update function - status changes should call <code>PATCH</code> method and change UI elements</li>
<li>Enable user to capture thoughts, ideas and other BS against each <code>todo</code>. Doing this would require you to provide functionality to add <code>comments</code> against any specific <code>todo</code> (utilising the <code>Detail page</code>)</li>
</ol>
<h2 id="learning-resources">Learning Resources</h2>
<p>See more of Next and keep rocking.</p>
<ul>
<li><a href="https://nextjs.org/learn/basics/create-nextjs-app">Learn NextJS</a> by Vercel, creator of NextJS</li>
<li><a href="https://www.youtube.com/watch?v=tt3PUvhOVzo">NextJS in 2 hours</a></li>
<li><a href="https://www.youtube.com/watch?v=1GpbdX8aJCU">Create a Snippet Manager in Next</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Create Reddit Reader Using Vue 3 &amp; Vite</title>
      <link>https://techformist.com/reddit-reader-vue3-vite/</link>
      <pubDate>Wed, 30 Dec 2020 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/reddit-reader-vue3-vite/</guid>
      <description>&lt;p&gt;Hello everyone! Hope you are all set for the new year. While you are waiting for the Y2020 to end with bated breath, here&amp;rsquo;s a post to kick start your Vue 3 journey. We will create a Reddit reader using Vue3 and Vite!&lt;/p&gt;
&lt;p&gt;This post is more useful for someone with basic knowledge of Vue and Vue 2.&lt;/p&gt;
&lt;h2 id=&#34;get-started-installation&#34;&gt;Get Started: Installation&lt;/h2&gt;
&lt;p&gt;Create a Vue 3 project with Vite..&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmd&#34; data-lang=&#34;cmd&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;npm create @vitejs/app
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Select the &lt;code&gt;vue&lt;/code&gt; template on prompt to create a new folder for your project. Install dependencies.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Hello everyone! Hope you are all set for the new year. While you are waiting for the Y2020 to end with bated breath, here&rsquo;s a post to kick start your Vue 3 journey. We will create a Reddit reader using Vue3 and Vite!</p>
<p>This post is more useful for someone with basic knowledge of Vue and Vue 2.</p>
<h2 id="get-started-installation">Get Started: Installation</h2>
<p>Create a Vue 3 project with Vite..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm create @vitejs/app
</span></span></code></pre></div><p>Select the <code>vue</code> template on prompt to create a new folder for your project. Install dependencies.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"><span class="k">cd</span> reddit-reader-vite-vue-app
</span></span><span class="line"><span class="cl">npm i
</span></span></code></pre></div><p>Run the project -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm run dev
</span></span></code></pre></div><p>The project starts almost instantaneously.. sweet. Do two more things -</p>
<ul>
<li>Open the project folder in VSCode</li>
<li>Open <code>http://localhost:3000/</code> in your browser</li>
</ul>
<p>Edit the file <code>index.html</code> and include reference to a light-weight CSS framework. I use <a href="https://jenil.github.io/chota/">chota css</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/chota@latest&#34;</span> <span class="p">/&gt;</span>
</span></span></code></pre></div><p>Create a blank file at <code>src/assets/css/styles.css</code> to create custom styles (we will include this file in <code>main.js</code>). I will not explicitly outline any custom styles here, but you should find them here on the Github repo.</p>
<p>Yay.. you have this beautiful app.</p>
<p><img loading="lazy" src="/2020/vite3-initial-page.jpg" type="" alt="vite3-initial-page"  /></p>
<p>You are all set! Let us start coding in the app.</p>
<h2 id="setup-vue-router">Setup Vue Router</h2>
<p>We will have a bunch of links (well, two to be exact) to navigate within the app. Vue Router makes that routing real easy. Let&rsquo;s set it up.</p>
<p>First, install Vue router compatible with Vue3.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i vue-router@4
</span></span></code></pre></div><p>Next, create the router file <code>src/router/index.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">createWebHistory</span><span class="p">,</span> <span class="nx">createRouter</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue-router&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Home</span> <span class="nx">from</span> <span class="s2">&#34;../views/Home.vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">history</span> <span class="o">=</span> <span class="nx">createWebHistory</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">routes</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="nx">component</span><span class="o">:</span> <span class="nx">Home</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;/top&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;../views/Posts.vue&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span> <span class="nx">filter</span><span class="o">:</span> <span class="s2">&#34;top&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;/controversial&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;../views/Posts.vue&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span> <span class="nx">filter</span><span class="o">:</span> <span class="s2">&#34;controversial&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">createRouter</span><span class="p">({</span> <span class="nx">history</span><span class="p">,</span> <span class="nx">routes</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><p>We will use the same view <code>Posts</code> for both top and controversial posts. The view will decide which data to fetch based on the prop called <code>filter</code>, which gets passed by the router.</p>
<p>Change <code>src/main.js</code> to use the router file and include the custom style file we had created earlier -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">createApp</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">App</span> <span class="nx">from</span> <span class="s2">&#34;./App.vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">router</span> <span class="nx">from</span> <span class="s2">&#34;./router&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;./assets/css/styles.css&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">createApp</span><span class="p">(</span><span class="nx">App</span><span class="p">).</span><span class="nx">use</span><span class="p">(</span><span class="nx">router</span><span class="p">).</span><span class="nx">mount</span><span class="p">(</span><span class="s2">&#34;#app&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>There&rsquo;s a small problem with the router code - we don&rsquo;t have those views yet. Let&rsquo;s do that now.</p>
<h2 id="setup-views">Setup Views</h2>
<p>We will create two new views and setup <code>App</code> to use the router.</p>
<h4 id="home">Home</h4>
<p>Create a new view for the home page - <code>src/views/Home.vue</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h3</span><span class="p">&gt;</span>Reddit Reader<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>This is a simple Reddit Reader app.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;card hero justify-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;is-center text-light&#34;</span><span class="p">&gt;</span>Start Here!<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">router-link</span> <span class="na">to</span><span class="o">=</span><span class="s">&#34;/top&#34;</span><span class="p">&gt;</span>Top Posts<span class="p">&lt;/</span><span class="nt">router-link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="ni">&amp;nbsp;</span> | <span class="ni">&amp;nbsp;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">router-link</span> <span class="na">to</span><span class="o">=</span><span class="s">&#34;/controversial&#34;</span><span class="p">&gt;</span>Controversial Posts<span class="p">&lt;/</span><span class="nt">router-link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><h4 id="posts">Posts</h4>
<p>Create a new view for showing the list of posts - <code>src/views/Posts.vue</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;</span>Posts<span class="p">&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><h4 id="appvue">App.vue</h4>
<p>Change code in <code>src/App.vue</code> to make use of router.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">header</span><span class="p">&gt;&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">router-view</span> <span class="na">:key</span><span class="o">=</span><span class="s">&#34;$route.path&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="nx">Header</span> <span class="nx">from</span> <span class="s2">&#34;./components/Header.vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="nx">Footer</span> <span class="nx">from</span> <span class="s2">&#34;./components/Footer.vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">#</span><span class="nn">app</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-family</span><span class="p">:</span> <span class="n">Avenir</span><span class="p">,</span> <span class="n">Helvetica</span><span class="p">,</span> <span class="n">Arial</span><span class="p">,</span> <span class="kc">sans-serif</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kp">-webkit-</span><span class="n">font-smoothing</span><span class="p">:</span> <span class="n">antialiased</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kp">-moz-</span><span class="n">osx-font-smoothing</span><span class="p">:</span> <span class="n">grayscale</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">text-align</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span> <span class="mh">#2c3e50</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin-top</span><span class="p">:</span> <span class="mi">60</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Let&rsquo;s also create two new components for header and footer, which display the logo/brand, navbar and footer for the entire site.</p>
<p>Create new file <code>src/components/Header.vue</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">nav</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav-left&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;logo-brand&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/&#34;</span><span class="p">&gt;</span>Reddit Reader<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav-right&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;tabs&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">router-link</span> <span class="na">to</span><span class="o">=</span><span class="s">&#34;/top&#34;</span><span class="p">&gt;</span>Top<span class="p">&lt;/</span><span class="nt">router-link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">router-link</span> <span class="na">to</span><span class="o">=</span><span class="s">&#34;/controversial&#34;</span><span class="p">&gt;</span>Controversial<span class="p">&lt;/</span><span class="nt">router-link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create new file <code>src/components/Footer.vue</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">footer</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-grey bg-light&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container is-left&#34;</span><span class="p">&gt;</span>i am groot<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><h2 id="change-post-view">Change Post View</h2>
<p>Let&rsquo;s go back to our posts view and do just one thing - outline a list of <code>top</code> and <code>controversial</code> posts. No pagination, showing the page details - nothing. We just take the user to Reddit when a link is clicked. We will use the all new Vue composition API and features.</p>
<p>Let&rsquo;s start by extending the template created earlier to receive props from router, call Reddit API, and display the results.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">strong</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-light&#34;</span><span class="p">&gt;</span>posts<span class="p">&lt;/</span><span class="nt">strong</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-msg&#34;</span><span class="p">&gt;</span>{{ err }}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{ posts }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="p">{</span> <span class="nx">onMounted</span><span class="p">,</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">defineProps</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">([]);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">err</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">mounted</span> <span class="o">=</span> <span class="nx">onMounted</span><span class="p">(</span><span class="kr">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Fetching them posts..&#34;</span><span class="p">,</span> <span class="nx">props</span><span class="p">.</span><span class="nx">filter</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">posts</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetchPosts</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;posts.value: &#34;</span><span class="p">,</span> <span class="nx">posts</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nx">defineProps</span><span class="p">({</span> <span class="nx">filter</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;top&#34;</span> <span class="p">}</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">fetchPosts</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">query</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="sb">`https://api.reddit.com/</span><span class="si">${</span><span class="nx">props</span><span class="p">.</span><span class="nx">filter</span><span class="si">}</span><span class="sb">?limit=10`</span>
</span></span><span class="line"><span class="cl">      <span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">res</span><span class="p">.</span><span class="nx">ok</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">resJson</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">resJson</span><span class="o">?</span><span class="p">.</span><span class="nx">data</span><span class="o">?</span><span class="p">.</span><span class="nx">children</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">res</span><span class="p">.</span><span class="nx">statusText</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;data: &#34;</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">      <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Straight off the bat you will notice a few curiosities.</p>
<h6 id="variables">Variables</h6>
<p>There are no distinct sections that will be exported by default. Instead, we make do with a new function called <code>setup()</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">setup</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>This is further simplified by using <code>&lt;script setup&gt;</code> tag.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="p">{</span> <span class="nx">onMounted</span><span class="p">,</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">defineProps</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h6 id="variables-and-state">Variables and State</h6>
<p>Instead of a <code>data()</code> section in Vue2, we directly define variables in <code>script</code> (you could always mix and match, and confuse yourself and others though).</p>
<p>But, we need to tell Vue that we are creating a state variable that may also be reactive. We do that using <code>ref</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">([]);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">err</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h6 id="props">Props</h6>
<p>Define props with -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nx">defineProps</span><span class="p">({</span> <span class="nx">filter</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;top&#34;</span> <span class="p">}</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h6 id="life-cycle-hooks">Life Cycle Hooks</h6>
<p>We use <code>onMounted</code> hook to fetch data from Reddit.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">mounted</span> <span class="o">=</span> <span class="nx">onMounted</span><span class="p">(</span><span class="kr">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Fetching them posts..&#34;</span><span class="p">,</span> <span class="nx">props</span><span class="p">.</span><span class="nx">filter</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">posts</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetchPosts</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;posts.value: &#34;</span><span class="p">,</span> <span class="nx">posts</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h6 id="methods">Methods</h6>
<p>Methods can be defined anywhere within <code>script</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">fetchPosts</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">query</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="sb">`https://api.reddit.com/</span><span class="si">${</span><span class="nx">props</span><span class="p">.</span><span class="nx">filter</span><span class="si">}</span><span class="sb">?limit=10`</span>
</span></span><span class="line"><span class="cl">      <span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">res</span><span class="p">.</span><span class="nx">ok</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">resJson</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">resJson</span><span class="o">?</span><span class="p">.</span><span class="nx">data</span><span class="o">?</span><span class="p">.</span><span class="nx">children</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">res</span><span class="p">.</span><span class="nx">statusText</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;data: &#34;</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">      <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>With a few cosmetic chahges, the final code for <code>Posts.vue</code> is outlined below -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">strong</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-light&#34;</span><span class="p">&gt;</span>{{ props.filter || &#34;&#34; }} posts<span class="p">&lt;/</span><span class="nt">strong</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-msg&#34;</span><span class="p">&gt;</span>{{ err }}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">v-if</span><span class="o">=</span><span class="s">&#34;!posts || posts.length &lt;= 0&#34;</span><span class="p">&gt;</span>Loading..<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span>
</span></span><span class="line"><span class="cl">      <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-item card text-left&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">v-for</span><span class="o">=</span><span class="s">&#34;(post, index) in posts&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">:key</span><span class="o">=</span><span class="s">&#34;index&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">v-else</span>
</span></span><span class="line"><span class="cl">    <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-title&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">:href</span><span class="o">=</span><span class="s">&#34;post?.data?.url&#34;</span> <span class="na">target</span><span class="o">=</span><span class="s">&#34;_blank&#34;</span><span class="p">&gt;</span>{{ post?.data?.title }}<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-item-meta&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span>
</span></span><span class="line"><span class="cl">          <span class="na">:href</span><span class="o">=</span><span class="s">&#34;`https://reddit.com/${post?.data?.subreddit_name_prefixed}`&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">target</span><span class="o">=</span><span class="s">&#34;blank&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&gt;</span>{{ post?.data?.subreddit_name_prefixed }}<span class="p">&lt;/</span><span class="nt">a</span>
</span></span><span class="line"><span class="cl">        <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        | {{ post?.data?.num_comments }} comments
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="p">{</span> <span class="nx">onMounted</span><span class="p">,</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">defineProps</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">([]);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">err</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">mounted</span> <span class="o">=</span> <span class="nx">onMounted</span><span class="p">(</span><span class="kr">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Fetching them posts..&#34;</span><span class="p">,</span> <span class="nx">props</span><span class="p">.</span><span class="nx">filter</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">posts</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetchPosts</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;posts.value: &#34;</span><span class="p">,</span> <span class="nx">posts</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nx">defineProps</span><span class="p">({</span> <span class="nx">filter</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;top&#34;</span> <span class="p">}</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">fetchPosts</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">query</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="sb">`https://api.reddit.com/</span><span class="si">${</span><span class="nx">props</span><span class="p">.</span><span class="nx">filter</span><span class="si">}</span><span class="sb">?limit=10`</span>
</span></span><span class="line"><span class="cl">      <span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">res</span><span class="p">.</span><span class="nx">ok</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">resJson</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">resJson</span><span class="o">?</span><span class="p">.</span><span class="nx">data</span><span class="o">?</span><span class="p">.</span><span class="nx">children</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">res</span><span class="p">.</span><span class="nx">statusText</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;data: &#34;</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">      <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Your app is now ready to rock!</p>
<p><img loading="lazy" src="/2021/reddit-reader-posts-vite.gif" type="" alt="reddit-reader-posts-vite"  /></p>
<h2 id="finis">Finis</h2>
<p>You will find the complete code at this <a href="https://github.com/prashanth1k/reddit-reader-vite-vue-app">Github repo</a>.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
