<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>PWA |</title><link>https://www.espinosa-oviedo.com/tags/pwa/</link><atom:link href="https://www.espinosa-oviedo.com/tags/pwa/index.xml" rel="self" type="application/rss+xml"/><description>PWA</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Mon, 10 Jun 2024 00:00:00 +0000</lastBuildDate><image><url>https://www.espinosa-oviedo.com/media/icon_hu_8204893b4697223d.png</url><title>PWA</title><link>https://www.espinosa-oviedo.com/tags/pwa/</link></image><item><title>WeatherNow - Real-Time Weather App</title><link>https://www.espinosa-oviedo.com/projects2/weather-app/</link><pubDate>Mon, 10 Jun 2024 00:00:00 +0000</pubDate><guid>https://www.espinosa-oviedo.com/projects2/weather-app/</guid><description>&lt;p&gt;A fast, beautiful weather application that provides real-time weather data, forecasts, and interactive maps. Built as a Progressive Web App with offline support.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;WeatherNow started as a weekend project to learn PWA development. It evolved into a fully-featured weather app used by thousands of people daily.&lt;/p&gt;
&lt;h2 id="features"&gt;Features&lt;/h2&gt;
&lt;h3 id="weather-data"&gt;Weather Data&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Current Conditions&lt;/strong&gt; - Real-time weather for any location&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;7-Day Forecast&lt;/strong&gt; - Detailed daily forecasts with hourly breakdown&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Weather Alerts&lt;/strong&gt; - Severe weather notifications&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Historical Data&lt;/strong&gt; - Past weather data and trends&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="user-experience"&gt;User Experience&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Location Detection&lt;/strong&gt; - Automatic location based on GPS or IP&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Search&lt;/strong&gt; - Find weather for any city worldwide&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Favorites&lt;/strong&gt; - Save frequently checked locations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Units&lt;/strong&gt; - Toggle between metric and imperial&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dark Mode&lt;/strong&gt; - Automatic or manual theme switching&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="progressive-web-app"&gt;Progressive Web App&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Offline Support&lt;/strong&gt; - Access cached data without internet&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Install&lt;/strong&gt; - Add to home screen like a native app&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fast&lt;/strong&gt; - Optimized for performance (Lighthouse 100)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Responsive&lt;/strong&gt; - Perfect on any device&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="technical-highlights"&gt;Technical Highlights&lt;/h2&gt;
&lt;h3 id="performance"&gt;Performance&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Achieved &lt;strong&gt;100/100 Lighthouse score&lt;/strong&gt; across all categories&lt;/li&gt;
&lt;li&gt;Implemented service workers for offline functionality&lt;/li&gt;
&lt;li&gt;Optimized bundle size: &amp;lt; 150KB gzipped&lt;/li&gt;
&lt;li&gt;Lazy loading for images and components&lt;/li&gt;
&lt;li&gt;Prefetching for instant navigation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="data-management"&gt;Data Management&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Smart caching strategy with stale-while-revalidate&lt;/li&gt;
&lt;li&gt;Background sync for updated forecasts&lt;/li&gt;
&lt;li&gt;Efficient API usage with request batching&lt;/li&gt;
&lt;li&gt;Local storage for user preferences&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="uiux"&gt;UI/UX&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Smooth animations with Framer Motion&lt;/li&gt;
&lt;li&gt;Interactive weather map with Mapbox&lt;/li&gt;
&lt;li&gt;Weather icons that match current conditions&lt;/li&gt;
&lt;li&gt;Accessible (WCAG AA compliant)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="api-integration"&gt;API Integration&lt;/h2&gt;
&lt;p&gt;Integrated multiple weather APIs for comprehensive data:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Example: Fetching weather data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchWeather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lat&lt;/span&gt;: &lt;span class="kt"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lon&lt;/span&gt;: &lt;span class="kt"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sb"&gt;`https://api.openweathermap.org/data/2.5/weather?lat=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lat&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;&amp;amp;lon=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lon&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;&amp;amp;appid=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="architecture"&gt;Architecture&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌─────────────┐ ┌──────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ React App │────▶│ OpenWeather │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ (Vite) │ │ API │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└──────┬──────┘ └──────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ┌──────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └───────────▶│ Mapbox │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ API │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └──────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="challenges"&gt;Challenges&lt;/h2&gt;
&lt;h3 id="challenge-api-rate-limits"&gt;Challenge: API Rate Limits&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Implemented intelligent caching and request batching to stay within free tier limits while maintaining data freshness&lt;/p&gt;
&lt;h3 id="challenge-offline-experience"&gt;Challenge: Offline Experience&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Service workers with cache-first strategy for UI, network-first for data with graceful fallbacks&lt;/p&gt;
&lt;h3 id="challenge-performance-on-slow-networks"&gt;Challenge: Performance on Slow Networks&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Image optimization, code splitting, and Progressive rendering for instant perceived performance&lt;/p&gt;
&lt;h2 id="results"&gt;Results&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;📈 &lt;strong&gt;Users&lt;/strong&gt;: 5000+ monthly active users&lt;/li&gt;
&lt;li&gt;⚡ &lt;strong&gt;Performance&lt;/strong&gt;: 100 Lighthouse score&lt;/li&gt;
&lt;li&gt;📱 &lt;strong&gt;PWA&lt;/strong&gt;: 40% of users installed as app&lt;/li&gt;
&lt;li&gt;🌍 &lt;strong&gt;Global&lt;/strong&gt;: Users from 50+ countries&lt;/li&gt;
&lt;li&gt;⭐ &lt;strong&gt;Rating&lt;/strong&gt;: 4.8/5 average user rating&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tech-stack"&gt;Tech Stack&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Frontend&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;React 18&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;Framer Motion&lt;/li&gt;
&lt;li&gt;Vite (build tool)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;APIs&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenWeather API&lt;/li&gt;
&lt;li&gt;Mapbox GL JS&lt;/li&gt;
&lt;li&gt;IP Geolocation API&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Workbox (PWA)&lt;/li&gt;
&lt;li&gt;React Query (data fetching)&lt;/li&gt;
&lt;li&gt;Zustand (state management)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Hosting&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Netlify&lt;/li&gt;
&lt;li&gt;Cloudflare CDN&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="open-source"&gt;Open Source&lt;/h2&gt;
&lt;p&gt;This project is open source and welcomes contributions!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;License&lt;/strong&gt;: MIT&lt;br&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;:
&lt;/p&gt;
&lt;h2 id="lessons-learned"&gt;Lessons Learned&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;PWAs are powerful&lt;/strong&gt;: Service workers enable app-like experiences on the web&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance matters&lt;/strong&gt;: Users notice and appreciate fast apps&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Caching strategy&lt;/strong&gt;: Critical for offline support and API cost management&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplicity wins&lt;/strong&gt;: Started with core features, added more based on user feedback&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="future-plans"&gt;Future Plans&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Weather widgets for websites&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Social features (share weather conditions)&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Weather photography integration&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Apple Watch &amp;amp; Android Wear apps&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Premium features (ad-free, extended forecasts)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Status&lt;/strong&gt;: ✅ Live &amp;amp; Maintained&lt;br&gt;
&lt;strong&gt;Try it&lt;/strong&gt;:
&lt;br&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;:
&lt;/p&gt;</description></item></channel></rss>