<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Osinachukwu Nnanna</title>
    <description>The latest articles on DEV Community by Osinachukwu Nnanna (@osinnanna).</description>
    <link>https://dev.to/osinnanna</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3277313%2F363787dc-36ab-4b9d-acc1-868f8ffab929.png</url>
      <title>DEV Community: Osinachukwu Nnanna</title>
      <link>https://dev.to/osinnanna</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/osinnanna"/>
    <language>en</language>
    <item>
      <title>NextJS Gallery now with Vite</title>
      <dc:creator>Osinachukwu Nnanna</dc:creator>
      <pubDate>Wed, 13 May 2026 00:55:46 +0000</pubDate>
      <link>https://dev.to/osinnanna/nextjs-gallery-now-with-vite-4i</link>
      <guid>https://dev.to/osinnanna/nextjs-gallery-now-with-vite-4i</guid>
      <description>

&lt;p&gt;What I learned porting the Next.js Gallery to a Vite SPA&lt;/p&gt;

&lt;p&gt;I’ve always admired the Next.js Gallery template (&lt;a href="https://nextjsconf-pics.vercel.app/" rel="noopener noreferrer"&gt;https://nextjsconf-pics.vercel.app/&lt;/a&gt;). It’s a beautiful&lt;br&gt;
piece of engineering, but it relies on a lot of &lt;em&gt;"framework magic"&lt;/em&gt; from things like next/image and server-side functions that just work, but are&lt;br&gt;
sometimes hard to peek inside of.&lt;/p&gt;

&lt;p&gt;I decided to try porting it to a Vite SPA (Single Page Application). Not because Vite is "better," but because I wanted to see if I could&lt;br&gt;
replicate those high-end features using simpler, more transparent building blocks like Bun/NodeJS, Sharp, and Supabase.&lt;/p&gt;

&lt;p&gt;Here’s what that process looked like.&lt;/p&gt;

&lt;p&gt;The Goal: High Performance without the "Magic"&lt;/p&gt;

&lt;p&gt;The original template feels great because of two things: layout stability (no jumping around) and those smooth "blur-up" image loads. In a&lt;br&gt;
standard SPA, you usually lose these because you don't have a server processing the images on the fly.&lt;/p&gt;

&lt;p&gt;To get around this, I moved the "thinking" to a build-time script.&lt;/p&gt;

&lt;p&gt;Understanding the Metadata&lt;br&gt;
Instead of asking a server to resize images while the user waits, I wrote a script (src/scripts/buildImages.ts) that runs once before the app&lt;br&gt;
even starts.&lt;/p&gt;

&lt;p&gt;I used Sharp to do the heavy lifting. It opens the images, finds their width and height, and generates a tiny (10px) base64 string. This string&lt;br&gt;
becomes the "blur" you see while the high-res photo is downloading.&lt;/p&gt;

&lt;p&gt;Storing this in a static images.json file felt like a "low-tech" but effective way to get that premium feel without needing a complex backend.&lt;/p&gt;

&lt;p&gt;Building the "Admin" in the Terminal&lt;br&gt;
I realized that for a personal gallery, I didn't really need a web dashboard. I just wanted to drop files in a folder and have them appear.&lt;br&gt;
Also if you use in the uploads/ directory that is created in a links.txt, by providing the image links in this folder, the delimeter/separation would just be a New Line/Enter, once the scipt starts and sees links there it temporarily downloads the files, converts them and then pushes them to the bucket.&lt;/p&gt;

&lt;p&gt;I built a small CLI tool (src/scripts/admin.ts) that handles the "boring" parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Optimizing images to WebP so they don't take up too much space.&lt;/li&gt;
&lt;li&gt;Uploading them to Supabase.&lt;/li&gt;
&lt;li&gt;Setting up the initial user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s not flashy, but it made the workflow feel a lot more "local" and manageable.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I can try Next? (The "Adapter" Idea)
&lt;/h3&gt;

&lt;p&gt;Right now, the project is tied to Supabase. It works well, but I’ve been thinking about how to make it more flexible.&lt;/p&gt;

&lt;p&gt;The next step in this experiment is to pull the Supabase logic out and create Adapters. The idea is that you could use the same gallery UI but&lt;br&gt;
point it at an S3 bucket, Cloudflare R2, or even just a local folder on your computer.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;This project was a great way to demystify how modern galleries work. By stepping away from the "all-in-one" frameworks for a moment, I got to&lt;br&gt;
see exactly how image metadata and placeholders come together to create a smooth user experience.&lt;/p&gt;

&lt;p&gt;Would you like to self-host a gallery website, try it out. There are a little less CVE's to worry about&lt;/p&gt;

&lt;p&gt;If you’re interested in the code or want to try setting up your own, I’ve put everything on GitHub:&lt;/p&gt;

&lt;p&gt;=&amp;gt; &lt;strong&gt;Vite-Gallery&lt;/strong&gt; on GitHub (&lt;a href="https://github.com/osinnanna/vite-gallery" rel="noopener noreferrer"&gt;https://github.com/osinnanna/vite-gallery&lt;/a&gt;)&lt;br&gt;
=&amp;gt; &lt;strong&gt;NextJS Template&lt;/strong&gt; &lt;a href="https://vercel.com/templates/next.js/image-gallery-starter" rel="noopener noreferrer"&gt;on Vercel&lt;/a&gt; and &lt;a href="https://nextjsconf-pics.vercel.app/" rel="noopener noreferrer"&gt;demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’m still tinkering with the adapter logic(local folder inst. of Supabase and other options), so if you have ideas on how to make this more "pluggable," I'd love to hear them.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>performance</category>
      <category>cli</category>
    </item>
  </channel>
</rss>
