\n\u003C/template>",{"id":406,"title":407,"titles":408,"content":409,"level":36},"/blog/mastering-image-optimization-in-nuxt3#_2-responsive-images","2. Responsive Images",[378,398],"\u003Ctemplate>\n \u003CNuxtImg\n src=\"/images/hero.jpg\"\n sizes=\"sm:100vw md:50vw lg:400px\"\n preload\n />\n\u003C/template> Important: Always specify image dimensions to prevent layout shifts!",{"id":411,"title":412,"titles":413,"content":66,"level":25},"/blog/mastering-image-optimization-in-nuxt3#advanced-techniques","Advanced Techniques ๐ฏ",[378],{"id":415,"title":416,"titles":417,"content":418,"level":36},"/blog/mastering-image-optimization-in-nuxt3#image-format-selection","Image Format Selection",[378,412],"First, create a utility function to handle format selection:const formats = {\n jpeg: 'image/jpeg',\n webp: 'image/webp',\n avif: 'image/avif'\n};\n\nconst selectFormat = (formats: string[]) => {\n // Format selection logic\n return formats.find(format =>\n typeof window !== 'undefined' &&\n window.navigator.userAgent.includes(format)\n ) || 'jpeg';\n};\nThen create a reusable component that uses this utility:\u003Cscript setup lang=\"ts\">\nimport { selectFormat } from '~/utils/imageFormatSelector'\n\nconst selectedFormat = ref(selectFormat(['webp', 'jpeg']))\n\n// Props for component customization\ninterface Props {\n src: string\n alt: string\n width?: number\n height?: number\n}\n\nconst props = withDefaults(defineProps\u003CProps>(), {\n width: undefined,\n height: undefined\n})\n\u003C/script>\n\n\u003Ctemplate>\n \u003CNuxtImg\n :src=\"src\"\n :alt=\"alt\"\n :format=\"selectedFormat\"\n :width=\"width\"\n :height=\"height\"\n loading=\"lazy\"\n />\n\u003C/template>\nUsage in your pages or components:\u003Ctemplate>\n \u003COptimizedImage\n src=\"/images/hero.jpg\"\n alt=\"Hero Image\"\n :width=\"800\"\n :height=\"400\"\n />\n\u003C/template>",{"id":420,"title":421,"titles":422,"content":423,"level":36},"/blog/mastering-image-optimization-in-nuxt3#custom-image-provider","Custom Image Provider",[378,412],"export default defineNuxtConfig({\n image: {\n provider: 'cloudinary',\n cloudinary: {\n baseURL: 'https://res.cloudinary.com/your-account/image/upload/'\n }\n }\n})",{"id":425,"title":426,"titles":427,"content":428,"level":36},"/blog/mastering-image-optimization-in-nuxt3#progressive-loading","Progressive Loading",[378,412],"\u003Ctemplate>\n \u003CNuxtImg\n src=\"/images/hero.jpg\"\n placeholder\n blur=\"30\"\n />\n\u003C/template>",{"id":430,"title":431,"titles":432,"content":433,"level":25},"/blog/mastering-image-optimization-in-nuxt3#best-practices","Best Practices ๐",[378],"PracticeDescriptionImpactUse WebPModern format with better compression25-35% smaller filesLazy LoadingLoad images only when neededFaster initial page loadResponsive ImagesDifferent sizes for different screensOptimal deliveryWidth/HeightAlways specify dimensionsPrevents CLS",{"id":435,"title":436,"titles":437,"content":438,"level":36},"/blog/mastering-image-optimization-in-nuxt3#dos","โ
Do's",[378,431],"Implement lazy loading for below-fold imagesUse modern formats like WebP with fallbacksSpecify image dimensionsUse responsive images for different viewports",{"id":440,"title":441,"titles":442,"content":443,"level":36},"/blog/mastering-image-optimization-in-nuxt3#donts","โ Don'ts",[378,431],"Load full-size images for thumbnailsSkip image alt textsIgnore WebP supportUse oversized images",{"id":445,"title":446,"titles":447,"content":448,"level":25},"/blog/mastering-image-optimization-in-nuxt3#performance-metrics","Performance Metrics ๐",[378],"Monitor these key metrics: graph LR\n A[Image Load Time] --> B[Core Web Vitals]\n B --> C[LCP - Largest Contentful Paint]\n B --> D[CLS - Cumulative Layout Shift]\n B --> E[FID - First Input Delay] ๐ฏ Target Metrics:LCP: \u003C 2.5sCLS: \u003C 0.1Image weight: \u003C 200KB for hero images",{"id":450,"title":451,"titles":452,"content":453,"level":25},"/blog/mastering-image-optimization-in-nuxt3#debugging-tools","Debugging Tools ๐ง",[378],"Chrome DevTools\nNetwork tabPerformance tabLighthouseNuxt Image Inspector # Enable in development\n NUXT_IMAGE_PROVIDER_ENABLE_INSPECTOR=true",{"id":455,"title":456,"titles":457,"content":458,"level":25},"/blog/mastering-image-optimization-in-nuxt3#conclusion","Conclusion ๐",[378],"Image optimization in Nuxt 3 is a powerful way to improve your application's performance. By following these guidelines, you can ensure your images load quickly while maintaining quality.",{"id":460,"title":461,"titles":462,"content":463,"level":36},"/blog/mastering-image-optimization-in-nuxt3#resources","Resources ๐",[378,456],"Nuxt Image DocumentationWeb.dev Image OptimizationCore Web Vitals html pre.shiki code .su6et, html code.shiki .su6et{--shiki-default:#A0ADA0;--shiki-dark:#758575DD}html pre.shiki code .sOmcl, html code.shiki .sOmcl{--shiki-default:#59873A;--shiki-dark:#80A665}html pre.shiki code .sl0f5, html code.shiki .sl0f5{--shiki-default:#B56959;--shiki-dark:#C98A7D}html pre.shiki code .s68wy, html code.shiki .s68wy{--shiki-default:#A65E2B;--shiki-dark:#C99076}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s0iuz, html code.shiki .s0iuz{--shiki-default:#1E754F;--shiki-dark:#4D9375}html pre.shiki code .sVgvp, html code.shiki .sVgvp{--shiki-default:#999999;--shiki-dark:#666666}html pre.shiki code .s26OC, html code.shiki .s26OC{--shiki-default:#998418;--shiki-dark:#B8A965}html pre.shiki code .sggpr, html code.shiki .sggpr{--shiki-default:#B5695977;--shiki-dark:#C98A7D77}html pre.shiki code .sThj8, html code.shiki .sThj8{--shiki-default:#2F798A;--shiki-dark:#4C9A91}html pre.shiki code .sVIT7, html code.shiki .sVIT7{--shiki-default:#B07D48;--shiki-dark:#BD976A}html pre.shiki code .sOJWj, html code.shiki .sOJWj{--shiki-default:#AB5959;--shiki-dark:#CB7676}html pre.shiki code .stDYs, html code.shiki .stDYs{--shiki-default:#2E8F82;--shiki-dark:#5DA994}",{"id":465,"title":466,"titles":467,"content":468,"level":19},"/blog/record-and-structs-in-csharp","Records and Structs in C#",[],"A comprehensive guide to understanding the differences between records and structs in C# and when to use each effectively.",{"id":470,"title":471,"titles":472,"content":473,"level":25},"/blog/record-and-structs-in-csharp#understanding-records-and-structs-in-c-a-comprehensive-guide","Understanding Records and Structs in C#: A Comprehensive Guide",[466],"In modern C# development, choosing the right data structure is crucial for writing efficient and maintainable code. Two important options are records and structs, each with distinct characteristics and use cases. This guide will help you understand when to use each one.",{"id":475,"title":476,"titles":477,"content":478,"level":25},"/blog/record-and-structs-in-csharp#what-is-a-struct","What is a Struct?",[466],"A struct (structure) is a value type in C# that encapsulates related data and behaviors. Structs are particularly useful for small, lightweight objects where performance is critical. Here's a basic example of a struct: public struct Point\n{\n public int X { get; set; }\n public int Y { get; set; }\n\n public Point(int x, int y)\n {\n X = x;\n Y = y;\n }\n\n public double DistanceFromOrigin() =>\n Math.Sqrt(X * X + Y * Y);\n}",{"id":480,"title":481,"titles":482,"content":483,"level":36},"/blog/record-and-structs-in-csharp#key-features-of-structs","Key Features of Structs",[466,476],"Value Semantics* Structs are copied when assigned to a new variable\nEach instance maintains its own copy of the dataPassed by value to methods (unless using ref or out)Performance Benefits* Allocated on the stack (for local variables)\nNo garbage collection overheadEfficient for small data structuresLimitations* Cannot inherit from other structs or classes\nCannot be null (unless declared as nullable)Should remain small and lightweightAll fields must be initialized",{"id":485,"title":486,"titles":487,"content":488,"level":25},"/blog/record-and-structs-in-csharp#what-is-a-record","What is a Record?",[466],"Introduced in C# 9.0, records are reference types designed for immutable data modeling. They provide built-in functionality for value-based equality and data manipulation. Here's a simple record declaration: // Immutable record with positional parameters\npublic record Point(int X, int Y)\n{\n public double DistanceFromOrigin =>\n Math.Sqrt(X * X + Y * Y);\n}\n\n// Mutable record (C# 10.0+)\npublic record class MutablePoint\n{\n public int X { get; set; }\n public int Y { get; set; }\n}",{"id":490,"title":491,"titles":492,"content":493,"level":36},"/blog/record-and-structs-in-csharp#key-features-of-records","Key Features of Records",[466,486],"Built-in Functionality* Value-based equality comparisons\nImmutability by defaultBuilt-in ToString() implementationCopy constructors with with expressionsInheritance Support* Can inherit from other records\nSupport for virtual membersInterface implementationPattern Matching* First-class support for deconstruction\nEnhanced pattern matching capabilities",{"id":495,"title":496,"titles":497,"content":498,"level":25},"/blog/record-and-structs-in-csharp#comparing-structs-and-records","Comparing Structs and Records",[466],"FeatureStructRecordType CategoryValue TypeReference TypeMemory LocationStack (usually)HeapMutabilityMutable by defaultImmutable by defaultInheritanceNo inheritanceSupports inheritanceNull AssignmentNo (unless nullable)YesEqualityMember-wise comparisonValue-based equalityPerformanceBetter for small typesBetter for larger typesUse CaseSmall, simple dataComplex domain models",{"id":500,"title":501,"titles":502,"content":66,"level":25},"/blog/record-and-structs-in-csharp#when-to-use-each","When to Use Each",[466],{"id":504,"title":505,"titles":506,"content":507,"level":36},"/blog/record-and-structs-in-csharp#choose-a-struct-when","Choose a Struct When",[466,501],"Working with small, simple data structuresPerformance is criticalThe data structure is less than 16 bytesValue semantics are desiredThe type will be used in arrays public struct Coordinate\n{\n public double Latitude { get; init; }\n public double Longitude { get; init; }\n}",{"id":509,"title":510,"titles":511,"content":512,"level":36},"/blog/record-and-structs-in-csharp#choose-a-record-when","Choose a Record When",[466,501],"Modeling immutable dataWorking with domain modelsNeed value-based equalityWant built-in formatting and deconstructionInheritance is required public record Person(\n string FirstName,\n string LastName,\n DateOnly DateOfBirth)\n{\n public int Age =>\n DateOnly.FromDateTime(DateTime.Now).Year - DateOfBirth.Year;\n}",{"id":514,"title":79,"titles":515,"content":516,"level":25},"/blog/record-and-structs-in-csharp#best-practices",[466],"Struct Best Practices* Keep them small and focused\nConsider making them readonlyImplement IEquatable\u003CT> for better performanceAvoid reference type fieldsRecord Best Practices* Use init-only properties for immutability\nLeverage with-expressions for modificationsConsider using records for DTOsUse positional syntax for simple cases",{"id":518,"title":141,"titles":519,"content":520,"level":25},"/blog/record-and-structs-in-csharp#conclusion",[466],"Both structs and records serve important purposes in C# development: Use structs when you need lightweight, value-type semantics and performance is crucialUse records when you want immutable objects with value-based equality and rich built-in functionality The choice between them should be based on your specific requirements around immutability, equality comparison, and performance needs. Remember that premature optimization is the root of all evil - choose the type that makes your code most maintainable and clear first, then optimize if needed. Happy coding! ๐ html pre.shiki code .sOJWj, html code.shiki .sOJWj{--shiki-default:#AB5959;--shiki-dark:#CB7676}html pre.shiki code .stDYs, html code.shiki .stDYs{--shiki-default:#2E8F82;--shiki-dark:#5DA994}html pre.shiki code .sVgvp, html code.shiki .sVgvp{--shiki-default:#999999;--shiki-dark:#666666}html pre.shiki code .s0iuz, html code.shiki .s0iuz{--shiki-default:#1E754F;--shiki-dark:#4D9375}html pre.shiki code .sOmcl, html code.shiki .sOmcl{--shiki-default:#59873A;--shiki-dark:#80A665}html pre.shiki code .sVIT7, html code.shiki .sVIT7{--shiki-default:#B07D48;--shiki-dark:#BD976A}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .su6et, html code.shiki .su6et{--shiki-default:#A0ADA0;--shiki-dark:#758575DD}",{"id":522,"title":523,"titles":524,"content":525,"level":19},"/blog/usefetch-and-navigation-blocking","The Nuxt 3 useFetch Navigation Conundrum: A Deep Dive",[],"Understanding Nuxt 3's useFetch and Navigation Blocking Issues",{"id":527,"title":523,"titles":528,"content":529,"level":25},"/blog/usefetch-and-navigation-blocking#the-nuxt-3-usefetch-navigation-conundrum-a-deep-dive",[523],"I recently ran into an interesting challenge while working with Nuxt 3's useFetch composable. The issue manifested as sluggish page transitions and blocked navigation - something that was particularly noticeable on slower connections. After digging deep and even getting insight from Daniel Roe (Nuxt's lead maintainer), I wanted to share my findings and solution.",{"id":531,"title":532,"titles":533,"content":534,"level":25},"/blog/usefetch-and-navigation-blocking#the-initial-problem","The Initial Problem",[523],"At first, my code looked something like this: \u003Cscript setup>\nconst { data: posts } = await useFetch('/api/posts')\n\u003C/script>\n\n\u003Ctemplate>\n \u003Cdiv class=\"posts-container\">\n \u003Ch1>Latest Posts\u003C/h1>\n \u003Cdiv v-for=\"post in posts\" :key=\"post.id\" class=\"post-item\">\n {{ post.title }}\n \u003C/div>\n \u003C/div>\n\u003C/template> Seems innocent enough, right? But this pattern was causing several issues: Navigation would stall until the data fetch completedUsers had no visual feedback during the loading processThe page would appear frozen during data fetching",{"id":536,"title":537,"titles":538,"content":539,"level":25},"/blog/usefetch-and-navigation-blocking#the-root-cause","The Root Cause",[523],"The core issue was the await keyword before useFetch. As Daniel Roe himself pointed out: \"Unless you're statically generating your Nuxt site, then I would suggest not awaiting it - and instead handle displaying the loading state. I'd always prefer quicker feedback to the user, even if it means more work to handle the loading state.\"",{"id":541,"title":334,"titles":542,"content":543,"level":25},"/blog/usefetch-and-navigation-blocking#the-solution",[523],"Here's how I refactored the code to solve these issues: \u003Cscript setup>\nconst { pending, data: posts, error } = useFetch('/api/posts')\n\u003C/script>\n\n\u003Ctemplate>\n \u003Cdiv class=\"posts-container\">\n \u003Ch1>Latest Posts\u003C/h1>\n \n \u003C!-- Loading State -->\n \u003Cdiv v-if=\"pending\" class=\"loading-state\">\n \u003CLoadingSpinner />\n \u003C/div>\n \n \u003C!-- Error State -->\n \u003Cdiv v-else-if=\"error\" class=\"error-state\">\n \u003Cp>Failed to load posts: {{ error.message }}\u003C/p>\n \u003Cbutton @click=\"refresh\">Retry\u003C/button>\n \u003C/div>\n \n \u003C!-- Success State -->\n \u003Cdiv v-else class=\"posts-grid\">\n \u003Cdiv v-for=\"post in posts\" :key=\"post.id\" class=\"post-item\">\n {{ post.title }}\n \u003C/div>\n \u003C/div>\n \u003C/div>\n\u003C/template>",{"id":545,"title":546,"titles":547,"content":548,"level":25},"/blog/usefetch-and-navigation-blocking#handling-ssr-considerations","Handling SSR Considerations",[523],"When working with SSR, we need to be extra careful about how we handle data fetching. Here's a pattern I've found to work well: \u003Cscript setup>\nconst { data, pending, error } = useFetch('/api/posts', {\n // Unique key for caching\n key: 'posts-list',\n \n // Default value to prevent undefined errors\n default: () => [],\n \n // Transform the data if needed\n transform: (response) => {\n return response.posts.map(post => ({\n ...post,\n createdAt: new Date(post.createdAt)\n }))\n },\n \n // Handle errors gracefully\n onResponseError({ response }) {\n console.error('Failed to fetch posts:', response._data)\n }\n})\n\u003C/script>",{"id":550,"title":551,"titles":552,"content":553,"level":25},"/blog/usefetch-and-navigation-blocking#special-case-static-site-generation","Special Case: Static Site Generation",[523],"The one exception to the \"don't await\" rule is when you're doing static site generation. In this case, you actually want to wait for the data: \u003Cscript setup>\nconst { data } = import.meta.env.SSG \n ? await useFetch('/api/posts')\n : useFetch('/api/posts')\n\u003C/script>",{"id":555,"title":556,"titles":557,"content":558,"level":25},"/blog/usefetch-and-navigation-blocking#creating-a-reusable-composable","Creating a Reusable Composable",[523],"For better code organization, I extracted this logic into a composable: export const usePostsData = () => {\n const config = useRuntimeConfig()\n \n const { data, pending, error, refresh } = useFetch(`${config.apiBase}/posts`, {\n key: 'posts',\n default: () => [],\n onResponseError({ response }) {\n const error = new Error(response._data.message || 'Failed to fetch posts')\n showError({ statusCode: response.status, message: error.message })\n }\n })\n\n return {\n posts: data,\n isLoading: pending,\n error,\n refresh\n }\n}",{"id":560,"title":561,"titles":562,"content":563,"level":25},"/blog/usefetch-and-navigation-blocking#key-takeaways","Key Takeaways",[523],"Avoid awaiting useFetch unless you're doing static site generationAlways handle loading states to provide feedback to usersImplement proper error handlingConsider using a composable for reusable data fetching logicRemember that faster feedback (even if loading) is better than a blocked UI",{"id":565,"title":566,"titles":567,"content":568,"level":25},"/blog/usefetch-and-navigation-blocking#why-this-matters","Why This Matters",[523],"By removing the await and properly handling loading states, we've achieved: Faster perceived performanceBetter user feedbackSmoother page transitionsMore resilient error handlingImproved SSR compatibility Remember, the goal isn't just to fetch data efficiently - it's to create a smooth, responsive user experience. Sometimes that means embracing asynchronous patterns and doing a bit more work to handle loading states properly.",{"id":570,"title":141,"titles":571,"content":572,"level":25},"/blog/usefetch-and-navigation-blocking#conclusion",[523],"Daniel Roe's advice about not awaiting useFetch highlights an important principle in modern web development: prioritize user experience and perceived performance. While it might require a bit more code to handle loading states and errors properly, the end result is a much more polished and responsive application. By following these patterns, you'll create Nuxt 3 applications that not only work well but feel well-crafted and professional. Your users might not notice the technical details, but they'll definitely appreciate the smooth, responsive experience. html pre.shiki code .sVgvp, html code.shiki .sVgvp{--shiki-default:#999999;--shiki-dark:#666666}html pre.shiki code .s0iuz, html code.shiki .s0iuz{--shiki-default:#1E754F;--shiki-dark:#4D9375}html pre.shiki code .sVIT7, html code.shiki .sVIT7{--shiki-default:#B07D48;--shiki-dark:#BD976A}html pre.shiki code .sOJWj, html code.shiki .sOJWj{--shiki-default:#AB5959;--shiki-dark:#CB7676}html pre.shiki code .sOmcl, html code.shiki .sOmcl{--shiki-default:#59873A;--shiki-dark:#80A665}html pre.shiki code .sggpr, html code.shiki .sggpr{--shiki-default:#B5695977;--shiki-dark:#C98A7D77}html pre.shiki code .sl0f5, html code.shiki .sl0f5{--shiki-default:#B56959;--shiki-dark:#C98A7D}html pre.shiki code .syipR, html code.shiki .syipR{--shiki-default:#393A34;--shiki-dark:#DBD7CAEE}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .su6et, html code.shiki .su6et{--shiki-default:#A0ADA0;--shiki-dark:#758575DD}html pre.shiki code .s26OC, html code.shiki .s26OC{--shiki-default:#998418;--shiki-dark:#B8A965}",["Reactive",574],{"$scolor-mode":575,"$ssite-config":579},{"preference":576,"value":576,"unknown":577,"forced":578},"system",true,false,{"env":580,"name":581,"url":582},"production","Teshane Crawford","https://teshanecrawford.com",["Set"],["ShallowReactive",585],{"search":-1},"/blogs"]