Web Development Coding Challenges: Can You Solve These Real Scenarios?
8 min read
Dive into real-world web development coding challenges that test your problem-solving mindset.
By Nikolina Požega
Introduction: Turning Problems into Practice
Every developer knows the rush of fixing a bug after hours of debugging.
But what if those moments became part of how we practice and grow as web developers?
In this post, we explore web development coding challenges inspired by real-world issues — the kind that don’t just test your syntax knowledge, but your ability to think critically and build better solutions.
Let’s see how you’d solve them.
Challenge 1: The Responsive Image Mystery
Your landing page looks great on desktop, but on mobile, the hero image takes forever to load. It’s the same large image served to all devices — wasting bandwidth and slowing performance.
Goal: Serve images that load quickly and look sharp on every device.
Hint: Think about dynamic image delivery and browser-based rendering choices.
Question: How could you automate responsive image sizes for different screen widths?
Solution (to think about): Using a media-aware image service like Cloudinary or imgix, or implementing <picture> and srcset attributes for responsive loading.
💡 Reveal Solution
Use a media-aware image service like Cloudinary or imgix, or implement native HTML responsive loading:
<picture>
<source media="(max-width: 768px)" srcset="/images/hero-small.jpg" />
<source media="(min-width: 769px)" srcset="/images/hero-large.jpg" />
<img src="/images/hero-large.jpg" alt="Hero banner" loading="lazy" />
</picture>
This lets browsers pick the optimal image for each device automatically.
Challenge 2: The SPA SEO Paradox
Your single-page app works beautifully for users — smooth navigation, fast load, great UI. But Google only sees one page. Everything else seems invisible to search engines.
Goal: Make your SPA (Single Page Application) SEO-friendly without breaking routing.
Hint: Think canonical tags, route metadata, and server configuration.
Question: How can a single-page app signal to search engines that its sections matter?
Solution (to think about): Implement server-side or dynamic metadata generation using serverless functions or frameworks like Next.js. Manage canonical tags carefully — one canonical per session, but multiple indexed sections.
💡 Reveal Solution
Implement server-side or dynamic metadata generation with serverless functions. For example, using Vercel:
export default async function handler(req, res) {
const path = req.query.path || '/';
const meta = getMetaForPath(path);
res.setHeader('Content-Type', 'text/html');
res.end(generateHtmlWithMeta(meta));
}
You can serve different tags per route dynamically while maintaining a single-page structure.
Challenge 3: The Font Performance
Your Largest Contentful Paint (LCP) score is low.
Everything seems optimized — except for one thing: the page flashes as fonts load.
The layout shifts slightly when the custom font appears.
Goal: Improve font performance and eliminate layout shifts.
Hint: Consider where the font is hosted and how it’s loaded.
Question: What’s the most reliable way to make web fonts load instantly?
Solution (to think about): Host fonts locally and use @font-face with font-display: swap. Preload key fonts and reduce third-party requests.
💡 Reveal Solution
Host fonts locally and preload them:
<link
rel="preload"
href="/fonts/Audiowide.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<style>
@font-face {
font-family: 'Audiowide';
src: url('/fonts/Audiowide.woff2') format('woff2');
font-display: swap;
}
</style>
This avoids external requests and reduces layout shifts.
Challenge 4: The 404 Mystery
You’ve built a clean SPA with smooth navigation — until someone refreshes a page or shares a deep link. Then, suddenly, it’s a 404. The route exists in your app but not on the server.
Goal: Make every URL in your SPA accessible directly — even on reload.
Hint: The issue might not be in your router.
Question: What happens when the server receives a non-root URL in a SPA setup?
Solution (to think about): Configure your hosting platform (e.g., Vercel, Netlify) to rewrite all requests to index.html. This ensures the client-side router takes over.
💡 Reveal Solution
Configure your hosting platform (e.g., Vercel, Netlify) to rewrite all requests to index.html.
For example, vercel.json:
{
"rewrites": [
{ "source": "/(.*)", "destination": "/" }
]
}
This ensures the client-side router handles navigation properly.
Challenge 5: Run vercel/og in a non-Next.js environment
Goal: Generate dynamic OG images in a React + Vite setup without migrating your whole project to a Next.js.
Hint: You can still use @vercel/og, but you’ll need a small serverless setup to run it.
Question: How can you create dynamic OG images for your Vite app without switching to Next.js?
💡 Reveal Solution
While Vite doesn’t include native API routes, you can still use Vercel Functions to handle OG image generation. All you need is a small endpoint inside your /api directory — just like in Next.js.
Example structure:
/api/og.js:
import { ImageResponse } from '@vercel/og';
export const runtime = 'edge';
export default {
async fetch() {
return new ImageResponse(
(
<div
style={{
background: '#121212',
color: 'white',
fontSize: 48,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
height: '100%',
}}
>
VibeIT 🚀
</div>
)
);
},
};
Challenge 6: The Dynamic OG Tag Problem
You want your social links to display unique images and descriptions for each section of your site. Setting this up with SPA can be challenging.
Goal: Generate dynamic Open Graph (OG) tags that update per route.
Hint: Consider a backend-driven or serverless solution.
Question: How can metadata be served dynamically when routes are client-side?
Solution (to think about): Use serverless functions on your hosting platform (like Vercel) to generate and serve OG tags dynamically. Each request can include metadata for its respective path.
💡 Reveal Solution
Use serverless functions to serve dynamic metadata per route:
const ogData = getOgDataForRoute(pathname);
const dynamicOgImage = `https://${
req.headers.host
}/api/ogImage?title=${encodeURIComponent(ogData.ogTitle)}`;
htmlContent = htmlContent.replace(/__TITLE__/g, ogData.title);
htmlContent = htmlContent.replace(/__DESCRIPTION__/g, ogData.description);
htmlContent = htmlContent.replace(/__OG_TITLE__/g, ogData.ogTitle);
htmlContent = htmlContent.replace(/__OG_DESCRIPTION__/g, ogData.ogDescription);
htmlContent = htmlContent.replace(/__OG_IMAGE__/g, dynamicOgImage);
htmlContent = htmlContent.replace(
/__OG_URL__/g,
`https://${req.headers.host}${pathname}`
);
Then use SSR or prerendering to inject these tags dynamically at build time.
Challenge 7: The Multilingual Expansion
You want to add multilingual versions of your site — but you don’t want to duplicate the entire structure manually.
Goal: Implement translation support that’s scalable and SEO-friendly.
Hint: Centralize translations instead of splitting your codebase.
Question: What’s the cleanest way to manage translations for content and metadata?
Solution (to think about): Use i18next or a similar library to handle translations in separate JSON files. Add a simple language switch for users, and later expand to separate domains if needed.
💡 Reveal Solution
Use i18next to manage translations via JSON files.
i18n.js configuration:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import translationEN from './locales/en/translation.json';
import translationHR from './locales/hr/translation.json';
i18n.use(initReactI18next).init({
resources: {
en: { translation: translationEN },
hr: { translation: translationHR },
},
lng: selectedLang,
fallbackLng: 'hr',
interpolation: { escapeValue: false },
});
export default i18n;
Component:
const { t } = useTranslation();
<SectionTitle>{t('welcomeDevWorld.title')}</SectionTitle>;
And later, expand to domain-based separation like .hr and .tech for multilingual SEO.
Challenge 8: The Build Breaker
Your React + Vite project used a critical Rollup plugin to extract critical CSS — until Vercel’s upgrade to Node 22 suddenly broke your builds. The culprit? Puppeteer, a dependency of the plugin, isn’t compatible with Node 22 in Vercel’s environment.
Goal: Keep your automated build and deployment flow running smoothly despite the Node upgrade.
Hint: If your build step can’t run in Vercel’s environment, maybe it doesn’t have to.
Question: How can you preserve your performance optimization pipeline while adapting to the new runtime?
Solution (to think about): Move your build process to GitHub Actions. By running the build on GitHub before deployment, you can use a compatible Node version, keep Puppeteer working, and deploy the already-built output to Vercel — bypassing the runtime conflict entirely.
💡 Reveal Solution
Move your build process to GitHub Actions.
# .github/workflows/build.yml
name: Vercel Production Deployment (critical-css)
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
on:
push:
branches: [main, develop]
workflow_dispatch: {}
jobs:
critical:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
# ⚡ Install Chromium only if cache is missing
- name: Install Chromium and dependencies
run: |
if [ -d ~/.cache/puppeteer ]; then
echo "Chromium already cached, skipping apt install."
else
echo "Chromium not found, installing..."
sudo apt-get update
sudo apt-get install -y chromium-browser libnss3
fi
# ⚡ Install Node dependencies only if cache missed
- name: Install dependencies
env:
PUPPETEER_EXECUTABLE_PATH: '/usr/bin/chromium-browser'
run: |
npm install
- name: Build site
run: npm run build
# 🚀 Deploy main branch (production)
- name: Deploy to Vercel (production)
if: github.ref == 'refs/heads/main'
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
run: |
npm install -g vercel
vercel pull --yes --environment=production --token=$VERCEL_TOKEN
vercel build --prod --token=$VERCEL_TOKEN
vercel deploy --prebuilt --prod --token=$VERCEL_TOKEN
This lets you run builds in a controlled Node version and deploy pre-built output to Vercel.
Conclusion: Real Challenges, Real Growth
These challenges are based on real development scenarios — the kind that don’t appear in tutorials but show up in every real project.
Solving them sharpens not only your coding skills, but your problem-solving mindset.
Each one is a step toward thinking like a true developer: patient, curious, and always improving.
So — which one will you tackle first?
