[{"slug":"how-to-run-typescript-scripts-in-your-next-js-project","highlight":"If you've ever tried to add Typescript script to one of your Node.js projects to run it on its own from the command line, it's very likely you came across one of these messages:\n\nError [ERR_REQUIRE_ESM]: Must use import to load ES Module:\nWarning: To load an ES module, set \"type\": \"module\" in the package.json or use the .mjs extension.\n\nA quick search on Google doesn't help much. The solutions range from trying a variety of different tsconfig.json configurations and even adding \"type\": \"module\" to your ","content":"If you've ever tried to add Typescript script to one of your Node.js projects to run it on its own from the command line, it's very likely you came across one of these messages:\n\n- `Error [ERR_REQUIRE_ESM]: Must use import to load ES Module:`\n- `Warning: To load an ES module, set \"type\": \"module\" in the package.json or use the .mjs extension.`\n\nA quick search on Google doesn't help much. The solutions range from trying a variety of different `tsconfig.json` configurations and even adding `\"type\": \"module\"` to your `package.json` file (which would stop Next.js and any other setup from working entirely).\n\n## Running a Typescript script with TSX\n\nI managed to find [`tsx`](https://www.npmjs.com/package/tsx) after a lot of useless Googling and testing Stackoverflow answers that simply didn't help. All I had to do was replace my script in my `package.json`:\n\n```json\n\"cache\": \"ts-node lib/file.ts\"\n```\n\nWith TSX:\n\n```json\n\"cache\": \"tsx lib/file.ts\"\n```\n\nAnd that was it! No weird errors, no need to configure a separate `tsconfig.json` file. Just plug and play!\n\n<Notice>\n\nI'm 99% sure everything that `tsx` can do can be done in `ts-node`or similar Typescript runners (with the right config and setup). However the big upside of `tsx` is how no-config it is.\n\nIt's really as easy as install and run!\n\n</Notice>\n\n## Running a Typescript ESM script with TSX\n\nOne footnote: in certain cases your script might need to import a package that has been converted to ES modules. Unless that package also supports CommonJS it's likely you'll be met with an error like this:\n\n```js\n❯ yarn run cache\n\nError [ERR_PACKAGE_PATH_NOT_EXPORTED]: No \\\"exports\\\" main defined in <path to your package here>\n```\n\nIn these cases all you have to do is to change your file name from `file.ts` to `file.mts` and then change your command to:\n\n```json\n\"cache\": \"tsx lib/file.mts\"\n```\n\nThis will tell `tsx` to run the entire file as an ES module, solving your error!\n\n","data":{"title":"How to run Typescript scripts in your Next.js project","categories":[{"slug":"quick-tips","highlight":"","content":"","data":{"name":"Quick Tips","visible":true,"description":"Handy bite-sized articles on all things web-design and development.\n\nThey won’t take long to read, but these tips can take you a long way! More coming soon…"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},{"slug":"react","highlight":"","content":"","data":{"name":"React","visible":true,"description":"How to's and tutorials on our favorite Javascript library."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}}],"published":true,"author":{"slug":"leonardo-petrucci","highlight":"@creativiii\n","content":"\n[@creativiii](https://twitter.com/creativiii)\n","data":{"name":"Leonardo Petrucci","avatar":"/images/leonardo-petrucci.jpg"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    a: \"a\"\n  }, _provideComponents(), props.components);\n  return _jsx(_components.p, {\n    children: _jsx(_components.a, {\n      href: \"https://twitter.com/creativiii\",\n      children: \"@creativiii\"\n    })\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},"date":"2023-03-04T19:34","thumbnail":"images/ts-note-to-tsx.png"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    ul: \"ul\",\n    li: \"li\",\n    code: \"code\",\n    h2: \"h2\",\n    a: \"a\",\n    pre: \"pre\",\n    span: \"span\"\n  }, _provideComponents(), props.components), {Notice} = _components;\n  if (!Notice) _missingMdxReference(\"Notice\", true);\n  return _jsxs(_Fragment, {\n    children: [_jsx(_components.p, {\n      children: \"If you've ever tried to add Typescript script to one of your Node.js projects to run it on its own from the command line, it's very likely you came across one of these messages:\"\n    }), \"\\n\", _jsxs(_components.ul, {\n      children: [\"\\n\", _jsx(_components.li, {\n        children: _jsx(_components.code, {\n          children: \"Error [ERR_REQUIRE_ESM]: Must use import to load ES Module:\"\n        })\n      }), \"\\n\", _jsx(_components.li, {\n        children: _jsx(_components.code, {\n          children: \"Warning: To load an ES module, set \\\"type\\\": \\\"module\\\" in the package.json or use the .mjs extension.\"\n        })\n      }), \"\\n\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"A quick search on Google doesn't help much. The solutions range from trying a variety of different \", _jsx(_components.code, {\n        children: \"tsconfig.json\"\n      }), \" configurations and even adding \", _jsx(_components.code, {\n        children: \"\\\"type\\\": \\\"module\\\"\"\n      }), \" to your \", _jsx(_components.code, {\n        children: \"package.json\"\n      }), \" file (which would stop Next.js and any other setup from working entirely).\"]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Running a Typescript script with TSX\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"I managed to find \", _jsx(_components.a, {\n        href: \"https://www.npmjs.com/package/tsx\",\n        children: _jsx(_components.code, {\n          children: \"tsx\"\n        })\n      }), \" after a lot of useless Googling and testing Stackoverflow answers that simply didn't help. All I had to do was replace my script in my \", _jsx(_components.code, {\n        children: \"package.json\"\n      }), \":\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-json\",\n      children: _jsxs(_components.code, {\n        className: \"language-json\",\n        children: [_jsx(_components.span, {\n          className: \"token property\",\n          children: \"\\\"cache\\\"\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"ts-node lib/file.ts\\\"\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"With TSX:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-json\",\n      children: _jsxs(_components.code, {\n        className: \"language-json\",\n        children: [_jsx(_components.span, {\n          className: \"token property\",\n          children: \"\\\"cache\\\"\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"tsx lib/file.ts\\\"\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"And that was it! No weird errors, no need to configure a separate \", _jsx(_components.code, {\n        children: \"tsconfig.json\"\n      }), \" file. Just plug and play!\"]\n    }), \"\\n\", _jsxs(Notice, {\n      children: [_jsxs(_components.p, {\n        children: [\"I'm 99% sure everything that \", _jsx(_components.code, {\n          children: \"tsx\"\n        }), \" can do can be done in \", _jsx(_components.code, {\n          children: \"ts-node\"\n        }), \"or similar Typescript runners (with the right config and setup). However the big upside of \", _jsx(_components.code, {\n          children: \"tsx\"\n        }), \" is how no-config it is.\"]\n      }), _jsx(_components.p, {\n        children: \"It's really as easy as install and run!\"\n      })]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Running a Typescript ESM script with TSX\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"One footnote: in certain cases your script might need to import a package that has been converted to ES modules. Unless that package also supports CommonJS it's likely you'll be met with an error like this:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-js\",\n      children: _jsxs(_components.code, {\n        className: \"language-js\",\n        children: [\"❯ yarn run cache\\n\\n\", _jsx(_components.span, {\n          className: \"token known-class-name class-name\",\n          children: \"Error\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token constant\",\n          children: \"ERR_PACKAGE_PATH_NOT_EXPORTED\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token maybe-class-name\",\n          children: \"No\"\n        }), \" \\\\\\\"exports\\\\\\\" main defined \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"in\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"<\"\n        }), \"path to your \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"package\"\n        }), \" here\", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \">\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"In these cases all you have to do is to change your file name from \", _jsx(_components.code, {\n        children: \"file.ts\"\n      }), \" to \", _jsx(_components.code, {\n        children: \"file.mts\"\n      }), \" and then change your command to:\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-json\",\n      children: _jsxs(_components.code, {\n        className: \"language-json\",\n        children: [_jsx(_components.span, {\n          className: \"token property\",\n          children: \"\\\"cache\\\"\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"tsx lib/file.mts\\\"\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"This will tell \", _jsx(_components.code, {\n        children: \"tsx\"\n      }), \" to run the entire file as an ES module, solving your error!\"]\n    })]\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\nfunction _missingMdxReference(id, component) {\n  throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");\n}\n","frontmatter":{},"scope":{}}},{"slug":"the-gamification-of-supermarket-rewards-apps-a-fun-way-to-save-or-more-manipulation","highlight":"In 2022, gamification played an increasingly major role in supermarket rewards apps as financial savviness became more important than ever. Apps like ASDA Rewards and My Morrisons began outshining more traditional loyalty schemes by offering a more dynamic, user-driven experience. In short, they tapped into our human desire for fun.\nInstead of just tallying points, these apps hook us by gamifying and expanding the rewards process in increasingly clever (and even addictive) ways. But how?\nWhat is Gamification?\nGamification is when a process or system i","content":"In 2022, gamification played an increasingly major role in supermarket rewards apps as financial savviness became more important than ever. Apps like ASDA Rewards and My Morrisons began outshining more traditional loyalty schemes by offering **a more dynamic, user-driven experience**. In short, they tapped into our human desire for fun.\n\nInstead of just tallying points, these apps hook us by gamifying and expanding the rewards process in increasingly clever (and even addictive) ways. But how?\n\n## What is Gamification?\n\nGamification is when a process or system is modified to mimic the dopamine-driven experience of playing a game. This allows a designer to ensure engagement by **turning the mundane or difficult into something fun**. \n\n[Duolingo](https://ironeko.com/posts/duolingo-and-the-art-of-engagement), which uses rewards and checkpoints to make language learning addictive, is a great example.\n\n![](/images/frame-1.png \"Every aspect of Duolingo's UX is orchestrated to distance language learning from the idea of hard work and associate it with fun and ease\")\n\nThe app even has a “health” system, whereby the user loses hearts if they make a mistake. These hearts, cleverly reminiscent of classic videogames, work exceptionally well with Duolingo’s simple, child-friendly aesthetic.\n\nWhile it might be harder to spot gamification in supermarket apps, the technique has become a primary method of **keeping customers hooked between shopping trips**.\n\nASDA Rewards, one of the newest faces on the rewards app market, is a great example.\n\n## ASDA Rewards\n\n### Everyone's a winner, baby\n\nWhen you open ASDA Rewards between shops, you’re instantly hit with a congratulatory message about your “cashpot”. This **clever wording, synonymous with casinos and prize draws**, excites the user. \n\n![](/images/frame-2-1-.png \"Bold text hierarchy and colour in the ASDA Rewards app make for an eye-catching experience\")\n\nIs it manipulative? Yes kind of. As in reality, you haven’t really “won” anything - you’ve spent a lot of money and got a little bit of money in return. But thanks to **gamified language**, the illusion of success is there.\n\nASDA Rewards uses gamified language and gamified design hand in hand really well here, accompanying their popup with some fun and celebratory star imagery.\n\nThe homepage is adorned with even more stars, a further mention of your cashpot and a menu at the bottom with some **interesting icons**. What really stands out under close inspection is the icon for ‘Earn’. Rather than a star, a tick or a pound sign, ASDA uses a trophy, thus reinforcing the all important idea of “winning”.\n\nMoreover, the icon for ‘Spend’ resembles a ticket. The kind of ticket one might use at a casino in an amusement park...\n\n### Abundance-suggestive design\n\nIndeed, the idea of gambling is everywhere, implicitly woven into the visual langauge of the app. Like a casino, ASDA Rewards strives to create a sense of *abundance*. \n\nAs you scroll you're met with card after card, some packed into carousels and some with star-spangled checkpoints. **Everywhere you look there is some new way to earn.**\n\nRemember, gambling and gaming are very similar. Both rely on hooking the user with the fun of a tantalisingly intermittent dopamine rush. \n\n![](/images/frame-3-1-.png \"ASDA Rewards bombards the user with bars to fill and tasks to complete, a great example of gamification\")\n\n### Progress Bars\n\nAs gamified design hallmarks go, checkpoints and progress bars are pretty easy to spot. And ASDA wields these to full effect.\n\nIn the ‘Earn’ section of the app you’ll find tasks to complete in store. This can be as simple as spending a certain amount on a certain type of product like champagne or fruit and veg, or take the form of **a 3-step challenge of buying specific products** within a certain timeframe.\n\nTo make the most out of this functionality, the user must check the 'Earn' tab in their downtime. You can plan your weekly shop at home, for example, around these challenges while aiming to hit as many 'star products' as possible.\n\n### Challenging the user\n\nBy adding these extra steps and thus **complicating the shopping process**, ASDA Rewards gives the user the illusion of having significant agency over how much they can \"win\" in the battle between their desire to save and the shop's desire for profit. \n\nNot to mention that **tasks are fun**. This is why missions, checkpoints and fetch quests are so commonly used in videogames.\n\nUtilising gamified language, ASDA even calls their tasks ‘Missions’. And watching your green progress bar fill up as you complete them is pretty satisfying, even if the “prize” for completion is nothing more than a measly £1 for your cashpot.\n\n'Mission milestones' build on this concept. You get bigger and bigger prizes from these for completing certain missions consistently over time. This instills a feeling of having achieved something significant, even if all you've done is… go shopping.\n\n## My Morrisons\n\n### Festive Challenges\n\nThis Christmas, Morrisons’ slimline but competent rewards app utilised progress bars very cleverly indeed, challenging customers to spend £20 each week in the leadup to Christmas. In exchange, a \"free\" £8.\n\nLike mission milestones in a game, each week is marked as “completed” with a green tick. **Humans love completing things**, so seeing all those ticks in a row gives an all important sense of achievement and satisfaction.\n\n![](/images/frame-4.png \"Each week in the lead up to Christmas, the My Morrisons app tracks your spending and rewards consistency\")\n\nIt could be argued that **Christmas spending targets are problematic**. During a time of financial hardship, it seems a bit insidious to force £20 out of someone who’s spent £18 and doesn’t want to spend any more. Especially when all they're promised in return is less than a tenner weeks down the line. \n\nEither way, it's certainly clever.\n\nMy Morrisons has ‘clubs’ too, indicated by a little shield icon like that of Duolingo’s 'leagues'. Their 'Christmas Savers’ club is part of this but its benefits aren't clearly stated.\n\n### Basket Bonus\n\nMorrisons’ “basket bonus”, while underexplained in the app, is a great piece of gamification. Essentially, it promises that you ‘could unlock an offer’ when scanning the app at the till, **like a random drop in a videogame.**\n\n![ASDA Rewards' basket bonus and fun voucher creation functionality give the user more perceived control](/images/frame-5-yay.png \"Morrisons Morrisons' basket bonus and ASDA Rewards' voucher creation functionality encourage enthusiastic user engagement\")\n\nI have personally been blessed with a basket bonus once, and only once. However, I have to say it was genuinely exciting. It appeared out of the blue when I scanned my card, with a slider and a command to swipe right to unlock my mystery offer.\n\nMy special item was just £1 off my shop, but I felt like I was winning. I had gained and the supermarket had lost! Which in reality is not what happened, but it left me wanting more, which is what a successfully gamified rewards app does.\n\nI particularly like how **the slider gives a momentary feeling of agency**. Or more agency, at least, than one gets from clicking a button. Maximising user agency is an excellent tactic, also used in ASDA’s voucher creation feature which allows the user to decide when, and how much, to cash out.\n\n## Lidl Plus\n\n### A half-baked attempt\n\nLidl Plus is a much more paired down attempt at a dynamic loyalty experience. However, here at least, simpler doesn't mean better.\n\nThe app focuses mostly on regular coupons which are activated and used passively like Boots Club Card coupons. I have a feeling this functionality may be phased out as the years progress as it simply doesn’t have that addictive quality.\n\n![](/images/frame-5-yay-1-.png \"the Lidl Plus app has a paired down and less gamified aesthetic\")\n\nIn the Coupon Plus section, users are given ‘rewards’ for spending certain amounts, visualised as checkpoints on a progress bar. The checkpoints are decorated with undersized present icons and the page is starkly devoid of colour. I can't see myself wanting to interact with the app between shops.\n\nAll in all, **it lacks the gamified flair of ASDA Rewards or the bold typographic hierarchy of Morrisons More.**\n\n(Not to mention that users are urged to spend up to £250 a month to earn a gift as measly as a 10% discount. Ouch.)\n\nLidl Plus has one pretty cool gamified feature up its sleeve, however.\n\n### Dailies\n\nThis Christmas, Lidl created an advent calendar with mystery daily surprises. And this is where the app’s gamification really shines.\n\nUpon opening the app, you’re prompted to ‘tap for today’s treat’ as a cursor icon hovers over an illustration of a present. **The hand cursor as a nod to PC gaming** is a fun touch. An animation shows the present opening and your ‘festive surprise’ appears... (20% off a cake, for example). \n\n![](/images/frame-5-yay-final.png \"Lidl Plus and Mario Kart Tour both utilise daily challenges to ensure consistent engagement\")\n\nAgain, the prizes aren’t much to write home about but their importance is glorified by the interactive, gamified design and word choice. \n\nSeeing your prizes visualised in a progressive grid mimics the experience of “dailies”. In mobile gaming, these are daily challenges with specific rewards.\n\nMario Kart Tour’s daily challenges are a good example of this. **The more consecutive days you interact on, the more rewards you get.** By using the same technique, Lidl Plus encourages users to keep interacting with their app even when they’re not visiting in store or actively purchasing anything.\n\n## Is ASDA Rewards the start of something bigger?\n\nAs the rewards app gamification trend continues, many more brands are likely to follow suit if they want to keep up.\n\nBoots Club Card has historically provided one of the best - if not *the* best - points systems in retail, but they’re stuck on a coupon activation system which doesn’t encourage user interaction in any fun or meaningful way.\n\nWould it be off-brand for Boots to encourage users to start opening their app every day to complete challenges, or follow progress bars? Maybe. But what's for sure is that modern consumers demand a richer experience than one akin to scanning a card at a till.\n\nAnd with mobile phones now an inextricable part of life, techniques born from mobile gaming or social media are naturally successful in ensuring user engagement. \n\nThe age of rewards cards is coming to an end, and the age of **interactive rewards *experiences***is well and truly here - even if that means more room for user manipulation.\n","data":{"layout":"blog","title":"Gamification, Gambling and Groceries: how ASDA Rewards makes spending fun","categories":[{"slug":"design","highlight":"","content":"","data":{"name":"Design","visible":true,"description":"Delving into the world of design, with an emphasis on website and app design (two of our favourite things)."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}}],"author":{"slug":"evie-dillon-riley","highlight":"Writer, editor &amp; translator (IT-ENG)\n","content":"\nWriter, editor & translator (IT-ENG)\n","data":{"name":"Evie Dillon-Riley","avatar":"/images/image-6.jpg"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\"\n  }, _provideComponents(), props.components);\n  return _jsx(_components.p, {\n    children: \"Writer, editor & translator (IT-ENG)\"\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},"date":"2022-12-16T12:07:03.111Z","thumbnail":"/images/peepoo.png","description":"With the success of ASDA Rewards, the age of traditional loyalty cards is coming to an end, and the age of interactive rewards experiences is well and truly here.","yoast_keyword":"ASDA Rewards","published":true},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    strong: \"strong\",\n    h2: \"h2\",\n    a: \"a\",\n    img: \"img\",\n    h3: \"h3\",\n    em: \"em\"\n  }, _provideComponents(), props.components);\n  return _jsxs(_Fragment, {\n    children: [_jsxs(_components.p, {\n      children: [\"In 2022, gamification played an increasingly major role in supermarket rewards apps as financial savviness became more important than ever. Apps like ASDA Rewards and My Morrisons began outshining more traditional loyalty schemes by offering \", _jsx(_components.strong, {\n        children: \"a more dynamic, user-driven experience\"\n      }), \". In short, they tapped into our human desire for fun.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Instead of just tallying points, these apps hook us by gamifying and expanding the rewards process in increasingly clever (and even addictive) ways. But how?\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"What is Gamification?\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Gamification is when a process or system is modified to mimic the dopamine-driven experience of playing a game. This allows a designer to ensure engagement by \", _jsx(_components.strong, {\n        children: \"turning the mundane or difficult into something fun\"\n      }), \".\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [_jsx(_components.a, {\n        href: \"https://ironeko.com/posts/duolingo-and-the-art-of-engagement\",\n        children: \"Duolingo\"\n      }), \", which uses rewards and checkpoints to make language learning addictive, is a great example.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-1.png\",\n        alt: \"\",\n        title: \"Every aspect of Duolingo's UX is orchestrated to distance language learning from the idea of hard work and associate it with fun and ease\",\n        width: \"770\",\n        height: \"764\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"The app even has a “health” system, whereby the user loses hearts if they make a mistake. These hearts, cleverly reminiscent of classic videogames, work exceptionally well with Duolingo’s simple, child-friendly aesthetic.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"While it might be harder to spot gamification in supermarket apps, the technique has become a primary method of \", _jsx(_components.strong, {\n        children: \"keeping customers hooked between shopping trips\"\n      }), \".\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"ASDA Rewards, one of the newest faces on the rewards app market, is a great example.\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"ASDA Rewards\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Everyone's a winner, baby\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"When you open ASDA Rewards between shops, you’re instantly hit with a congratulatory message about your “cashpot”. This \", _jsx(_components.strong, {\n        children: \"clever wording, synonymous with casinos and prize draws\"\n      }), \", excites the user.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-2-1-.png\",\n        alt: \"\",\n        title: \"Bold text hierarchy and colour in the ASDA Rewards app make for an eye-catching experience\",\n        width: \"874\",\n        height: \"764\"\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Is it manipulative? Yes kind of. As in reality, you haven’t really “won” anything - you’ve spent a lot of money and got a little bit of money in return. But thanks to \", _jsx(_components.strong, {\n        children: \"gamified language\"\n      }), \", the illusion of success is there.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"ASDA Rewards uses gamified language and gamified design hand in hand really well here, accompanying their popup with some fun and celebratory star imagery.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"The homepage is adorned with even more stars, a further mention of your cashpot and a menu at the bottom with some \", _jsx(_components.strong, {\n        children: \"interesting icons\"\n      }), \". What really stands out under close inspection is the icon for ‘Earn’. Rather than a star, a tick or a pound sign, ASDA uses a trophy, thus reinforcing the all important idea of “winning”.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Moreover, the icon for ‘Spend’ resembles a ticket. The kind of ticket one might use at a casino in an amusement park...\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Abundance-suggestive design\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Indeed, the idea of gambling is everywhere, implicitly woven into the visual langauge of the app. Like a casino, ASDA Rewards strives to create a sense of \", _jsx(_components.em, {\n        children: \"abundance\"\n      }), \".\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"As you scroll you're met with card after card, some packed into carousels and some with star-spangled checkpoints. \", _jsx(_components.strong, {\n        children: \"Everywhere you look there is some new way to earn.\"\n      })]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Remember, gambling and gaming are very similar. Both rely on hooking the user with the fun of a tantalisingly intermittent dopamine rush.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-3-1-.png\",\n        alt: \"\",\n        title: \"ASDA Rewards bombards the user with bars to fill and tasks to complete, a great example of gamification\",\n        width: \"793\",\n        height: \"764\"\n      })\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Progress Bars\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"As gamified design hallmarks go, checkpoints and progress bars are pretty easy to spot. And ASDA wields these to full effect.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"In the ‘Earn’ section of the app you’ll find tasks to complete in store. This can be as simple as spending a certain amount on a certain type of product like champagne or fruit and veg, or take the form of \", _jsx(_components.strong, {\n        children: \"a 3-step challenge of buying specific products\"\n      }), \" within a certain timeframe.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"To make the most out of this functionality, the user must check the 'Earn' tab in their downtime. You can plan your weekly shop at home, for example, around these challenges while aiming to hit as many 'star products' as possible.\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Challenging the user\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"By adding these extra steps and thus \", _jsx(_components.strong, {\n        children: \"complicating the shopping process\"\n      }), \", ASDA Rewards gives the user the illusion of having significant agency over how much they can \\\"win\\\" in the battle between their desire to save and the shop's desire for profit.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Not to mention that \", _jsx(_components.strong, {\n        children: \"tasks are fun\"\n      }), \". This is why missions, checkpoints and fetch quests are so commonly used in videogames.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Utilising gamified language, ASDA even calls their tasks ‘Missions’. And watching your green progress bar fill up as you complete them is pretty satisfying, even if the “prize” for completion is nothing more than a measly £1 for your cashpot.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"'Mission milestones' build on this concept. You get bigger and bigger prizes from these for completing certain missions consistently over time. This instills a feeling of having achieved something significant, even if all you've done is… go shopping.\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"My Morrisons\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Festive Challenges\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"This Christmas, Morrisons’ slimline but competent rewards app utilised progress bars very cleverly indeed, challenging customers to spend £20 each week in the leadup to Christmas. In exchange, a \\\"free\\\" £8.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Like mission milestones in a game, each week is marked as “completed” with a green tick. \", _jsx(_components.strong, {\n        children: \"Humans love completing things\"\n      }), \", so seeing all those ticks in a row gives an all important sense of achievement and satisfaction.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-4.png\",\n        alt: \"\",\n        title: \"Each week in the lead up to Christmas, the My Morrisons app tracks your spending and rewards consistency\",\n        width: \"761\",\n        height: \"764\"\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"It could be argued that \", _jsx(_components.strong, {\n        children: \"Christmas spending targets are problematic\"\n      }), \". During a time of financial hardship, it seems a bit insidious to force £20 out of someone who’s spent £18 and doesn’t want to spend any more. Especially when all they're promised in return is less than a tenner weeks down the line.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Either way, it's certainly clever.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"My Morrisons has ‘clubs’ too, indicated by a little shield icon like that of Duolingo’s 'leagues'. Their 'Christmas Savers’ club is part of this but its benefits aren't clearly stated.\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Basket Bonus\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Morrisons’ “basket bonus”, while underexplained in the app, is a great piece of gamification. Essentially, it promises that you ‘could unlock an offer’ when scanning the app at the till, \", _jsx(_components.strong, {\n        children: \"like a random drop in a videogame.\"\n      })]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-5-yay.png\",\n        alt: \"ASDA Rewards' basket bonus and fun voucher creation functionality give the user more perceived control\",\n        title: \"Morrisons Morrisons' basket bonus and ASDA Rewards' voucher creation functionality encourage enthusiastic user engagement\",\n        width: \"950\",\n        height: \"764\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"I have personally been blessed with a basket bonus once, and only once. However, I have to say it was genuinely exciting. It appeared out of the blue when I scanned my card, with a slider and a command to swipe right to unlock my mystery offer.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"My special item was just £1 off my shop, but I felt like I was winning. I had gained and the supermarket had lost! Which in reality is not what happened, but it left me wanting more, which is what a successfully gamified rewards app does.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"I particularly like how \", _jsx(_components.strong, {\n        children: \"the slider gives a momentary feeling of agency\"\n      }), \". Or more agency, at least, than one gets from clicking a button. Maximising user agency is an excellent tactic, also used in ASDA’s voucher creation feature which allows the user to decide when, and how much, to cash out.\"]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Lidl Plus\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"A half-baked attempt\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Lidl Plus is a much more paired down attempt at a dynamic loyalty experience. However, here at least, simpler doesn't mean better.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"The app focuses mostly on regular coupons which are activated and used passively like Boots Club Card coupons. I have a feeling this functionality may be phased out as the years progress as it simply doesn’t have that addictive quality.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-5-yay-1-.png\",\n        alt: \"\",\n        title: \"the Lidl Plus app has a paired down and less gamified aesthetic\",\n        width: \"950\",\n        height: \"764\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"In the Coupon Plus section, users are given ‘rewards’ for spending certain amounts, visualised as checkpoints on a progress bar. The checkpoints are decorated with undersized present icons and the page is starkly devoid of colour. I can't see myself wanting to interact with the app between shops.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"All in all, \", _jsx(_components.strong, {\n        children: \"it lacks the gamified flair of ASDA Rewards or the bold typographic hierarchy of Morrisons More.\"\n      })]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"(Not to mention that users are urged to spend up to £250 a month to earn a gift as measly as a 10% discount. Ouch.)\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Lidl Plus has one pretty cool gamified feature up its sleeve, however.\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Dailies\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"This Christmas, Lidl created an advent calendar with mystery daily surprises. And this is where the app’s gamification really shines.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Upon opening the app, you’re prompted to ‘tap for today’s treat’ as a cursor icon hovers over an illustration of a present. \", _jsx(_components.strong, {\n        children: \"The hand cursor as a nod to PC gaming\"\n      }), \" is a fun touch. An animation shows the present opening and your ‘festive surprise’ appears... (20% off a cake, for example).\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-5-yay-final.png\",\n        alt: \"\",\n        title: \"Lidl Plus and Mario Kart Tour both utilise daily challenges to ensure consistent engagement\",\n        width: \"950\",\n        height: \"764\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Again, the prizes aren’t much to write home about but their importance is glorified by the interactive, gamified design and word choice.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Seeing your prizes visualised in a progressive grid mimics the experience of “dailies”. In mobile gaming, these are daily challenges with specific rewards.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Mario Kart Tour’s daily challenges are a good example of this. \", _jsx(_components.strong, {\n        children: \"The more consecutive days you interact on, the more rewards you get.\"\n      }), \" By using the same technique, Lidl Plus encourages users to keep interacting with their app even when they’re not visiting in store or actively purchasing anything.\"]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Is ASDA Rewards the start of something bigger?\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"As the rewards app gamification trend continues, many more brands are likely to follow suit if they want to keep up.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Boots Club Card has historically provided one of the best - if not \", _jsx(_components.em, {\n        children: \"the\"\n      }), \" best - points systems in retail, but they’re stuck on a coupon activation system which doesn’t encourage user interaction in any fun or meaningful way.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Would it be off-brand for Boots to encourage users to start opening their app every day to complete challenges, or follow progress bars? Maybe. But what's for sure is that modern consumers demand a richer experience than one akin to scanning a card at a till.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"And with mobile phones now an inextricable part of life, techniques born from mobile gaming or social media are naturally successful in ensuring user engagement.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"The age of rewards cards is coming to an end, and the age of \", _jsxs(_components.strong, {\n        children: [\"interactive rewards \", _jsx(_components.em, {\n          children: \"experiences\"\n        })]\n      }), \"is well and truly here - even if that means more room for user manipulation.\"]\n    })]\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},{"slug":"the-dos-and-donts-of-skeleton-loading-in-react","highlight":"Skeleton Loading is the practice of displaying a mockup of a a part of your interface while data that is supposed to fill that interface is loaded. In theory this is no different than showing the user a spinning icon or telling them that you're loading something, but there is research that suggests skeleton loading tricks users into thinking your app loads faster than it does.\n\nBeyond that, it's an excellent way to avoid parts of your","content":"Skeleton Loading is the practice of displaying a mockup of a a part of your interface while data that is supposed to fill that interface is loaded. In theory this is no different than showing the user a spinning icon or telling them that you're loading something, but there is research that suggests **skeleton loading tricks users into thinking your app loads faster than it does**.\n\n![Hero image with the text \"The Do's and Don'ts of skeleton loading in react\"](/images/frame-142.png)\n\nBeyond that, it's an excellent way to avoid parts of your interface shifting as data loads in and overall makes an interface look and feel more polished.\n\n## How to implement Skeleton Loading in React\n\nIf you're looking to implement Skeleton Loading in React, I'd recommend using an **external dependency**. Depending on the behaviour you want it might get quite complex so you'll probably not want to handle that complexity yourself.\n\nThat said, there are two specific packages I recommend if you need to develop a Skeleton Loading functionality:\n\n* **[Skeleton React](https://skeletonreact.com)**, which uses an interesting approach which consists of re-creating your skeleton with SVGs.\n* **[React Loading Skeleton](https://www.npmjs.com/package/react-loading-skeleton)**, which simply displays a skeleton of X and Y size as a DOM element.\n\nThe way I like to use Skeletons is to have a Skeleton version of each component I'm planning to display once the data has been loaded. So for example, if I have a page that allows me to search for articles I would most likely have:\n\n* A skeleton for article cards\n* A skeleton for the search bar\n* A skeleton for all the different categories the user can filter between\n\nThese would be replaced by both their non-skeleton components the first time my data loads. You could also have a single skeleton for all the components above, but in my personal experience breaking each down to its most basic components allows for more reusability and less work.\n\n<Notice>\n\n\n\n\n\n\n\nIf you had to load more articles on another page formatted differently from this search page, you'd be able to reuse the skeleton component for just the articles rather than having to re-create a skeleton specifically for that page!\n\n\n\n\n\n\n\n</Notice>\n\n<iframe src=\"https://codesandbox.io/embed/with-react-loading-skeleton-forked-3nmph4?codemirror=1&fontsize=14&hidenavigation=1&theme=dark&view=preview\"\n     title=\"with react loading skeleton (forked)\"\n     allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n     sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n   ></iframe>\n\nThe example above uses the same components I use for this blog and allows you to trigger between the two different packages I mentioned above.\n\n## Differences between the skeleton packages and how to use them\n\nThe example uses both `react-content-loader` as well as `react-loading-skeleton`. If you switch between them you'll notice that there's not a huge difference between them visually. However, they are created in very different ways.\n\n### React Loading Skeleton\n\nThis is probably my favourite out of the two, mostly due to its **ease of implementation**. Since the package simply exports a DOM element we can just copy our existing markup (styles and all) and simply replace its text with a skeleton!\n\nAside from that, it's also quite easy to change its styles so you'll most likely be able to make it look any way you want without much hassle.\n\n<List type=\"tick\">\n\n\n\n\n* Quick and easy to create skeletons\n* Easy to style and customise\n* Responsive by design\n\n\n\n\n</List>\n\n<List type=\"cross\">\n\n\n\n\n* Probably not great for accessibility since it will be interpreted as a DOM element\n* Lots of code duplication to match the component's styles\n\n\n\n\n</List>\n\n### React Content Loader\n\nReact Content Loader is definitely a bit more complicated to use than its DOM counterpart, but it does have its advantages. My main complaint about this package is that creating a skeleton is difficult. You're unlikely to know how to position SVG elements without a visual aid so you won't be able to create a skeleton just with code.\n\nMy preferred way around that is to take a screenshot of whatever I want to transform into a skeleton, open it in Figma and replace the elements I want to make into skeletons:\n\n![](/images/screenshot-2022-10-07-at-15.54.05.png)\n\nEach red element is an SVG rectangle. You can then:\n\n1. Select the frame containing your rectangles\n2. Go to \"Export\" in the right sidebar\n3. Select \"SVG\" and then export\n\nThis will download an SVG file which once dragged into any code editor will reveal the SVG you need for your skeleton component! For example, the above ended up being:\n\n```svg\n<svg width=\"388\" height=\"504\" viewBox=\"0 0 388 504\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n  <rect width=\"388\" height=\"504\" fill=\"white\"/>\n  <rect x=\"13\" y=\"10\" width=\"364\" height=\"191\" fill=\"#D9D9D9\"/>\n  <circle cx=\"43.5\" cy=\"216.5\" r=\"30.5\" fill=\"#D9D9D9\"/>\n  <rect x=\"13\" y=\"340\" width=\"357\" height=\"14\" fill=\"#D9D9D9\"/>\n  <rect x=\"13\" y=\"360\" width=\"234\" height=\"14\" fill=\"#D9D9D9\"/>\n  <rect x=\"13\" y=\"380\" width=\"298\" height=\"14\" fill=\"#D9D9D9\"/>\n  <rect x=\"13\" y=\"400\" width=\"168\" height=\"14\" fill=\"#D9D9D9\"/>\n  <rect x=\"127\" y=\"471\" width=\"134\" height=\"14\" fill=\"#D9D9D9\"/>\n  <rect x=\"83\" y=\"233\" width=\"134\" height=\"14\" fill=\"#D9D9D9\"/>\n  <rect x=\"83\" y=\"213\" width=\"184\" height=\"14\" fill=\"#D9D9D9\"/>\n  <rect x=\"16\" y=\"264\" width=\"316\" height=\"30\" fill=\"#D9D9D9\"/>\n  <rect x=\"16\" y=\"298\" width=\"253\" height=\"30\" fill=\"#D9D9D9\"/>\n</svg>\n```\n\nWe can then clean it up a bit (remove fills, borders, add some corner radius) and place it in `react-content-loader`'s component:\n\n```tsx\n  <ContentLoader\n    speed={2}\n    // We want our component to be vaguely responsive\n    width=\"100%\"\n    // unfortunately the height needs to be hardcoded\n    height={500}\n    backgroundColor=\"#f3f3f3\"\n    foregroundColor=\"#ecebeb\"\n  >\n    <rect x=\"13\" y=\"10\" width=\"364\" height=\"191\" rx=\"3\" />\n    <circle cx=\"43.5\" cy=\"216.5\" r=\"30.5\" rx=\"3\" />\n    <rect x=\"13\" y=\"340\" width=\"357\" height=\"14\" rx=\"3\" />\n    <rect x=\"13\" y=\"360\" width=\"234\" height=\"14\" rx=\"3\" />\n    <rect x=\"13\" y=\"380\" width=\"298\" height=\"14\" rx=\"3\" />\n    <rect x=\"13\" y=\"400\" width=\"168\" height=\"14\" rx=\"3\" />\n    <rect x=\"127\" y=\"471\" width=\"134\" height=\"14\" rx=\"3\" />\n    <rect x=\"83\" y=\"233\" width=\"134\" height=\"14\" rx=\"3\" />\n    <rect x=\"83\" y=\"213\" width=\"184\" height=\"14\" rx=\"3\" />\n    <rect x=\"13\" y=\"264\" width=\"316\" height=\"30\" rx=\"3\" />\n    <rect x=\"13\" y=\"298\" width=\"253\" height=\"30\" rx=\"3\" />\n  </ContentLoader>\n```\n\nIt's likely you'll have to change your height/width depending on the situation, but that's pretty much all you need.\n\n<List type=\"tick\">\n\n\n\n\n* Essentially just displays an image, which is great for accessibility\n* Code is clean and short\n\n\n\n\n</List>\n\n<List type=\"cross\">\n\n\n\n* Difficult to write without visual aid\n\n\n\n</List>\n\n## Tips on creating your skeleton components\n\nHere are a couple of things I highly recommend you do when writing your skeleton components in React. They'll make the whole thing much easier to manage.\n\n### Keep your skeletons with your components\n\nOne of my favorite ways of keeping my code organised is to keep each component's skeleton in the same file as its main component and then export it using **dot-notation**.\n\n```jsx\n// inside components/mycomponent.tsx\n\nimport SkeletonPrimitive from \"react-loading-skeleton\";\n\nconst Component = () => {\n  return <></>\n}\n\nconst Skeleton = () => {\n  return <SkeletonPrimitive />\n}\n\nComponent.Skeleton = Skeleton;\n\nexport Component;\n\n// in another file\n\nimport { Component } from 'components/mycomponent';\n\nconst MyPage = ({ isLoading }) => {\n  return (\n    <>\n      {\n        isLoading ? <Component.Skeleton /> : <Component />\n      }\n    </>\n  ) \n}\n```\n\n### Keep sizes consistent\n\nSince loading skeletons largely work to replace missing text it's very important to **make sure different levels of typography are consistently replaced throughout your skeletons.** For example, if your body text is always the same size and always has the same line height, so should any skeleton that replaces body text.\n\n### Not everything needs to be put into your skeleton\n\nIt's easy to just replace all the elements in a div with skeletons and call it a day, but sometimes **keeping it simple** will actually make it look far more professional.\n\n![an image showing the different between the real skeleton and a modified version of it without the picture element](/images/screenshot-2022-10-10-at-20.04.32.png \"The skeleton on the right looks much cleaner without overlapping elements.\")\n\nFor example, the skeleton from the example above is missing the author's photo which would've been overlaid over the skeleton of the article's thumbnail. In general I think having skeletons crossing over each other doesn't look great so I decided not to include the author's picture at all.\n\n### Make it look good!\n\nLet's be honest, the main reason you're wanting to implement skeleton loading in React is to make your app look more professional or make it seem faster. So the best tip I can give is to just **keep trying** until it looks good!\n\nBoth `react-spring` and `framer-motion` are great options to animate the transition between your skeleton and your actual component to give it that extra polished touch.\n","data":{"layout":"blog","title":"The do's and dont's of Skeleton Loading in React","categories":[{"slug":"ui","highlight":"","content":"","data":{"name":"UI","visible":false,"description":"A﻿ section for components, interfaces and thoughts about building user interfaces."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},{"slug":"react","highlight":"","content":"","data":{"name":"React","visible":true,"description":"How to's and tutorials on our favorite Javascript library."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}}],"author":{"slug":"leonardo-petrucci","highlight":"@creativiii\n","content":"\n[@creativiii](https://twitter.com/creativiii)\n","data":{"name":"Leonardo Petrucci","avatar":"/images/leonardo-petrucci.jpg"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    a: \"a\"\n  }, _provideComponents(), props.components);\n  return _jsx(_components.p, {\n    children: _jsx(_components.a, {\n      href: \"https://twitter.com/creativiii\",\n      children: \"@creativiii\"\n    })\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},"date":"2022-10-13T15:07:02.026Z","thumbnail":"/images/frame-142.png","description":"Skeleton components in React are an extremely common pattern, however there seem to be very few tips on how to implement them in a real world scenario.","yoast_keyword":"Skeleton Loading in React","published":true},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    strong: \"strong\",\n    img: \"img\",\n    h2: \"h2\",\n    ul: \"ul\",\n    li: \"li\",\n    a: \"a\",\n    code: \"code\",\n    h3: \"h3\",\n    ol: \"ol\",\n    pre: \"pre\",\n    span: \"span\"\n  }, _provideComponents(), props.components), {Notice, List} = _components;\n  if (!List) _missingMdxReference(\"List\", true);\n  if (!Notice) _missingMdxReference(\"Notice\", true);\n  return _jsxs(_Fragment, {\n    children: [_jsxs(_components.p, {\n      children: [\"Skeleton Loading is the practice of displaying a mockup of a a part of your interface while data that is supposed to fill that interface is loaded. In theory this is no different than showing the user a spinning icon or telling them that you're loading something, but there is research that suggests \", _jsx(_components.strong, {\n        children: \"skeleton loading tricks users into thinking your app loads faster than it does\"\n      }), \".\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-142.png\",\n        alt: \"Hero image with the text \\\"The Do's and Don'ts of skeleton loading in react\\\"\",\n        width: \"1200\",\n        height: \"630\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Beyond that, it's an excellent way to avoid parts of your interface shifting as data loads in and overall makes an interface look and feel more polished.\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"How to implement Skeleton Loading in React\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"If you're looking to implement Skeleton Loading in React, I'd recommend using an \", _jsx(_components.strong, {\n        children: \"external dependency\"\n      }), \". Depending on the behaviour you want it might get quite complex so you'll probably not want to handle that complexity yourself.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"That said, there are two specific packages I recommend if you need to develop a Skeleton Loading functionality:\"\n    }), \"\\n\", _jsxs(_components.ul, {\n      children: [\"\\n\", _jsxs(_components.li, {\n        children: [_jsx(_components.strong, {\n          children: _jsx(_components.a, {\n            href: \"https://skeletonreact.com\",\n            children: \"Skeleton React\"\n          })\n        }), \", which uses an interesting approach which consists of re-creating your skeleton with SVGs.\"]\n      }), \"\\n\", _jsxs(_components.li, {\n        children: [_jsx(_components.strong, {\n          children: _jsx(_components.a, {\n            href: \"https://www.npmjs.com/package/react-loading-skeleton\",\n            children: \"React Loading Skeleton\"\n          })\n        }), \", which simply displays a skeleton of X and Y size as a DOM element.\"]\n      }), \"\\n\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"The way I like to use Skeletons is to have a Skeleton version of each component I'm planning to display once the data has been loaded. So for example, if I have a page that allows me to search for articles I would most likely have:\"\n    }), \"\\n\", _jsxs(_components.ul, {\n      children: [\"\\n\", _jsx(_components.li, {\n        children: \"A skeleton for article cards\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"A skeleton for the search bar\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"A skeleton for all the different categories the user can filter between\"\n      }), \"\\n\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"These would be replaced by both their non-skeleton components the first time my data loads. You could also have a single skeleton for all the components above, but in my personal experience breaking each down to its most basic components allows for more reusability and less work.\"\n    }), \"\\n\", _jsx(Notice, {\n      children: _jsx(_components.p, {\n        children: \"If you had to load more articles on another page formatted differently from this search page, you'd be able to reuse the skeleton component for just the articles rather than having to re-create a skeleton specifically for that page!\"\n      })\n    }), \"\\n\", _jsx(\"iframe\", {\n      src: \"https://codesandbox.io/embed/with-react-loading-skeleton-forked-3nmph4?codemirror=1&fontsize=14&hidenavigation=1&theme=dark&view=preview\",\n      title: \"with react loading skeleton (forked)\",\n      allow: \"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\",\n      sandbox: \"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"The example above uses the same components I use for this blog and allows you to trigger between the two different packages I mentioned above.\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Differences between the skeleton packages and how to use them\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"The example uses both \", _jsx(_components.code, {\n        children: \"react-content-loader\"\n      }), \" as well as \", _jsx(_components.code, {\n        children: \"react-loading-skeleton\"\n      }), \". If you switch between them you'll notice that there's not a huge difference between them visually. However, they are created in very different ways.\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"React Loading Skeleton\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"This is probably my favourite out of the two, mostly due to its \", _jsx(_components.strong, {\n        children: \"ease of implementation\"\n      }), \". Since the package simply exports a DOM element we can just copy our existing markup (styles and all) and simply replace its text with a skeleton!\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Aside from that, it's also quite easy to change its styles so you'll most likely be able to make it look any way you want without much hassle.\"\n    }), \"\\n\", _jsx(List, {\n      type: \"tick\",\n      children: _jsxs(_components.ul, {\n        children: [\"\\n\", _jsx(_components.li, {\n          children: \"Quick and easy to create skeletons\"\n        }), \"\\n\", _jsx(_components.li, {\n          children: \"Easy to style and customise\"\n        }), \"\\n\", _jsx(_components.li, {\n          children: \"Responsive by design\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(List, {\n      type: \"cross\",\n      children: _jsxs(_components.ul, {\n        children: [\"\\n\", _jsx(_components.li, {\n          children: \"Probably not great for accessibility since it will be interpreted as a DOM element\"\n        }), \"\\n\", _jsx(_components.li, {\n          children: \"Lots of code duplication to match the component's styles\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"React Content Loader\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"React Content Loader is definitely a bit more complicated to use than its DOM counterpart, but it does have its advantages. My main complaint about this package is that creating a skeleton is difficult. You're unlikely to know how to position SVG elements without a visual aid so you won't be able to create a skeleton just with code.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"My preferred way around that is to take a screenshot of whatever I want to transform into a skeleton, open it in Figma and replace the elements I want to make into skeletons:\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/screenshot-2022-10-07-at-15.54.05.png\",\n        alt: \"\",\n        width: \"1740\",\n        height: \"1206\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Each red element is an SVG rectangle. You can then:\"\n    }), \"\\n\", _jsxs(_components.ol, {\n      children: [\"\\n\", _jsx(_components.li, {\n        children: \"Select the frame containing your rectangles\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Go to \\\"Export\\\" in the right sidebar\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Select \\\"SVG\\\" and then export\"\n      }), \"\\n\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"This will download an SVG file which once dragged into any code editor will reveal the SVG you need for your skeleton component! For example, the above ended up being:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-svg\",\n      children: _jsxs(_components.code, {\n        className: \"language-svg\",\n        children: [_jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"svg\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"388\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"504\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"viewBox\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"0 0 388 504\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"none\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"xmlns\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"http://www.w3.org/2000/svg\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), \"\\n  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"388\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"504\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"white\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"13\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"10\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"364\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"191\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#D9D9D9\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"circle\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"cx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"43.5\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"cy\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"216.5\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"r\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"30.5\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#D9D9D9\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"13\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"340\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"357\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#D9D9D9\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"13\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"360\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"234\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#D9D9D9\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"13\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"380\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"298\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#D9D9D9\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"13\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"400\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"168\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#D9D9D9\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"127\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"471\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"134\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#D9D9D9\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"83\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"233\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"134\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#D9D9D9\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"83\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"213\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"184\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#D9D9D9\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"16\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"264\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"316\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"30\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#D9D9D9\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"16\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"298\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"253\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"30\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"fill\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#D9D9D9\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n\", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            }), \"svg\"]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"We can then clean it up a bit (remove fills, borders, add some corner radius) and place it in \", _jsx(_components.code, {\n        children: \"react-content-loader\"\n      }), \"'s component:\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-tsx\",\n      children: _jsxs(_components.code, {\n        className: \"language-tsx\",\n        children: [\"  \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"ContentLoader\"\n            })]\n          }), \"\\n    \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"speed\"\n          }), _jsxs(_components.span, {\n            className: \"token script language-javascript\",\n            children: [_jsx(_components.span, {\n              className: \"token script-punctuation punctuation\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"{\"\n            }), _jsx(_components.span, {\n              className: \"token number\",\n              children: \"2\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"}\"\n            })]\n          }), \"\\n    \", _jsx(_components.span, {\n            className: \"token comment\",\n            children: \"// We want our component to be vaguely responsive\"\n          }), \"\\n    \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"100%\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \"\\n    \", _jsx(_components.span, {\n            className: \"token comment\",\n            children: \"// unfortunately the height needs to be hardcoded\"\n          }), \"\\n    \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token script language-javascript\",\n            children: [_jsx(_components.span, {\n              className: \"token script-punctuation punctuation\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"{\"\n            }), _jsx(_components.span, {\n              className: \"token number\",\n              children: \"500\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"}\"\n            })]\n          }), \"\\n    \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"backgroundColor\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#f3f3f3\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \"\\n    \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"foregroundColor\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"#ecebeb\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \"\\n  \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"13\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"10\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"364\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"191\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"rx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"3\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"circle\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"cx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"43.5\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"cy\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"216.5\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"r\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"30.5\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"rx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"3\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"13\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"340\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"357\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"rx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"3\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"13\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"360\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"234\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"rx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"3\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"13\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"380\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"298\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"rx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"3\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"13\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"400\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"168\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"rx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"3\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"127\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"471\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"134\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"rx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"3\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"83\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"233\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"134\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"rx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"3\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"83\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"213\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"184\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"14\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"rx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"3\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"13\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"264\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"316\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"30\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"rx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"3\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"rect\"]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"x\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"13\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"y\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"298\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"width\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"253\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"height\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"30\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"rx\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"3\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n  \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"ContentLoader\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"It's likely you'll have to change your height/width depending on the situation, but that's pretty much all you need.\"\n    }), \"\\n\", _jsx(List, {\n      type: \"tick\",\n      children: _jsxs(_components.ul, {\n        children: [\"\\n\", _jsx(_components.li, {\n          children: \"Essentially just displays an image, which is great for accessibility\"\n        }), \"\\n\", _jsx(_components.li, {\n          children: \"Code is clean and short\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(List, {\n      type: \"cross\",\n      children: _jsxs(_components.ul, {\n        children: [\"\\n\", _jsx(_components.li, {\n          children: \"Difficult to write without visual aid\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Tips on creating your skeleton components\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Here are a couple of things I highly recommend you do when writing your skeleton components in React. They'll make the whole thing much easier to manage.\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Keep your skeletons with your components\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"One of my favorite ways of keeping my code organised is to keep each component's skeleton in the same file as its main component and then export it using \", _jsx(_components.strong, {\n        children: \"dot-notation\"\n      }), \".\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-jsx\",\n      children: _jsxs(_components.code, {\n        className: \"language-jsx\",\n        children: [_jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// inside components/mycomponent.tsx\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token imports\",\n          children: _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"SkeletonPrimitive\"\n          })\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"react-loading-skeleton\\\"\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"Component\"\n          })\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsx(_components.span, {\n            className: \"token tag\",\n            children: _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            })\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsx(_components.span, {\n            className: \"token tag\",\n            children: _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            })\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"Skeleton\"\n          })\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"SkeletonPrimitive\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token maybe-class-name\",\n          children: \"Component\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"Skeleton\"\n          })\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token maybe-class-name\",\n          children: \"Skeleton\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token maybe-class-name\",\n          children: \"Component\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// in another file\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token imports\",\n          children: [_jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"{\"\n          }), \" \", _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"Component\"\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"}\"\n          })]\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'components/mycomponent'\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"MyPage\"\n          })\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsxs(_components.span, {\n          className: \"token parameter\",\n          children: [_jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"{\"\n          }), \" isLoading \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"}\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"\\n    \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsx(_components.span, {\n            className: \"token tag\",\n            children: _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            })\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n      \"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n        isLoading \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"?\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Component.Skeleton\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Component\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n      \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsx(_components.span, {\n            className: \"token tag\",\n            children: _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            })\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Keep sizes consistent\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Since loading skeletons largely work to replace missing text it's very important to \", _jsx(_components.strong, {\n        children: \"make sure different levels of typography are consistently replaced throughout your skeletons.\"\n      }), \" For example, if your body text is always the same size and always has the same line height, so should any skeleton that replaces body text.\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Not everything needs to be put into your skeleton\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"It's easy to just replace all the elements in a div with skeletons and call it a day, but sometimes \", _jsx(_components.strong, {\n        children: \"keeping it simple\"\n      }), \" will actually make it look far more professional.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/screenshot-2022-10-10-at-20.04.32.png\",\n        alt: \"an image showing the different between the real skeleton and a modified version of it without the picture element\",\n        title: \"The skeleton on the right looks much cleaner without overlapping elements.\",\n        width: \"1748\",\n        height: \"1178\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"For example, the skeleton from the example above is missing the author's photo which would've been overlaid over the skeleton of the article's thumbnail. In general I think having skeletons crossing over each other doesn't look great so I decided not to include the author's picture at all.\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Make it look good!\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Let's be honest, the main reason you're wanting to implement skeleton loading in React is to make your app look more professional or make it seem faster. So the best tip I can give is to just \", _jsx(_components.strong, {\n        children: \"keep trying\"\n      }), \" until it looks good!\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Both \", _jsx(_components.code, {\n        children: \"react-spring\"\n      }), \" and \", _jsx(_components.code, {\n        children: \"framer-motion\"\n      }), \" are great options to animate the transition between your skeleton and your actual component to give it that extra polished touch.\"]\n    })]\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\nfunction _missingMdxReference(id, component) {\n  throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");\n}\n","frontmatter":{},"scope":{}}},{"slug":"how-to-blurred-images-on-load-in-next-js","highlight":"Next.js' &lt;Image&gt; component is a really impressive piece of engineering. It offers automatic image optimisation, all the SEO features you'd want from html image tags and some more arcane properties like blurDataURL, which is supposed to help Next.js display a low-res blurred image before loading its full-res version.\n\nIf that sounds too good to be true, well that's prob","content":"Next.js' `<Image>` component is a really impressive piece of engineering. It offers automatic image optimisation, all the SEO features you'd want from html image tags and some more arcane properties like `blurDataURL`, which is supposed to help Next.js display a low-res blurred image before loading its full-res version.\n\n![thumbnail with the text \"Blurring images on load in Next.js and Node.js\"](/images/frame-141.png \"How to: Blurred images on load in Next.js thumbnail image\")\n\nIf that sounds too good to be true, well that's probably because it is. The Next.js documentation is [very vague about the `blurDataURL` property](https://nextjs.org/docs/api-reference/next/image#blurdataurl). \n\n> A [Data URI](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) to be used as a placeholder image before the `src` image successfully loads. Only takes effect when combined with [`placeholder=\"blur\"`](https://nextjs.org/docs/api-reference/next/image#placeholder).\n>\n> Must be a base64-encoded image. It will be enlarged and blurred, so a very small image (10px or less) is recommended. Including larger images as placeholders may harm your application performance\n\n...Thanks?\n\nI don't know about you but the above means absolutely nothing to me in terms of actually using it. It took me a while in fact to figure out how to implement it, so here's everything I've learned about how to blur images in Next.js.\n\n## What is the blurDataURL property for the Image component?\n\nThe Next.js docs give us a little information, despite being a bit confusing:\n\n* Must be a base64-encoded image\n* a very small image (10px or less)\n\nThis means we need to generate a base64-encoded version of our image that is 10px or less. Pretty easy right? No, not really, but luckily there's a package for that!\n\n## Generating a base64 encoded image for blurDataURL\n\n[`Plaiceholder`](https://plaiceholder.co/docs/usage#base64) is going to be our package of choice for this. It's a nifty utility that can be used with Next.js or Node to generate the information we need. On top of `blurDataURL` we'll also need to know the image's size, which we can get with [`image-size`](https://www.npmjs.com/package/image-size?activeTab=readme)\n\n```shell\nnpm i sharp plaiceholder image-size\n# or\nyarn add sharp plaiceholder image-size\n```\n\nFor this article we'll use a lightly altered (and non-typescript) way of getting the information we need originally written by **Nikolov Lazar** in his blog [Generating blurDataURL for remote images in Next.js](https://nikolovlazar.com/blog/generating-blur-for-dynamic-images-nextjs).\n\nThe code we use here is mostly the same, but I'd like to show off a couple of different ways to use it in case you're not working with MDX.\n\n```javascript\n/**\n * utils/imageMetadata.js\n * Code written by Nikolov Lazar \n * https://nikolovlazar.com/blog/generating-blur-for-dynamic-images-nextjs\n */\n\nimport imageSize from 'image-size'\nimport path from 'path'\nimport { getPlaiceholder } from 'plaiceholder'\nimport visit from 'unist-util-visit'\nimport { promisify } from 'util'\n\n// Convert the imageSize method from callback-based to a Promise-based\n// promisify is a built-in nodejs utility function btw\nconst sizeOf = promisify(imageSize)\n\n// Just to check if the node is an image node\nfunction isImageNode(node) {\n    const img = node\n    return (\n        img.type === 'element' &&\n        img.tagName === 'img' &&\n        img.properties &&\n        typeof img.properties.src === 'string'\n    )\n}\n\n// Returns the props of given `src` to use for blurred images\nexport async function returnProps(src) {\n    // Calculate image resolution (width, height)\n    const res = await sizeOf(path.join(process.cwd(), 'public', src))\n    // Calculate base64 for the blur\n    const { base64: blurDataURL, img } = await getPlaiceholder(src)\n\n    // If an error happened calculating the resolution, throw an error\n    if (!res) throw Error(`Invalid image with src \"${node.properties.src}\"`)\n\n    const { width, height } = res\n\n    return {\n        ...img,\n        width,\n        height,\n        blurDataURL,\n    }\n}\n\nasync function addProps(node) {\n    // return the new props we'll need for our image\n    const { width, height, blurDataURL } = await returnProps(\n        node.properties.src\n    )\n\n    // add the props in the properties object of the node\n    // the properties object later gets transformed as props\n    node.properties.width = width\n    node.properties.height = height\n\n    node.properties.blurDataURL = blurDataURL\n    node.properties.placeholder = 'blur'\n}\n\nconst imageMetadata = () => {\n    return async function transformer(tree) {\n        // Create an array to hold all of the images from the markdown file\n        const images = []\n\n        visit(tree, 'element', (node) => {\n            // Visit every node in the tree, check if it's an image and push it in the images array\n            if (isImageNode(node)) {\n                images.push(node)\n            }\n        })\n\n        for (const image of images) {\n            // Loop through all of the images and add their props\n            await addProps(image)\n        }\n\n        return tree\n    }\n}\n\nexport default imageMetadata\n```\n\nFor this I've specifically separated some of the logic into it's own function `returnProps`, which we'll use when working with more standard APIs.\n\n### How to blur images in Next.js from a Node.js API\n\nThis is probably the easiest way to return the information you need to blur images. Whenever an image needs to be returned by an endpoint, you'll also have to make sure to use `plaiceholder` to return its data. It should look something like this:\n\n```javascript\nimport { returnProps } from 'utils/imageMetaData'\n\n/**\n * Random example using Next.js API functions, use whatever Node backend you\n * prefer\n */\nexport default function handler(req, res) {\n  // Get your data from a database or any other source\n  const data = getPostsFromDatabase();\n  \n  // Pass the image to plaiceholder\n  const imageProps = await returnProps(data.thumbnailSrc);\n  \n  // Or maybe you have a gallery\n  data.gallery = await Promise.all(\n    data.gallery.map(async item => {\n      const imageProps = await returnProps(item.imageSrc);\n      \n      // This will return the image a well as the needed plaiceholder\n      // info in the same object within the array 🤯\n      return { ...item, imageProps };\n    })\n  );\n  \n  res.status(200).json({ \n    ...data,\n    // This data will then be used by <Image> in our frontEnd\n    thumbnail: imageProps\n  })\n}\n```\n\n### How to blur images in a statically exported Next.js site\n\nUsing `plaiceholder` in a statically generated Next.js site is also pretty easy.\n\n```javascript\nexport const getStaticProps = async context => {\n  // Get your data from a database or any other source\n  const data = getPostsFromDatabase();\n  \n  // Pass the image to plaiceholder\n  const imageProps = await returnProps(data.thumbnailSrc);\n  \n  // Or maybe you have a gallery\n  data.gallery = await Promise.all(\n    data.gallery.map(async item => {\n      const imageProps = await returnProps(item.imageSrc);\n      \n      // This will return the image a well as the needed plaiceholder\n      // info in the same object within the array 🤯\n      return { ...item, imageProps };\n    })\n  );\n  \n  return {\n    props: {\n      data,\n      // This data will then be used by <Image> in our frontEnd\n      thumbnail: imageProps\n    },\n  };\n}\n```\n\n### How to blur images in Next.js from a markdown file\n\nBlurring images within Markdown or MDX is thankfully a lot easier thanks to the rest of Nikolov's functions. We just need to pass the plugin to our serialize function.\n\n```jsx\nimport imageMetaData from 'utils/imageMetadata'\nimport { serialize } from 'next-mdx-remote/serialize'\n\n\nconst components = {\n    img: (props: any): React.ReactNode => (\n        <Image {...props} layout=\"responsive\" loading=\"lazy\" />\n    ),\n}\n\n\nfunction Post({ mdx }) {\n    return (\n        <>\n            <MDXRemote\n                {...mdx}\n                components={components}\n            />\n        </>\n}\n\nexport const getStaticProps = async context => {\n  // Get your data from a database or any other source\n  const markdown = getPostsFromDatabase();\n  \n  // convert your markdown to html with unified, rehype or remark\n  const mdx = await serialize(markdown, {\n      mdxOptions: {\n          rehypePlugins: [imageMetaData],\n      },\n  })\n  \n  return {\n    props: {\n      mdx,\n    },\n  };\n}\n```\n\nT﻿hat's all! Try to load your page. Your images should have a beautiful blur before they lazy-load into view.\n","data":{"layout":"blog","title":"How to: Blurred images on load in Next.js","categories":[{"slug":"react","highlight":"","content":"","data":{"name":"React","visible":true,"description":"How to's and tutorials on our favorite Javascript library."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}}],"author":{"slug":"leonardo-petrucci","highlight":"@creativiii\n","content":"\n[@creativiii](https://twitter.com/creativiii)\n","data":{"name":"Leonardo Petrucci","avatar":"/images/leonardo-petrucci.jpg"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    a: \"a\"\n  }, _provideComponents(), props.components);\n  return _jsx(_components.p, {\n    children: _jsx(_components.a, {\n      href: \"https://twitter.com/creativiii\",\n      children: \"@creativiii\"\n    })\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},"date":"2022-09-28T13:39:45.129Z","thumbnail":"/images/frame-141.png","description":"A guide to implement blur placeholders with Next.js' image component in Node.js, Mardkwon and MDX.","yoast_keyword":"blur image next.js","published":true},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    code: \"code\",\n    img: \"img\",\n    a: \"a\",\n    blockquote: \"blockquote\",\n    h2: \"h2\",\n    ul: \"ul\",\n    li: \"li\",\n    pre: \"pre\",\n    span: \"span\",\n    strong: \"strong\",\n    h3: \"h3\"\n  }, _provideComponents(), props.components);\n  return _jsxs(_Fragment, {\n    children: [_jsxs(_components.p, {\n      children: [\"Next.js' \", _jsx(_components.code, {\n        children: \"<Image>\"\n      }), \" component is a really impressive piece of engineering. It offers automatic image optimisation, all the SEO features you'd want from html image tags and some more arcane properties like \", _jsx(_components.code, {\n        children: \"blurDataURL\"\n      }), \", which is supposed to help Next.js display a low-res blurred image before loading its full-res version.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-141.png\",\n        alt: \"thumbnail with the text \\\"Blurring images on load in Next.js and Node.js\\\"\",\n        title: \"How to: Blurred images on load in Next.js thumbnail image\",\n        width: \"1200\",\n        height: \"630\"\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"If that sounds too good to be true, well that's probably because it is. The Next.js documentation is \", _jsxs(_components.a, {\n        href: \"https://nextjs.org/docs/api-reference/next/image#blurdataurl\",\n        children: [\"very vague about the \", _jsx(_components.code, {\n          children: \"blurDataURL\"\n        }), \" property\"]\n      }), \".\"]\n    }), \"\\n\", _jsxs(_components.blockquote, {\n      children: [\"\\n\", _jsxs(_components.p, {\n        children: [\"A \", _jsx(_components.a, {\n          href: \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs\",\n          children: \"Data URI\"\n        }), \" to be used as a placeholder image before the \", _jsx(_components.code, {\n          children: \"src\"\n        }), \" image successfully loads. Only takes effect when combined with \", _jsx(_components.a, {\n          href: \"https://nextjs.org/docs/api-reference/next/image#placeholder\",\n          children: _jsx(_components.code, {\n            children: \"placeholder=\\\"blur\\\"\"\n          })\n        }), \".\"]\n      }), \"\\n\", _jsx(_components.p, {\n        children: \"Must be a base64-encoded image. It will be enlarged and blurred, so a very small image (10px or less) is recommended. Including larger images as placeholders may harm your application performance\"\n      }), \"\\n\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"...Thanks?\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"I don't know about you but the above means absolutely nothing to me in terms of actually using it. It took me a while in fact to figure out how to implement it, so here's everything I've learned about how to blur images in Next.js.\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"What is the blurDataURL property for the Image component?\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"The Next.js docs give us a little information, despite being a bit confusing:\"\n    }), \"\\n\", _jsxs(_components.ul, {\n      children: [\"\\n\", _jsx(_components.li, {\n        children: \"Must be a base64-encoded image\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"a very small image (10px or less)\"\n      }), \"\\n\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"This means we need to generate a base64-encoded version of our image that is 10px or less. Pretty easy right? No, not really, but luckily there's a package for that!\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Generating a base64 encoded image for blurDataURL\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [_jsx(_components.a, {\n        href: \"https://plaiceholder.co/docs/usage#base64\",\n        children: _jsx(_components.code, {\n          children: \"Plaiceholder\"\n        })\n      }), \" is going to be our package of choice for this. It's a nifty utility that can be used with Next.js or Node to generate the information we need. On top of \", _jsx(_components.code, {\n        children: \"blurDataURL\"\n      }), \" we'll also need to know the image's size, which we can get with \", _jsx(_components.a, {\n        href: \"https://www.npmjs.com/package/image-size?activeTab=readme\",\n        children: _jsx(_components.code, {\n          children: \"image-size\"\n        })\n      })]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-shell\",\n      children: _jsxs(_components.code, {\n        className: \"language-shell\",\n        children: [_jsx(_components.span, {\n          className: \"token function\",\n          children: \"npm\"\n        }), \" i sharp plaiceholder image-size\\n\", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"# or\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"yarn\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"add\"\n        }), \" sharp plaiceholder image-size\\n\"]\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"For this article we'll use a lightly altered (and non-typescript) way of getting the information we need originally written by \", _jsx(_components.strong, {\n        children: \"Nikolov Lazar\"\n      }), \" in his blog \", _jsx(_components.a, {\n        href: \"https://nikolovlazar.com/blog/generating-blur-for-dynamic-images-nextjs\",\n        children: \"Generating blurDataURL for remote images in Next.js\"\n      }), \".\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"The code we use here is mostly the same, but I'd like to show off a couple of different ways to use it in case you're not working with MDX.\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-javascript\",\n      children: _jsxs(_components.code, {\n        className: \"language-javascript\",\n        children: [_jsx(_components.span, {\n          className: \"token doc-comment comment\",\n          children: \"/**\\n * utils/imageMetadata.js\\n * Code written by Nikolov Lazar \\n * https://nikolovlazar.com/blog/generating-blur-for-dynamic-images-nextjs\\n */\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token imports\",\n          children: \"imageSize\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'image-size'\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token imports\",\n          children: \"path\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'path'\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token imports\",\n          children: [_jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"{\"\n          }), \" getPlaiceholder \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"}\"\n          })]\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'plaiceholder'\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token imports\",\n          children: \"visit\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'unist-util-visit'\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token imports\",\n          children: [_jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"{\"\n          }), \" promisify \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"}\"\n          })]\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'util'\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Convert the imageSize method from callback-based to a Promise-based\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// promisify is a built-in nodejs utility function btw\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" sizeOf \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"promisify\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"imageSize\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Just to check if the node is an image node\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"function\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"isImageNode\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"node\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" img \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" node\\n    \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"\\n        img\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"type\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"===\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'element'\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"&&\"\n        }), \"\\n        img\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"tagName\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"===\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'img'\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"&&\"\n        }), \"\\n        img\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"properties\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"&&\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"typeof\"\n        }), \" img\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"properties\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"src\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"===\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'string'\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Returns the props of given `src` to use for blurred images\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"function\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"returnProps\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"src\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Calculate image resolution (width, height)\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" res \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"sizeOf\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"path\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"join\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"process\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"cwd\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'public'\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" src\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Calculate base64 for the blur\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"base64\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" blurDataURL\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" img \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"getPlaiceholder\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"src\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n\\n    \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// If an error happened calculating the resolution, throw an error\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"if\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"!\"\n        }), \"res\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"throw\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token known-class-name class-name\",\n          children: \"Error\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsxs(_components.span, {\n          className: \"token template-string\",\n          children: [_jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          }), _jsx(_components.span, {\n            className: \"token string\",\n            children: \"Invalid image with src \\\"\"\n          }), _jsxs(_components.span, {\n            className: \"token interpolation\",\n            children: [_jsx(_components.span, {\n              className: \"token interpolation-punctuation punctuation\",\n              children: \"${\"\n            }), \"node\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \".\"\n            }), _jsx(_components.span, {\n              className: \"token property-access\",\n              children: \"properties\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \".\"\n            }), _jsx(_components.span, {\n              className: \"token property-access\",\n              children: \"src\"\n            }), _jsx(_components.span, {\n              className: \"token interpolation-punctuation punctuation\",\n              children: \"}\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token string\",\n            children: \"\\\"\"\n          }), _jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \" width\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" height \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" res\\n\\n    \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token spread operator\",\n          children: \"...\"\n        }), \"img\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n        width\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n        height\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n        blurDataURL\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"function\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"addProps\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"node\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// return the new props we'll need for our image\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \" width\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" height\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" blurDataURL \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"returnProps\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"\\n        node\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"properties\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"src\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n\\n    \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// add the props in the properties object of the node\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// the properties object later gets transformed as props\"\n        }), \"\\n    node\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"properties\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"width\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" width\\n    node\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"properties\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"height\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" height\\n\\n    node\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"properties\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"blurDataURL\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" blurDataURL\\n    node\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"properties\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"placeholder\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'blur'\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: \"imageMetadata\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"function\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"transformer\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"tree\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Create an array to hold all of the images from the markdown file\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" images \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\\n        \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"visit\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"tree\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'element'\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"node\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n            \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Visit every node in the tree, check if it's an image and push it in the images array\"\n        }), \"\\n            \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"if\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token function\",\n          children: \"isImageNode\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"node\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n                images\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"push\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"node\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n            \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n\\n        \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"for\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" image \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"of\"\n        }), \" images\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n            \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Loop through all of the images and add their props\"\n        }), \"\\n            \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"addProps\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"image\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n        \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" tree\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"default\"\n        }), \" imageMetadata\\n\"]\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"For this I've specifically separated some of the logic into it's own function \", _jsx(_components.code, {\n        children: \"returnProps\"\n      }), \", which we'll use when working with more standard APIs.\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"How to blur images in Next.js from a Node.js API\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"This is probably the easiest way to return the information you need to blur images. Whenever an image needs to be returned by an endpoint, you'll also have to make sure to use \", _jsx(_components.code, {\n        children: \"plaiceholder\"\n      }), \" to return its data. It should look something like this:\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-javascript\",\n      children: _jsxs(_components.code, {\n        className: \"language-javascript\",\n        children: [_jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token imports\",\n          children: [_jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"{\"\n          }), \" returnProps \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"}\"\n          })]\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'utils/imageMetaData'\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token doc-comment comment\",\n          children: \"/**\\n * Random example using Next.js API functions, use whatever Node backend you\\n * prefer\\n */\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"default\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"function\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"handler\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsxs(_components.span, {\n          className: \"token parameter\",\n          children: [\"req\", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \",\"\n          }), \" res\"]\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Get your data from a database or any other source\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" data \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"getPostsFromDatabase\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n  \\n  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Pass the image to plaiceholder\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" imageProps \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"returnProps\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"data\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"thumbnailSrc\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n  \\n  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Or maybe you have a gallery\"\n        }), \"\\n  data\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"gallery\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token known-class-name class-name\",\n          children: \"Promise\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"all\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"\\n    data\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"gallery\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"map\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"item\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n      \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" imageProps \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"returnProps\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"item\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"imageSrc\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n      \\n      \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// This will return the image a well as the needed plaiceholder\"\n        }), \"\\n      \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// info in the same object within the array 🤯\"\n        }), \"\\n      \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token spread operator\",\n          children: \"...\"\n        }), \"item\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" imageProps \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n  \\n  res\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"status\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token number\",\n          children: \"200\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"json\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \" \\n    \", _jsx(_components.span, {\n          className: \"token spread operator\",\n          children: \"...\"\n        }), \"data\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// This data will then be used by <Image> in our frontEnd\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"thumbnail\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" imageProps\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"How to blur images in a statically exported Next.js site\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Using \", _jsx(_components.code, {\n        children: \"plaiceholder\"\n      }), \" in a statically generated Next.js site is also pretty easy.\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-javascript\",\n      children: _jsxs(_components.code, {\n        className: \"language-javascript\",\n        children: [_jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: \"getStaticProps\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"context\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Get your data from a database or any other source\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" data \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"getPostsFromDatabase\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n  \\n  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Pass the image to plaiceholder\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" imageProps \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"returnProps\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"data\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"thumbnailSrc\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n  \\n  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Or maybe you have a gallery\"\n        }), \"\\n  data\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"gallery\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token known-class-name class-name\",\n          children: \"Promise\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"all\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"\\n    data\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"gallery\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"map\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"item\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n      \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" imageProps \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"returnProps\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"item\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"imageSrc\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n      \\n      \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// This will return the image a well as the needed plaiceholder\"\n        }), \"\\n      \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// info in the same object within the array 🤯\"\n        }), \"\\n      \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token spread operator\",\n          children: \"...\"\n        }), \"item\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" imageProps \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n  \\n  \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"props\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n      data\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n      \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// This data will then be used by <Image> in our frontEnd\"\n        }), \"\\n      \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"thumbnail\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" imageProps\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"How to blur images in Next.js from a markdown file\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Blurring images within Markdown or MDX is thankfully a lot easier thanks to the rest of Nikolov's functions. We just need to pass the plugin to our serialize function.\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-jsx\",\n      children: _jsxs(_components.code, {\n        className: \"language-jsx\",\n        children: [_jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token imports\",\n          children: \"imageMetaData\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'utils/imageMetadata'\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token imports\",\n          children: [_jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"{\"\n          }), \" serialize \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"}\"\n          })]\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'next-mdx-remote/serialize'\"\n        }), \"\\n\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" components \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"img\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"props\", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" any\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token maybe-class-name\",\n          children: \"React\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"ReactNode\"\n          })\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"\\n        \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Image\"\n            })]\n          }), \" \", _jsxs(_components.span, {\n            className: \"token spread\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"{\"\n            }), _jsx(_components.span, {\n              className: \"token spread operator\",\n              children: \"...\"\n            }), \"props\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"}\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"layout\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"responsive\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"loading\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"lazy\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"function\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"Post\"\n          })\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsxs(_components.span, {\n          className: \"token parameter\",\n          children: [_jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"{\"\n          }), \" mdx \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"}\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"\\n        \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsx(_components.span, {\n            className: \"token tag\",\n            children: _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            })\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n            \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"MDXRemote\"\n            })]\n          }), \"\\n                \", _jsxs(_components.span, {\n            className: \"token spread\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"{\"\n            }), _jsx(_components.span, {\n              className: \"token spread operator\",\n              children: \"...\"\n            }), \"mdx\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"}\"\n            })]\n          }), \"\\n                \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"components\"\n          }), _jsxs(_components.span, {\n            className: \"token script language-javascript\",\n            children: [_jsx(_components.span, {\n              className: \"token script-punctuation punctuation\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"{\"\n            }), \"components\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"}\"\n            })]\n          }), \"\\n            \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n        \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsx(_components.span, {\n            className: \"token tag\",\n            children: _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            })\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: \"getStaticProps\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"context\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// Get your data from a database or any other source\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" markdown \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"getPostsFromDatabase\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n  \\n  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// convert your markdown to html with unified, rehype or remark\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" mdx \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"serialize\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"markdown\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n      \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"mdxOptions\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n          \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"rehypePlugins\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), \"imageMetaData\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n      \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n  \\n  \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"props\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n      mdx\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"T﻿hat's all! Try to load your page. Your images should have a beautiful blur before they lazy-load into view.\"\n    })]\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},{"slug":"how-to-asynchronous-buttons-with-loading-state-in-react","highlight":"Buttons and loading states are one of the most fundamental parts of any app or website. For me at least, I'd press a button to submit information to an endpoint so often that I found myself looking for easy ways to improve this action's UX.\n\nMy immediate thought was that it would be great to show a loading state and disable the button until the action had completed. Unfortunately doing this manually for each button looked like far too much boilerplate code.\n\nAdd a state to keep track of loading evrey time a button to submit is used&lt;","content":"Buttons and loading states are one of the most fundamental parts of any app or website. For me at least, I'd press a button to submit information to an endpoint so often that I found myself looking for easy ways to improve this action's UX.\n\n![](/images/frame-140.png)\n\nMy immediate thought was that it would be great to show a loading state and disable the button until the action had completed. Unfortunately doing this manually for each button looked like far too much boilerplate code.\n\n1. Add a state to keep track of loading evrey time a button to submit is used\n2. Make sure that before hitting my endpoint I set the loading state to true\n3. Pass the loading state to the button\n4. Ensure that on success or failure the loading state is reset\n\nDoing this for 10 buttons seemed like a code smell, so imagine doing it for my 100+ forms. Not a great idea.\n\n## Making your buttons asynchronous and adding a loading state\n\nFunnily enough, the solution is actually incredibly simple. I simply didn't know it could done.\n\nYour button component should look something like this:\n\n```jsx\nconst Button = (props) => {\n  return (\n    <button\n      // You don't need this line at this point, but we'll use it later\n      onClick={props.onClick}\n    >\n      {children}\n    </button>\n  );\n};\n```\n\nAll we have to do to make our button asynchronous is re-implement its onClick event.\n\n```jsx\nconst Button = (props) => {\n  const [loading, setLoading] = React.useState(false);\n\n  return (\n    <button\n      // don't forget to make your onClick async!\n      onClick={async (e) => {\n        if (props.onClick) {\n          // This is the only reliable way to check if a function is asynchronous\n          const onClickIsPromise =\n            props.onClick.constructor.name === \"AsyncFunction\";\n          // We only set loading if the function is actually async\n          // to avoid useless re-renders\n          if (onClickIsPromise) setLoading(true);\n          // We can await onclick even if it's not asynchronous\n          // it won't change its behavior\n          await props.onClick(e);\n          if (onClickIsPromise) setLoading(false);\n        }\n      }}\n    >\n      {children}\n    </button>\n  );\n};\n```\n\nLet's go through how this works:\n\n1. When onClick is called, we'll check if the prop function is async\n2. If it is, we'll set our loading state to true\n3. Then we'll launch the function itself and await its resolution\n4. Once it's finished we'll set the loading state back to false\n\nThat's it! All you have to do now is do *something* with your new state. For example, you could display an icon and disable the button:\n\n<iframe src=\"https://codesandbox.io/embed/async-button-f5tgz9?fontsize=14&hidenavigation=1&module=%2Fsrc%2Fbutton%2Fbutton.jsx&theme=dark\"\n     title=\"Async Button \"\n     allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n     sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n   ></iframe>\n\nOnce you have that first skeleton in place the sky is the limit, you could easily even add some animations to your button to make it look extra professional:\n\n<iframe src=\"https://codesandbox.io/embed/async-button-with-animations-4dr3mo?fontsize=14&hidenavigation=1&module=%2Fsrc%2Fbutton%2Fbutton.jsx&theme=dark\"\n     title=\"Async Button with animations\"\n     allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n     sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n   ></iframe>\n\nLet me know if this ends up helping you or if you come up with any cool buttons yourself!\n","data":{"layout":"blog","title":"How to: Asynchronous buttons with loading state in React","categories":[{"slug":"react","highlight":"","content":"","data":{"name":"React","visible":true,"description":"How to's and tutorials on our favorite Javascript library."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},{"slug":"ux","highlight":"","content":"","data":{"name":"UX","visible":true,"description":"UX makes the world around. Or at least it does to us."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}}],"author":{"slug":"leonardo-petrucci","highlight":"@creativiii\n","content":"\n[@creativiii](https://twitter.com/creativiii)\n","data":{"name":"Leonardo Petrucci","avatar":"/images/leonardo-petrucci.jpg"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    a: \"a\"\n  }, _provideComponents(), props.components);\n  return _jsx(_components.p, {\n    children: _jsx(_components.a, {\n      href: \"https://twitter.com/creativiii\",\n      children: \"@creativiii\"\n    })\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},"date":"2022-09-19T11:50:02.834Z","thumbnail":"/images/frame-140.png","description":"Buttons are the cornerstone of every application. This is a 5 minute improvement that will revolutionise how you create your button components and improve their UX.","published":true},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    img: \"img\",\n    ol: \"ol\",\n    li: \"li\",\n    h2: \"h2\",\n    pre: \"pre\",\n    code: \"code\",\n    span: \"span\",\n    em: \"em\"\n  }, _provideComponents(), props.components);\n  return _jsxs(_Fragment, {\n    children: [_jsx(_components.p, {\n      children: \"Buttons and loading states are one of the most fundamental parts of any app or website. For me at least, I'd press a button to submit information to an endpoint so often that I found myself looking for easy ways to improve this action's UX.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-140.png\",\n        alt: \"\",\n        width: \"1200\",\n        height: \"630\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"My immediate thought was that it would be great to show a loading state and disable the button until the action had completed. Unfortunately doing this manually for each button looked like far too much boilerplate code.\"\n    }), \"\\n\", _jsxs(_components.ol, {\n      children: [\"\\n\", _jsx(_components.li, {\n        children: \"Add a state to keep track of loading evrey time a button to submit is used\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Make sure that before hitting my endpoint I set the loading state to true\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Pass the loading state to the button\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Ensure that on success or failure the loading state is reset\"\n      }), \"\\n\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Doing this for 10 buttons seemed like a code smell, so imagine doing it for my 100+ forms. Not a great idea.\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Making your buttons asynchronous and adding a loading state\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Funnily enough, the solution is actually incredibly simple. I simply didn't know it could done.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Your button component should look something like this:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-jsx\",\n      children: _jsxs(_components.code, {\n        className: \"language-jsx\",\n        children: [_jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"Button\"\n          })\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"props\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"\\n    \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"button\"]\n          }), \"\\n      \", _jsx(_components.span, {\n            className: \"token comment\",\n            children: \"// You don't need this line at this point, but we'll use it later\"\n          }), \"\\n      \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"onClick\"\n          }), _jsxs(_components.span, {\n            className: \"token script language-javascript\",\n            children: [_jsx(_components.span, {\n              className: \"token script-punctuation punctuation\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"{\"\n            }), \"props\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \".\"\n            }), _jsx(_components.span, {\n              className: \"token property-access\",\n              children: \"onClick\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"}\"\n            })]\n          }), \"\\n    \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n      \"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"children\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            }), \"button\"]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"All we have to do to make our button asynchronous is re-implement its onClick event.\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-jsx\",\n      children: _jsxs(_components.code, {\n        className: \"language-jsx\",\n        children: [_jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"Button\"\n          })\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"props\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), \"loading\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" setLoading\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token maybe-class-name\",\n          children: \"React\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"useState\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token boolean\",\n          children: \"false\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n\\n  \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"\\n    \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), \"button\"]\n          }), \"\\n      \", _jsx(_components.span, {\n            className: \"token comment\",\n            children: \"// don't forget to make your onClick async!\"\n          }), \"\\n      \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"onClick\"\n          }), _jsxs(_components.span, {\n            className: \"token script language-javascript\",\n            children: [_jsx(_components.span, {\n              className: \"token script-punctuation punctuation\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"{\"\n            }), _jsx(_components.span, {\n              className: \"token keyword\",\n              children: \"async\"\n            }), \" \", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"(\"\n            }), _jsx(_components.span, {\n              className: \"token parameter\",\n              children: \"e\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \")\"\n            }), \" \", _jsx(_components.span, {\n              className: \"token arrow operator\",\n              children: \"=>\"\n            }), \" \", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"{\"\n            }), \"\\n        \", _jsx(_components.span, {\n              className: \"token keyword control-flow\",\n              children: \"if\"\n            }), \" \", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"(\"\n            }), \"props\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \".\"\n            }), _jsx(_components.span, {\n              className: \"token property-access\",\n              children: \"onClick\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \")\"\n            }), \" \", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"{\"\n            }), \"\\n          \", _jsx(_components.span, {\n              className: \"token comment\",\n              children: \"// This is the only reliable way to check if a function is asynchronous\"\n            }), \"\\n          \", _jsx(_components.span, {\n              className: \"token keyword\",\n              children: \"const\"\n            }), \" onClickIsPromise \", _jsx(_components.span, {\n              className: \"token operator\",\n              children: \"=\"\n            }), \"\\n            props\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \".\"\n            }), _jsx(_components.span, {\n              className: \"token property-access\",\n              children: \"onClick\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \".\"\n            }), _jsx(_components.span, {\n              className: \"token property-access\",\n              children: \"constructor\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \".\"\n            }), _jsx(_components.span, {\n              className: \"token property-access\",\n              children: \"name\"\n            }), \" \", _jsx(_components.span, {\n              className: \"token operator\",\n              children: \"===\"\n            }), \" \", _jsx(_components.span, {\n              className: \"token string\",\n              children: \"\\\"AsyncFunction\\\"\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \";\"\n            }), \"\\n          \", _jsx(_components.span, {\n              className: \"token comment\",\n              children: \"// We only set loading if the function is actually async\"\n            }), \"\\n          \", _jsx(_components.span, {\n              className: \"token comment\",\n              children: \"// to avoid useless re-renders\"\n            }), \"\\n          \", _jsx(_components.span, {\n              className: \"token keyword control-flow\",\n              children: \"if\"\n            }), \" \", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"(\"\n            }), \"onClickIsPromise\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \")\"\n            }), \" \", _jsx(_components.span, {\n              className: \"token function\",\n              children: \"setLoading\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"(\"\n            }), _jsx(_components.span, {\n              className: \"token boolean\",\n              children: \"true\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \")\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \";\"\n            }), \"\\n          \", _jsx(_components.span, {\n              className: \"token comment\",\n              children: \"// We can await onclick even if it's not asynchronous\"\n            }), \"\\n          \", _jsx(_components.span, {\n              className: \"token comment\",\n              children: \"// it won't change its behavior\"\n            }), \"\\n          \", _jsx(_components.span, {\n              className: \"token keyword control-flow\",\n              children: \"await\"\n            }), \" props\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \".\"\n            }), _jsx(_components.span, {\n              className: \"token method function property-access\",\n              children: \"onClick\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"(\"\n            }), \"e\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \")\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \";\"\n            }), \"\\n          \", _jsx(_components.span, {\n              className: \"token keyword control-flow\",\n              children: \"if\"\n            }), \" \", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"(\"\n            }), \"onClickIsPromise\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \")\"\n            }), \" \", _jsx(_components.span, {\n              className: \"token function\",\n              children: \"setLoading\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"(\"\n            }), _jsx(_components.span, {\n              className: \"token boolean\",\n              children: \"false\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \")\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \";\"\n            }), \"\\n        \", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"}\"\n            }), \"\\n      \", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"}\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"}\"\n            })]\n          }), \"\\n    \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n      \"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"children\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            }), \"button\"]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Let's go through how this works:\"\n    }), \"\\n\", _jsxs(_components.ol, {\n      children: [\"\\n\", _jsx(_components.li, {\n        children: \"When onClick is called, we'll check if the prop function is async\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"If it is, we'll set our loading state to true\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Then we'll launch the function itself and await its resolution\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Once it's finished we'll set the loading state back to false\"\n      }), \"\\n\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"That's it! All you have to do now is do \", _jsx(_components.em, {\n        children: \"something\"\n      }), \" with your new state. For example, you could display an icon and disable the button:\"]\n    }), \"\\n\", _jsx(\"iframe\", {\n      src: \"https://codesandbox.io/embed/async-button-f5tgz9?fontsize=14&hidenavigation=1&module=%2Fsrc%2Fbutton%2Fbutton.jsx&theme=dark\",\n      title: \"Async Button \",\n      allow: \"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\",\n      sandbox: \"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Once you have that first skeleton in place the sky is the limit, you could easily even add some animations to your button to make it look extra professional:\"\n    }), \"\\n\", _jsx(\"iframe\", {\n      src: \"https://codesandbox.io/embed/async-button-with-animations-4dr3mo?fontsize=14&hidenavigation=1&module=%2Fsrc%2Fbutton%2Fbutton.jsx&theme=dark\",\n      title: \"Async Button with animations\",\n      allow: \"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\",\n      sandbox: \"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Let me know if this ends up helping you or if you come up with any cool buttons yourself!\"\n    })]\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},{"slug":"how-to-create-an-api-from-markdown-files-with-next-js","highlight":"I've previously talked about how to read markdown files from Next.js' API routes. However, it was only recently, while improving some of my blog's logic, that I realised the true value of this technique. So here's a simple guide on how to create an incredibly powerful content API from your Markdown files and double your build speed while you're at it.\n","content":"I've previously talked about [how to read markdown files from Next.js' API routes](https://ironeko.com/posts/how-to-read-markdown-files-from-next-js-api-routes). However, it was only recently, while improving some of my blog's logic, that I realised the true value of this technique. So here's a simple guide on how to create an incredibly powerful content API from your Markdown files and **double your build speed** while you're at it.\n\n![Hero image with the text \"Speed up your static generation with a Next.js markdown API and ISR\"](/images/frame-139-1-.png)\n\n## The setup\n\nBefore you can actually get started turning your markdown files into an API, you'll need these files in an easily readable and parsable format. I would recommend following my explanation on how to [transform your markdown to JSON at build time](https://ironeko.com/posts/how-to-read-markdown-files-from-next-js-api-routes#how-to-work-around-nextjs-api-filesystem-limitations) but really any way to get your markdown into JSON will probably work.\n\nYou'll need your different categories of content each in a JSON file with each element being part of a larger array. For example I had:\n\n* `posts.json`\n* `authors.json`\n* `categories.json`\n\n## Creating your API endpoints\n\nLet's create endpoints to fetch our posts as an example.\n\n```javascript\n// pages/api/posts/index.js\n\n// You'll need to specify the absolute URL to fetch your file\nconst url = `http://example.com`\n\n/**\n * fetches and returns all posts from json cache\n */\nexport const getAllPosts = async () => {\n    const data = (await fetch(`${url}/cache/posts.json`).then((res) =>\n        res.json()\n    ))\n    return data\n}\n\n/**\n * Returns current page from query string. If undefined, returns 0.\n */\nexport const pagination = (req) => {\n    const { page = '0' } = req.query as { page: string }\n    const actualPage = parseInt(page) <= 0 ? 1 : parseInt(page)\n    return actualPage\n}\n\n/**\n * Returns a list of paginated posts\n */\nconst posts = async (req, res) => {\n    const page = pagination(req)\n    const data = (await getAllPosts())\n        // sort posts by publish date\n        .sort((post1, post2) => (post1.data.date > post2.data.date ? -1 : 1))\n        // only take 10 depending on page value\n        .slice((page - 1) * 10, page * 10)\n    res.status(200).json(data)\n}\n\nexport default posts\n```\n\nIt's fairly straightforward since we don't need to do a whole lot apart from return our entire JSON file. Nonetheless, we *can* implement small UX improvements.\n\n* On line `32` we sort our content by publishing date\n* We paginate all of our content, so we don't have to repeat the code in our pages\n\nYou can check out how [Ironeko's endpoint looks as an example](https://ironeko.com/api/posts).\n\nThe second piece of the puzzle is to then create an endpoint used just to return one singular piece of content. We'll use it to actually create our pages.\n\n```javascript\n// pages/api/posts/[slug].js\n\n// You'll need to specify the absolute URL to fetch your file\nconst url = `http://example.com`\n\n/**\n * fetches and returns all posts from json cache\n */\nexport const getAllPosts = async () => {\n    const data = (await fetch(`${url}/cache/posts.json`).then((res) =>\n        res.json()\n    ))\n    return data\n}\n\n/**\n * Finds and returns a single post\n */\nconst post = async (req, res) => {\n    const { slug } = req.query\n    const data = (await getAllPosts()).find((p) => p.slug === slug)\n    if (data) {\n        res.status(200).json(data)\n    } else {\n        res.status(404)\n        res.end()\n    }\n}\n\nexport default post\n```\n\nThe above is very similar to our endpoint, only with some minor differences:\n\n* We filter our data to find a post that matches the `slug` provided in the API url\n\n  * A `slug` is a unique piece of text that identifies our article. For example you can see the slug for this page in the URL `how-to-create-an-api-from-markdown-files-with-next-js`\n* If we couldn't find a match in our data we return a 404 error, which we'll then handle when trying to display the page\n\nIf you've done it right it'll look something like [the endpoint we use here on Ironeko](https://ironeko.com/api/posts/how-to-create-an-api-from-markdown-files-with-next-js).\n\n## Combining your new endpoints with Next.js' ISR to improve your build time\n\nIf you've managed a static site before you'll no doubt have noticed how **each time a new piece of content is added your builds take a little bit longer**. This blog has just over 100 articles, and the build time has slowly crawled to around 3 minutes... Every. Time. I. Edit. Something.\n\nY﻿ou may have heard of **Incremental Static Regeneration** before. (If not, Smashing Magazine published the fantastic [A Complete Guide To Incremental Static Regeneration (ISR) With Next.js](https://www.smashingmagazine.com/2021/04/incremental-static-regeneration-nextjs/) which is an excellent explanation of the feature.)\n\n<Notice>\n\n\n\nThere's a lot of magic related to how Incremental Static Regeneration works, but it's a fantastic feature and you don't necessarily need to understand how it functions to use it to its full potential.\n\n\n\n</Notice>\n\nThe point of ISR is that rather than telling Next.js how many pages you want to generate at build time, you'll just have to tell it where to get the information to generate them. The pages will then be generated upon request.\n\nThanks to your new endpoint you can replace your `getStaticProps` and `getStaticPaths` with a much simpler:\n\n```javascript\n// pages/posts/[slug].js\n\n// You'll need to specify the absolute URL to fetch your file\nconst url = `http://example.com`\n\nexport const getStaticPaths = async () => {\n    return {\n        paths: [],\n        fallback: 'blocking',\n    }\n}\n\nexport const getStaticProps = async ({ params }) => {\n    const { slug } = params\n\n    const post = (await fetch(`${url}/api/posts/${slug}`)\n        .then((res) => res.json())\n        .catch(() => null))\n\n    if (!post) {\n        return {\n            notFound: true,\n        }\n    }\n\n    return {\n        props: {\n            post,\n        },\n        revalidate: 60,\n    }\n}\n```\n\nYou should see your build time cut down exponentially depending on how much content you have!\n\n## Bonus: Serialize your markdown (or mdx) on build\n\nIdeally with these changes you'll want to keep your serverless function execution time as short as possible (especially if you're on a Vercel Hobby plan). So there's a couple more corners you can cut.\n\nIf you're using markdown or mdx you can actually serialize your markdown into a usable string outside of your `getStaticProps`. When generating your caches, rather than adding your markdown to your cache you can convert it directly to HTML or JSX so you won't have to convert it later while generating your page!\n\n```javascript\n// use this wherever you transform your markdown into JSON\n\nimport matter from 'gray-matter'\nimport { serialize } from 'next-mdx-remote/serialize'\nimport { remark } from 'remark'\nimport html from 'remark-html'\n\n/**\n * Convert a markdown file to JSON\n */\nconst serializeMarkdown = async (markdownFile) => {\n  // we extract the front-matter info from our markdown\n  const matterResult = matter(markdownFile)\n  \n  // convert the markdown body into HTML\n  const html = remark().use(html).processSync(matterResult.content)\n  \n  // or generate a JSX string from your MDX!\n  const mdx = await serialize(matterResult.content)\n\n  return {\n      html,\n      mdx,\n      ...matterResult,\n  }\n}\n```\n\nWith these small changes Ironeko's build time dropped to around 40 seconds. This has improved my quality of life considerably, so you should definitely give it a try if you're falling out of love with static generation.\n","data":{"layout":"blog","title":"How to create an api from markdown files with Next.js","categories":[{"slug":"technology","highlight":"","content":"","data":{"name":"Technology","visible":true,"description":"Frameworks, libraries, interesting new releases in the world of tech and programming. If this sounds good to you, you’re in the right place."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},{"slug":"react","highlight":"","content":"","data":{"name":"React","visible":true,"description":"How to's and tutorials on our favorite Javascript library."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},{"slug":"ux","highlight":"","content":"","data":{"name":"UX","visible":true,"description":"UX makes the world around. Or at least it does to us."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}}],"author":{"slug":"leonardo-petrucci","highlight":"@creativiii\n","content":"\n[@creativiii](https://twitter.com/creativiii)\n","data":{"name":"Leonardo Petrucci","avatar":"/images/leonardo-petrucci.jpg"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    a: \"a\"\n  }, _provideComponents(), props.components);\n  return _jsx(_components.p, {\n    children: _jsx(_components.a, {\n      href: \"https://twitter.com/creativiii\",\n      children: \"@creativiii\"\n    })\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},"date":"2022-09-12T09:15:36.648Z","thumbnail":"/images/frame-139-1-.png","description":"Markdown can be an incredibly powerful tool, but a lot of content can start slowing down your site. This is a quick guide on how you can mitigate these issues with a static API and ISR.","published":true},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    a: \"a\",\n    strong: \"strong\",\n    img: \"img\",\n    h2: \"h2\",\n    ul: \"ul\",\n    li: \"li\",\n    code: \"code\",\n    pre: \"pre\",\n    span: \"span\",\n    em: \"em\"\n  }, _provideComponents(), props.components), {Notice} = _components;\n  if (!Notice) _missingMdxReference(\"Notice\", true);\n  return _jsxs(_Fragment, {\n    children: [_jsxs(_components.p, {\n      children: [\"I've previously talked about \", _jsx(_components.a, {\n        href: \"https://ironeko.com/posts/how-to-read-markdown-files-from-next-js-api-routes\",\n        children: \"how to read markdown files from Next.js' API routes\"\n      }), \". However, it was only recently, while improving some of my blog's logic, that I realised the true value of this technique. So here's a simple guide on how to create an incredibly powerful content API from your Markdown files and \", _jsx(_components.strong, {\n        children: \"double your build speed\"\n      }), \" while you're at it.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-139-1-.png\",\n        alt: \"Hero image with the text \\\"Speed up your static generation with a Next.js markdown API and ISR\\\"\",\n        width: \"1200\",\n        height: \"630\"\n      })\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"The setup\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Before you can actually get started turning your markdown files into an API, you'll need these files in an easily readable and parsable format. I would recommend following my explanation on how to \", _jsx(_components.a, {\n        href: \"https://ironeko.com/posts/how-to-read-markdown-files-from-next-js-api-routes#how-to-work-around-nextjs-api-filesystem-limitations\",\n        children: \"transform your markdown to JSON at build time\"\n      }), \" but really any way to get your markdown into JSON will probably work.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"You'll need your different categories of content each in a JSON file with each element being part of a larger array. For example I had:\"\n    }), \"\\n\", _jsxs(_components.ul, {\n      children: [\"\\n\", _jsx(_components.li, {\n        children: _jsx(_components.code, {\n          children: \"posts.json\"\n        })\n      }), \"\\n\", _jsx(_components.li, {\n        children: _jsx(_components.code, {\n          children: \"authors.json\"\n        })\n      }), \"\\n\", _jsx(_components.li, {\n        children: _jsx(_components.code, {\n          children: \"categories.json\"\n        })\n      }), \"\\n\"]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Creating your API endpoints\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Let's create endpoints to fetch our posts as an example.\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-javascript\",\n      children: _jsxs(_components.code, {\n        className: \"language-javascript\",\n        children: [_jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// pages/api/posts/index.js\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// You'll need to specify the absolute URL to fetch your file\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" url \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token template-string\",\n          children: [_jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          }), _jsx(_components.span, {\n            className: \"token string\",\n            children: \"http://example.com\"\n          }), _jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          })]\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token doc-comment comment\",\n          children: \"/**\\n * fetches and returns all posts from json cache\\n */\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: \"getAllPosts\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" data \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"fetch\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsxs(_components.span, {\n          className: \"token template-string\",\n          children: [_jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          }), _jsxs(_components.span, {\n            className: \"token interpolation\",\n            children: [_jsx(_components.span, {\n              className: \"token interpolation-punctuation punctuation\",\n              children: \"${\"\n            }), \"url\", _jsx(_components.span, {\n              className: \"token interpolation-punctuation punctuation\",\n              children: \"}\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token string\",\n            children: \"/cache/posts.json\"\n          }), _jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"then\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"res\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \"\\n        res\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"json\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" data\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token doc-comment comment\",\n          children: \"/**\\n * Returns current page from query string. If undefined, returns 0.\\n */\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: \"pagination\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"req\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \" page \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'0'\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" req\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"query\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"as\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"page\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" string \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" actualPage \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"parseInt\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"page\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"<=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token number\",\n          children: \"0\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"?\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token number\",\n          children: \"1\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"parseInt\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"page\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" actualPage\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token doc-comment comment\",\n          children: \"/**\\n * Returns a list of paginated posts\\n */\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: \"posts\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsxs(_components.span, {\n          className: \"token parameter\",\n          children: [\"req\", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \",\"\n          }), \" res\"]\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" page \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"pagination\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"req\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" data \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"getAllPosts\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// sort posts by publish date\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"sort\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsxs(_components.span, {\n          className: \"token parameter\",\n          children: [\"post1\", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \",\"\n          }), \" post2\"]\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"post1\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"data\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"date\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \">\"\n        }), \" post2\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"data\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"date\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"?\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"-\"\n        }), _jsx(_components.span, {\n          className: \"token number\",\n          children: \"1\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token number\",\n          children: \"1\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// only take 10 depending on page value\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"slice\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"page \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"-\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token number\",\n          children: \"1\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"*\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token number\",\n          children: \"10\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \" page \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"*\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token number\",\n          children: \"10\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n    res\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"status\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token number\",\n          children: \"200\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"json\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"data\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"default\"\n        }), \" posts\\n\"]\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"It's fairly straightforward since we don't need to do a whole lot apart from return our entire JSON file. Nonetheless, we \", _jsx(_components.em, {\n        children: \"can\"\n      }), \" implement small UX improvements.\"]\n    }), \"\\n\", _jsxs(_components.ul, {\n      children: [\"\\n\", _jsxs(_components.li, {\n        children: [\"On line \", _jsx(_components.code, {\n          children: \"32\"\n        }), \" we sort our content by publishing date\"]\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"We paginate all of our content, so we don't have to repeat the code in our pages\"\n      }), \"\\n\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"You can check out how \", _jsx(_components.a, {\n        href: \"https://ironeko.com/api/posts\",\n        children: \"Ironeko's endpoint looks as an example\"\n      }), \".\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"The second piece of the puzzle is to then create an endpoint used just to return one singular piece of content. We'll use it to actually create our pages.\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-javascript\",\n      children: _jsxs(_components.code, {\n        className: \"language-javascript\",\n        children: [_jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// pages/api/posts/[slug].js\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// You'll need to specify the absolute URL to fetch your file\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" url \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token template-string\",\n          children: [_jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          }), _jsx(_components.span, {\n            className: \"token string\",\n            children: \"http://example.com\"\n          }), _jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          })]\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token doc-comment comment\",\n          children: \"/**\\n * fetches and returns all posts from json cache\\n */\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: \"getAllPosts\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" data \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"fetch\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsxs(_components.span, {\n          className: \"token template-string\",\n          children: [_jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          }), _jsxs(_components.span, {\n            className: \"token interpolation\",\n            children: [_jsx(_components.span, {\n              className: \"token interpolation-punctuation punctuation\",\n              children: \"${\"\n            }), \"url\", _jsx(_components.span, {\n              className: \"token interpolation-punctuation punctuation\",\n              children: \"}\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token string\",\n            children: \"/cache/posts.json\"\n          }), _jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"then\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"res\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \"\\n        res\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"json\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" data\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token doc-comment comment\",\n          children: \"/**\\n * Finds and returns a single post\\n */\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: \"post\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsxs(_components.span, {\n          className: \"token parameter\",\n          children: [\"req\", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \",\"\n          }), \" res\"]\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \" slug \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" req\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"query\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" data \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"getAllPosts\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"find\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"p\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" p\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"slug\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"===\"\n        }), \" slug\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"if\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"data\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n        res\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"status\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token number\",\n          children: \"200\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"json\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"data\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"else\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n        res\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"status\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token number\",\n          children: \"404\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n        res\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"end\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"default\"\n        }), \" post\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"The above is very similar to our endpoint, only with some minor differences:\"\n    }), \"\\n\", _jsxs(_components.ul, {\n      children: [\"\\n\", _jsxs(_components.li, {\n        children: [\"\\n\", _jsxs(_components.p, {\n          children: [\"We filter our data to find a post that matches the \", _jsx(_components.code, {\n            children: \"slug\"\n          }), \" provided in the API url\"]\n        }), \"\\n\", _jsxs(_components.ul, {\n          children: [\"\\n\", _jsxs(_components.li, {\n            children: [\"A \", _jsx(_components.code, {\n              children: \"slug\"\n            }), \" is a unique piece of text that identifies our article. For example you can see the slug for this page in the URL \", _jsx(_components.code, {\n              children: \"how-to-create-an-api-from-markdown-files-with-next-js\"\n            })]\n          }), \"\\n\"]\n        }), \"\\n\"]\n      }), \"\\n\", _jsxs(_components.li, {\n        children: [\"\\n\", _jsx(_components.p, {\n          children: \"If we couldn't find a match in our data we return a 404 error, which we'll then handle when trying to display the page\"\n        }), \"\\n\"]\n      }), \"\\n\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"If you've done it right it'll look something like \", _jsx(_components.a, {\n        href: \"https://ironeko.com/api/posts/how-to-create-an-api-from-markdown-files-with-next-js\",\n        children: \"the endpoint we use here on Ironeko\"\n      }), \".\"]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Combining your new endpoints with Next.js' ISR to improve your build time\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"If you've managed a static site before you'll no doubt have noticed how \", _jsx(_components.strong, {\n        children: \"each time a new piece of content is added your builds take a little bit longer\"\n      }), \". This blog has just over 100 articles, and the build time has slowly crawled to around 3 minutes... Every. Time. I. Edit. Something.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Y﻿ou may have heard of \", _jsx(_components.strong, {\n        children: \"Incremental Static Regeneration\"\n      }), \" before. (If not, Smashing Magazine published the fantastic \", _jsx(_components.a, {\n        href: \"https://www.smashingmagazine.com/2021/04/incremental-static-regeneration-nextjs/\",\n        children: \"A Complete Guide To Incremental Static Regeneration (ISR) With Next.js\"\n      }), \" which is an excellent explanation of the feature.)\"]\n    }), \"\\n\", _jsx(Notice, {\n      children: _jsx(_components.p, {\n        children: \"There's a lot of magic related to how Incremental Static Regeneration works, but it's a fantastic feature and you don't necessarily need to understand how it functions to use it to its full potential.\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"The point of ISR is that rather than telling Next.js how many pages you want to generate at build time, you'll just have to tell it where to get the information to generate them. The pages will then be generated upon request.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Thanks to your new endpoint you can replace your \", _jsx(_components.code, {\n        children: \"getStaticProps\"\n      }), \" and \", _jsx(_components.code, {\n        children: \"getStaticPaths\"\n      }), \" with a much simpler:\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-javascript\",\n      children: _jsxs(_components.code, {\n        className: \"language-javascript\",\n        children: [_jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// pages/posts/[slug].js\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// You'll need to specify the absolute URL to fetch your file\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" url \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token template-string\",\n          children: [_jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          }), _jsx(_components.span, {\n            className: \"token string\",\n            children: \"http://example.com\"\n          }), _jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          })]\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: \"getStaticPaths\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"paths\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"fallback\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'blocking'\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: \"getStaticProps\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsxs(_components.span, {\n          className: \"token parameter\",\n          children: [_jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"{\"\n          }), \" params \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"}\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \" slug \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" params\\n\\n    \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" post \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"fetch\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsxs(_components.span, {\n          className: \"token template-string\",\n          children: [_jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          }), _jsxs(_components.span, {\n            className: \"token interpolation\",\n            children: [_jsx(_components.span, {\n              className: \"token interpolation-punctuation punctuation\",\n              children: \"${\"\n            }), \"url\", _jsx(_components.span, {\n              className: \"token interpolation-punctuation punctuation\",\n              children: \"}\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token string\",\n            children: \"/api/posts/\"\n          }), _jsxs(_components.span, {\n            className: \"token interpolation\",\n            children: [_jsx(_components.span, {\n              className: \"token interpolation-punctuation punctuation\",\n              children: \"${\"\n            }), \"slug\", _jsx(_components.span, {\n              className: \"token interpolation-punctuation punctuation\",\n              children: \"}\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token template-punctuation string\",\n            children: \"`\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"then\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"res\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" res\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"json\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"catch\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword null nil\",\n          children: \"null\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n\\n    \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"if\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"!\"\n        }), \"post\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n            \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"notFound\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token boolean\",\n          children: \"true\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\\n    \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"props\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n            post\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n        \", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"revalidate\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token number\",\n          children: \"60\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n    \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"You should see your build time cut down exponentially depending on how much content you have!\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Bonus: Serialize your markdown (or mdx) on build\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Ideally with these changes you'll want to keep your serverless function execution time as short as possible (especially if you're on a Vercel Hobby plan). So there's a couple more corners you can cut.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"If you're using markdown or mdx you can actually serialize your markdown into a usable string outside of your \", _jsx(_components.code, {\n        children: \"getStaticProps\"\n      }), \". When generating your caches, rather than adding your markdown to your cache you can convert it directly to HTML or JSX so you won't have to convert it later while generating your page!\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-javascript\",\n      children: _jsxs(_components.code, {\n        className: \"language-javascript\",\n        children: [_jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// use this wherever you transform your markdown into JSON\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token imports\",\n          children: \"matter\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'gray-matter'\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token imports\",\n          children: [_jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"{\"\n          }), \" serialize \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"}\"\n          })]\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'next-mdx-remote/serialize'\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token imports\",\n          children: [_jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"{\"\n          }), \" remark \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"}\"\n          })]\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'remark'\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"import\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token imports\",\n          children: \"html\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"from\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'remark-html'\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token doc-comment comment\",\n          children: \"/**\\n * Convert a markdown file to JSON\\n */\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function-variable function\",\n          children: \"serializeMarkdown\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"async\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token parameter\",\n          children: \"markdownFile\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token arrow operator\",\n          children: \"=>\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// we extract the front-matter info from our markdown\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" matterResult \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"matter\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"markdownFile\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n  \\n  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// convert the markdown body into HTML\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" html \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"remark\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"use\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"html\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token method function property-access\",\n          children: \"processSync\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"matterResult\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"content\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n  \\n  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// or generate a JSX string from your MDX!\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"const\"\n        }), \" mdx \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"await\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"serialize\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"matterResult\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \".\"\n        }), _jsx(_components.span, {\n          className: \"token property-access\",\n          children: \"content\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n\\n  \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n      html\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n      mdx\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n      \", _jsx(_components.span, {\n          className: \"token spread operator\",\n          children: \"...\"\n        }), \"matterResult\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"With these small changes Ironeko's build time dropped to around 40 seconds. This has improved my quality of life considerably, so you should definitely give it a try if you're falling out of love with static generation.\"\n    })]\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\nfunction _missingMdxReference(id, component) {\n  throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");\n}\n","frontmatter":{},"scope":{}}},{"slug":"next-js-vs-create-react-app-your-choice-going-into-2023","highlight":"According to the 2022 Stack Overflow survey, React has finally surpassed jQuery as the most used web framework. So while React undoubtedly still has a bright future ahead of it, a few questions remain unanswered with regards to how to best use React. One of the most popular debates is whether you should use Next.js vs Create React App, so here are my thoughts on the argument.\n\nWhy do we need Next.js and Create React App?\n","content":"According to the 2022 Stack Overflow survey, [React has finally surpassed jQuery as the most used web framework](https://insights.stackoverflow.com/survey/2021#section-most-popular-technologies-web-frameworks). So while React undoubtedly still has a bright future ahead of it, a few questions remain unanswered with regards to how to best *use* React. One of the most popular debates is whether you should use Next.js vs Create React App, so here are my thoughts on the argument.\n\n![](/images/frame-138.png)\n\n## Why do we need Next.js and Create React App?\n\nNext.js and Create React App serve largely the same purpose. At their core they're pre-configured, easy-to-use frameworks to get started with React. Of course Next.js has since exceeded this functionality and now offers much, much more but today we'll be just looking at them as \"ways to get started\" with React.\n\nAs far as I understand it, pre-2016 React development required in-depth knowledge of bundlers and Webpack to even get started. **Create React App was a huge shift in accessibility** to React since it allowed virtually *anyone* with terminal access to start up a React app with a single command. \n\nCreate React App's strength, and what would also become it's biggest annoyance, **was the lack of configuration**. Users weren't asked to mess with complex bundling tools they didn't understand and could just get started.\n\n## The strengths and weaknesses of Create React App\n\nThere's a lot to say about Create React App, but you shouldn't just take my word for it. In this part of the article I'll be referencing a recent comment made by Dan Abramov (co-creator of CRA).\n\nYou can read this post in full at the [facebook/create-react-app github repository: We need CRA maintainers](https://github.com/facebook/create-react-app/issues/11180#issuecomment-874748552). It's a very interesting read into the current state of React and Create React App. I'll break it down (and what it means) here.\n\n### Configuration, or the lack thereof\n\n> \\[Create React App] was intentionally minimal and limited in scope (no configuration, no plugin system) for two reasons. One reason was that, the more feature-rich it is, the harder upgrades will be. The other reason was, I knew that React itself will take a vast majority of our time, and I won't be able to dedicate more than a few weeks sporadically to CRA every now and then.\n\nCreate React App is simple, and that's the way it was designed. It was more out of necessity than anything else, but with the evolution of the React ecosystem this has slowly become somewhat of a problem. For example, up until [the recent Create React App 5.0 release](https://github.com/facebook/create-react-app/releases/tag/v5.0.0), there was no official way of installing TailwindCSS. This meant that on top of installing Create React App, many developers had to resort to installing tools like [Craco, which allow users to add extra configurations](https://github.com/gsoft-inc/craco) for both Webpack and Babel.\n\n### Caching and building\n\nUnlike Next.js, **Create React App has no built-in caching**. Next.js keeps a local cache on the filesystem each time the app is started in development or built, which is *extremely* useful in cases where Continuous Integration is used since an automated pipeline is able to check if any files have been changed and decide to skip building them again altogether.\n\nFor small projects this won't make much of a difference. However, the larger your project becomes the more you'll be looking to shave off precious minutes from your build times.\n\nAs Dan Abramov observes:\n\n> \\[Create React App] is a tool to get started and get something running fast. Perhaps, it's not even best at that anymore.\n\nThe issues with CRA become apparent as a project grows in size.\n\n### Create React App is in \"maintenance mode\"\n\n> We would get critical fixes out as soon as possible, but overall, starting with 2.0, \\[Create React App is] mostly in maintenance mode and does not strive to be the best tool for production React apps.\n\nWhile a tool being in maintenance mode isn't usually a major red-flag, in the case of the Javascript ecosystem this can become a problem very quickly. **Javascript moves fast, and with so many competitor tools constantly improving their speed and feature support being in maintenance only is obviously an issue.**\n\nCRA likely will never have support for [Server Components](https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html), and it's unlikely the speed at which projects are built will improve.\n\n### Create React App's nested routes are still very powerful\n\nThe one argument in favor of CRA I see over and over is about it's nested route structure. If you're unfamiliar with nested routes, this is the practice of creating routes within routes. This is a very useful pattern in React as it can make heavy use of [React Context and hooks](https://ironeko.com/posts/an-easier-way-to-use-reacts-usecontext-hook).\n\nFor example, the page `/user/settings` could be a nested route of `/user`, and still have access to the user page's data via a context provider. Nested routes are also incredibly useful for protecting certain routes. Simply make the highest route inaccessible and all its children will also be.\n\nIn general I find **it keeps code cleaner**. It also makes app logic much easier to comprehend.\n\nUnfortunatelythe downside to thisis that **nested routes are easily replicable in Next.js**, and many other React starters also offer the same functionality.\n\n## Create React App's pros and cons\n\nHere's a roundup of what's written above and some other thoughts:\n\n<List type=\"tick\">\n\n\n\n\n* Fastest way of starting a React app with the best \"one size fits all\" defaults\n* Standardised configuration means easier to troubleshoot errors and finding help online\n* Designed to be easy to maintain\n\n\n\n\n</List>\n        \n\n<List type=\"cross\">\n\n\n* Impossible to configure without external packages\n* Has been in maintenance mode for years and will probably continue to be for the foreseeable future\n* As projects increase in size, build time and development times increase drastically\n* Many alternatives that do essentially the same thing\n\n\n</List>\n        \n\n## The strengths and weaknesses of Next.js\n\nNext.js is the king of React websites: it's versatile, easy to configure and built from the ground up to statically export pages. This leads people to believe it's not well versed for building one page applications. *(Spoiler: this couldn't be further from the truth!)*\n\n### Easy to get started\n\nOne of the best things about Next.js is just how quick it is to get started. Unlike Create React App, **Next is an all-in-one package**. \n\n* Routing is built in (although rudimentary)\n* A component that wraps your app is easily accessible\n* It doesn't require a separate package to inject tags into `<head>`\n* It comes with the `<Image>` component, which honestly deservers an entire article by itself\n\n### Setting up nested routing requires some Next.js know-how\n\nWhile Next.js is not intended to be used with nested routes, it's definitely possible to implement it... Although this does require understanding how Next.js' routing functions, which can be quite annoying.\n\nOne of my favorite examples of this is Max Lynch's (Ionic's CEO) take on using Next.js as an app native front-end solution. The ingenious solution, which you can check out at [mlynch/nextjs-tailwind-ionic-capacitor-starter on Github](https://github.com/mlynch/nextjs-tailwind-ionic-capacitor-starter/blob/main/pages/%5B...all%5D.js), relies on creating catch-all routes, and then redirecting them to a [component that handles routing client-side](https://github.com/mlynch/nextjs-tailwind-ionic-capacitor-starter/blob/main/components/AppShell.jsx).\n\nThis makes Next.js compatible with any of your favorite React routers: `react-router`, `ionic-router`, `wouter` and many more.\n\n### Actively developed, maintained and funded\n\nIt's difficult to argue for Next.js without also mentioning that it's at the centre of Vercel's business. And the [$150M funding they've received to develop Next.js further](https://vercel.com/blog/vercel-funding-series-d-and-valuation) is even harder to ignore.\n\nQuite a stark difference compared to Create React App, which is just in maintenance mode, without new features planned for it.\n\n## Next.js' pros and cons\n\nHere's a roundup of what we've mentioned (and some extras so far)\n\n<List type=\"tick\">\n\n\n* All-in-one platform, including many core components\n* Built to be configurable, with direct access to Webpack's internals\n* **So much more than just a front-end**, it includes static generation functionality and even built-in API routes\n* Fast and actively maintained by a seed-funded company\n\n\n</List>\n        \n\n<List type=\"cross\">\n\n\n\n* Can be a bit difficult for beginners to understand because of all the extra functionality\n* Requires know-how of its inner-workings before things like nested routes can be set-up\n\n\n\n</List>\n        \n\n## Final thoughts\n\nFor me, there's no doubt Next.js is probably the wisest choice if you're just starting out with React. Sure, it might take some extended reading to understand *everything* Next.js has to offer, but most of it is entirely optional.\n\nIn fact, you can use Next.js as a beginner just as well as you can use Create React App. Its strengths lie in the possibility of being able to do so much more with it.\n\nThe discourse isn't obviously just about Next.js vs Create React App, however. This year **we've also seen [Vite.js React](https://www.npmjs.com/package/@vitejs/plugin-react) and [Remix](https://remix.run/) jump into the fray**. These two are great topics in and of themselves and probably deserve their own articles. \n\nAll in all, the great thing is that whatever choice you make, you'll almost never be entirely locked in. **Jumping between CRA and Next and Vite has never been easier** so you can (and should) shop around before deciding.\n","data":{"layout":"blog","title":"Next.js VS Create React App: Your choice going into 2023","categories":[{"slug":"react","highlight":"","content":"","data":{"name":"React","visible":true,"description":"How to's and tutorials on our favorite Javascript library."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},{"slug":"technology","highlight":"","content":"","data":{"name":"Technology","visible":true,"description":"Frameworks, libraries, interesting new releases in the world of tech and programming. If this sounds good to you, you’re in the right place."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}}],"author":{"slug":"leonardo-petrucci","highlight":"@creativiii\n","content":"\n[@creativiii](https://twitter.com/creativiii)\n","data":{"name":"Leonardo Petrucci","avatar":"/images/leonardo-petrucci.jpg"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    a: \"a\"\n  }, _provideComponents(), props.components);\n  return _jsx(_components.p, {\n    children: _jsx(_components.a, {\n      href: \"https://twitter.com/creativiii\",\n      children: \"@creativiii\"\n    })\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},"date":"2022-09-04T19:14:58.220Z","thumbnail":"/images/frame-138.png","description":"Should you use Next.js or Create React App for your next project? While both have their strengths there's a lot more to consider than just preference.","yoast_keyword":"Next.js vs Create React App","published":true},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    a: \"a\",\n    em: \"em\",\n    img: \"img\",\n    h2: \"h2\",\n    strong: \"strong\",\n    h3: \"h3\",\n    blockquote: \"blockquote\",\n    code: \"code\",\n    ul: \"ul\",\n    li: \"li\"\n  }, _provideComponents(), props.components), {List} = _components;\n  if (!List) _missingMdxReference(\"List\", true);\n  return _jsxs(_Fragment, {\n    children: [_jsxs(_components.p, {\n      children: [\"According to the 2022 Stack Overflow survey, \", _jsx(_components.a, {\n        href: \"https://insights.stackoverflow.com/survey/2021#section-most-popular-technologies-web-frameworks\",\n        children: \"React has finally surpassed jQuery as the most used web framework\"\n      }), \". So while React undoubtedly still has a bright future ahead of it, a few questions remain unanswered with regards to how to best \", _jsx(_components.em, {\n        children: \"use\"\n      }), \" React. One of the most popular debates is whether you should use Next.js vs Create React App, so here are my thoughts on the argument.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-138.png\",\n        alt: \"\",\n        width: \"1200\",\n        height: \"630\"\n      })\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Why do we need Next.js and Create React App?\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Next.js and Create React App serve largely the same purpose. At their core they're pre-configured, easy-to-use frameworks to get started with React. Of course Next.js has since exceeded this functionality and now offers much, much more but today we'll be just looking at them as \\\"ways to get started\\\" with React.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"As far as I understand it, pre-2016 React development required in-depth knowledge of bundlers and Webpack to even get started. \", _jsx(_components.strong, {\n        children: \"Create React App was a huge shift in accessibility\"\n      }), \" to React since it allowed virtually \", _jsx(_components.em, {\n        children: \"anyone\"\n      }), \" with terminal access to start up a React app with a single command.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Create React App's strength, and what would also become it's biggest annoyance, \", _jsx(_components.strong, {\n        children: \"was the lack of configuration\"\n      }), \". Users weren't asked to mess with complex bundling tools they didn't understand and could just get started.\"]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"The strengths and weaknesses of Create React App\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"There's a lot to say about Create React App, but you shouldn't just take my word for it. In this part of the article I'll be referencing a recent comment made by Dan Abramov (co-creator of CRA).\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"You can read this post in full at the \", _jsx(_components.a, {\n        href: \"https://github.com/facebook/create-react-app/issues/11180#issuecomment-874748552\",\n        children: \"facebook/create-react-app github repository: We need CRA maintainers\"\n      }), \". It's a very interesting read into the current state of React and Create React App. I'll break it down (and what it means) here.\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Configuration, or the lack thereof\"\n    }), \"\\n\", _jsxs(_components.blockquote, {\n      children: [\"\\n\", _jsx(_components.p, {\n        children: \"[Create React App] was intentionally minimal and limited in scope (no configuration, no plugin system) for two reasons. One reason was that, the more feature-rich it is, the harder upgrades will be. The other reason was, I knew that React itself will take a vast majority of our time, and I won't be able to dedicate more than a few weeks sporadically to CRA every now and then.\"\n      }), \"\\n\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Create React App is simple, and that's the way it was designed. It was more out of necessity than anything else, but with the evolution of the React ecosystem this has slowly become somewhat of a problem. For example, up until \", _jsx(_components.a, {\n        href: \"https://github.com/facebook/create-react-app/releases/tag/v5.0.0\",\n        children: \"the recent Create React App 5.0 release\"\n      }), \", there was no official way of installing TailwindCSS. This meant that on top of installing Create React App, many developers had to resort to installing tools like \", _jsx(_components.a, {\n        href: \"https://github.com/gsoft-inc/craco\",\n        children: \"Craco, which allow users to add extra configurations\"\n      }), \" for both Webpack and Babel.\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Caching and building\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Unlike Next.js, \", _jsx(_components.strong, {\n        children: \"Create React App has no built-in caching\"\n      }), \". Next.js keeps a local cache on the filesystem each time the app is started in development or built, which is \", _jsx(_components.em, {\n        children: \"extremely\"\n      }), \" useful in cases where Continuous Integration is used since an automated pipeline is able to check if any files have been changed and decide to skip building them again altogether.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"For small projects this won't make much of a difference. However, the larger your project becomes the more you'll be looking to shave off precious minutes from your build times.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"As Dan Abramov observes:\"\n    }), \"\\n\", _jsxs(_components.blockquote, {\n      children: [\"\\n\", _jsx(_components.p, {\n        children: \"[Create React App] is a tool to get started and get something running fast. Perhaps, it's not even best at that anymore.\"\n      }), \"\\n\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"The issues with CRA become apparent as a project grows in size.\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Create React App is in \\\"maintenance mode\\\"\"\n    }), \"\\n\", _jsxs(_components.blockquote, {\n      children: [\"\\n\", _jsx(_components.p, {\n        children: \"We would get critical fixes out as soon as possible, but overall, starting with 2.0, [Create React App is] mostly in maintenance mode and does not strive to be the best tool for production React apps.\"\n      }), \"\\n\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"While a tool being in maintenance mode isn't usually a major red-flag, in the case of the Javascript ecosystem this can become a problem very quickly. \", _jsx(_components.strong, {\n        children: \"Javascript moves fast, and with so many competitor tools constantly improving their speed and feature support being in maintenance only is obviously an issue.\"\n      })]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"CRA likely will never have support for \", _jsx(_components.a, {\n        href: \"https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html\",\n        children: \"Server Components\"\n      }), \", and it's unlikely the speed at which projects are built will improve.\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Create React App's nested routes are still very powerful\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"The one argument in favor of CRA I see over and over is about it's nested route structure. If you're unfamiliar with nested routes, this is the practice of creating routes within routes. This is a very useful pattern in React as it can make heavy use of \", _jsx(_components.a, {\n        href: \"https://ironeko.com/posts/an-easier-way-to-use-reacts-usecontext-hook\",\n        children: \"React Context and hooks\"\n      }), \".\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"For example, the page \", _jsx(_components.code, {\n        children: \"/user/settings\"\n      }), \" could be a nested route of \", _jsx(_components.code, {\n        children: \"/user\"\n      }), \", and still have access to the user page's data via a context provider. Nested routes are also incredibly useful for protecting certain routes. Simply make the highest route inaccessible and all its children will also be.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"In general I find \", _jsx(_components.strong, {\n        children: \"it keeps code cleaner\"\n      }), \". It also makes app logic much easier to comprehend.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Unfortunatelythe downside to thisis that \", _jsx(_components.strong, {\n        children: \"nested routes are easily replicable in Next.js\"\n      }), \", and many other React starters also offer the same functionality.\"]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Create React App's pros and cons\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Here's a roundup of what's written above and some other thoughts:\"\n    }), \"\\n\", _jsx(List, {\n      type: \"tick\",\n      children: _jsxs(_components.ul, {\n        children: [\"\\n\", _jsx(_components.li, {\n          children: \"Fastest way of starting a React app with the best \\\"one size fits all\\\" defaults\"\n        }), \"\\n\", _jsx(_components.li, {\n          children: \"Standardised configuration means easier to troubleshoot errors and finding help online\"\n        }), \"\\n\", _jsx(_components.li, {\n          children: \"Designed to be easy to maintain\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(List, {\n      type: \"cross\",\n      children: _jsxs(_components.ul, {\n        children: [\"\\n\", _jsx(_components.li, {\n          children: \"Impossible to configure without external packages\"\n        }), \"\\n\", _jsx(_components.li, {\n          children: \"Has been in maintenance mode for years and will probably continue to be for the foreseeable future\"\n        }), \"\\n\", _jsx(_components.li, {\n          children: \"As projects increase in size, build time and development times increase drastically\"\n        }), \"\\n\", _jsx(_components.li, {\n          children: \"Many alternatives that do essentially the same thing\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"The strengths and weaknesses of Next.js\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Next.js is the king of React websites: it's versatile, easy to configure and built from the ground up to statically export pages. This leads people to believe it's not well versed for building one page applications. \", _jsx(_components.em, {\n        children: \"(Spoiler: this couldn't be further from the truth!)\"\n      })]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Easy to get started\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"One of the best things about Next.js is just how quick it is to get started. Unlike Create React App, \", _jsx(_components.strong, {\n        children: \"Next is an all-in-one package\"\n      }), \".\"]\n    }), \"\\n\", _jsxs(_components.ul, {\n      children: [\"\\n\", _jsx(_components.li, {\n        children: \"Routing is built in (although rudimentary)\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"A component that wraps your app is easily accessible\"\n      }), \"\\n\", _jsxs(_components.li, {\n        children: [\"It doesn't require a separate package to inject tags into \", _jsx(_components.code, {\n          children: \"<head>\"\n        })]\n      }), \"\\n\", _jsxs(_components.li, {\n        children: [\"It comes with the \", _jsx(_components.code, {\n          children: \"<Image>\"\n        }), \" component, which honestly deservers an entire article by itself\"]\n      }), \"\\n\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Setting up nested routing requires some Next.js know-how\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"While Next.js is not intended to be used with nested routes, it's definitely possible to implement it... Although this does require understanding how Next.js' routing functions, which can be quite annoying.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"One of my favorite examples of this is Max Lynch's (Ionic's CEO) take on using Next.js as an app native front-end solution. The ingenious solution, which you can check out at \", _jsx(_components.a, {\n        href: \"https://github.com/mlynch/nextjs-tailwind-ionic-capacitor-starter/blob/main/pages/%5B...all%5D.js\",\n        children: \"mlynch/nextjs-tailwind-ionic-capacitor-starter on Github\"\n      }), \", relies on creating catch-all routes, and then redirecting them to a \", _jsx(_components.a, {\n        href: \"https://github.com/mlynch/nextjs-tailwind-ionic-capacitor-starter/blob/main/components/AppShell.jsx\",\n        children: \"component that handles routing client-side\"\n      }), \".\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"This makes Next.js compatible with any of your favorite React routers: \", _jsx(_components.code, {\n        children: \"react-router\"\n      }), \", \", _jsx(_components.code, {\n        children: \"ionic-router\"\n      }), \", \", _jsx(_components.code, {\n        children: \"wouter\"\n      }), \" and many more.\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Actively developed, maintained and funded\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"It's difficult to argue for Next.js without also mentioning that it's at the centre of Vercel's business. And the \", _jsx(_components.a, {\n        href: \"https://vercel.com/blog/vercel-funding-series-d-and-valuation\",\n        children: \"$150M funding they've received to develop Next.js further\"\n      }), \" is even harder to ignore.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Quite a stark difference compared to Create React App, which is just in maintenance mode, without new features planned for it.\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Next.js' pros and cons\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Here's a roundup of what we've mentioned (and some extras so far)\"\n    }), \"\\n\", _jsx(List, {\n      type: \"tick\",\n      children: _jsxs(_components.ul, {\n        children: [\"\\n\", _jsx(_components.li, {\n          children: \"All-in-one platform, including many core components\"\n        }), \"\\n\", _jsx(_components.li, {\n          children: \"Built to be configurable, with direct access to Webpack's internals\"\n        }), \"\\n\", _jsxs(_components.li, {\n          children: [_jsx(_components.strong, {\n            children: \"So much more than just a front-end\"\n          }), \", it includes static generation functionality and even built-in API routes\"]\n        }), \"\\n\", _jsx(_components.li, {\n          children: \"Fast and actively maintained by a seed-funded company\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(List, {\n      type: \"cross\",\n      children: _jsxs(_components.ul, {\n        children: [\"\\n\", _jsx(_components.li, {\n          children: \"Can be a bit difficult for beginners to understand because of all the extra functionality\"\n        }), \"\\n\", _jsx(_components.li, {\n          children: \"Requires know-how of its inner-workings before things like nested routes can be set-up\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Final thoughts\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"For me, there's no doubt Next.js is probably the wisest choice if you're just starting out with React. Sure, it might take some extended reading to understand \", _jsx(_components.em, {\n        children: \"everything\"\n      }), \" Next.js has to offer, but most of it is entirely optional.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"In fact, you can use Next.js as a beginner just as well as you can use Create React App. Its strengths lie in the possibility of being able to do so much more with it.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"The discourse isn't obviously just about Next.js vs Create React App, however. This year \", _jsxs(_components.strong, {\n        children: [\"we've also seen \", _jsx(_components.a, {\n          href: \"https://www.npmjs.com/package/@vitejs/plugin-react\",\n          children: \"Vite.js React\"\n        }), \" and \", _jsx(_components.a, {\n          href: \"https://remix.run/\",\n          children: \"Remix\"\n        }), \" jump into the fray\"]\n      }), \". These two are great topics in and of themselves and probably deserve their own articles.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"All in all, the great thing is that whatever choice you make, you'll almost never be entirely locked in. \", _jsx(_components.strong, {\n        children: \"Jumping between CRA and Next and Vite has never been easier\"\n      }), \" so you can (and should) shop around before deciding.\"]\n    })]\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\nfunction _missingMdxReference(id, component) {\n  throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");\n}\n","frontmatter":{},"scope":{}}},{"slug":"github-highlight-planner-app-by-brian-vaughn","highlight":"New York based React developer Brian Vaughn has been showing off an open source planner app on Twitter. And as projects go, it's definitely one to watch in 2022.\nWhat's particularly impressive is how it displays information intuitively, allowing the user to visualise dependencies and durations of events in a clear and linear manner.\nIt's a nice change from traditional calendar layouts, which not everyone finds visually pleasing or helpful. While a calendar layout disrupts the duration ","content":"New York based React developer Brian Vaughn has been showing off an open source planner app on [Twitter](https://twitter.com/brian_d_vaughn/status/1476267825102786566). And as projects go, it's definitely one to watch in 2022.\n\n<Tweet id=\"1476267825102786566\" />\n\nWhat's particularly impressive is how it displays information intuitively, **allowing the user to visualise dependencies and durations of events in a clear and linear manner**. \n\nIt's a nice change from traditional calendar layouts, which not everyone finds visually pleasing or helpful. While a calendar layout disrupts the duration of events which span from one month to the other, **here one can scan a long period of time in which the events themselves, not the calendar months, are the focal point.**\n\n![](/images/brian-vaughn-planner-output.gif)\n\nThis makes for something much closer to the way many of us think about time and scheduling in our heads. In fact it could be particularly helpful for people with conditions, such as dyspraxia, which make planning and time management difficult.\n\nThanks to an html Canvas, **the planner is updated in real time**, evolving immediately with Vaughn's edits. This is quite a feat for such a complex collection of data.\n\nVaughn seems to be planning on turning this demo into a fully fleshed out planner app. As of right now he's yet to share more information, but it's looking very promising.\n\nInterested? Go check out the ongoing project on **Vaughn's [Github](https://github.com/bvaughn/planner)** as well as [Vaughn's personal website](http://www.briandavidvaughn.com/#/home).\n","data":{"layout":"blog","title":"Feature - Planner App by Brian Vaughn ","categories":[{"slug":"open-source","highlight":"","content":"","data":{"name":"Open Source","visible":true,"description":"Handpicked highlights of ongoing open source projects and Github gems worth keeping an eye on!"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},{"slug":"feature","highlight":"","content":"","data":{"name":"Feature","visible":false,"description":"Products, libraries, interfaces from some incredible creators we think you should be aware of."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}}],"author":{"slug":"evie-dillon-riley","highlight":"Writer, editor &amp; translator (IT-ENG)\n","content":"\nWriter, editor & translator (IT-ENG)\n","data":{"name":"Evie Dillon-Riley","avatar":"/images/image-6.jpg"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\"\n  }, _provideComponents(), props.components);\n  return _jsx(_components.p, {\n    children: \"Writer, editor & translator (IT-ENG)\"\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},"date":"2022-01-04T11:02:27.628Z","thumbnail":"/images/frame-136.png","description":"Brian Vaughn's open source planner app is one of the ongoing projects worth keeping an eye on in 2022.","published":true},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    a: \"a\",\n    strong: \"strong\",\n    img: \"img\"\n  }, _provideComponents(), props.components), {Tweet} = _components;\n  if (!Tweet) _missingMdxReference(\"Tweet\", true);\n  return _jsxs(_Fragment, {\n    children: [_jsxs(_components.p, {\n      children: [\"New York based React developer Brian Vaughn has been showing off an open source planner app on \", _jsx(_components.a, {\n        href: \"https://twitter.com/brian_d_vaughn/status/1476267825102786566\",\n        children: \"Twitter\"\n      }), \". And as projects go, it's definitely one to watch in 2022.\"]\n    }), \"\\n\", _jsx(Tweet, {\n      id: \"1476267825102786566\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"What's particularly impressive is how it displays information intuitively, \", _jsx(_components.strong, {\n        children: \"allowing the user to visualise dependencies and durations of events in a clear and linear manner\"\n      }), \".\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"It's a nice change from traditional calendar layouts, which not everyone finds visually pleasing or helpful. While a calendar layout disrupts the duration of events which span from one month to the other, \", _jsx(_components.strong, {\n        children: \"here one can scan a long period of time in which the events themselves, not the calendar months, are the focal point.\"\n      })]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/brian-vaughn-planner-output.gif\",\n        alt: \"\",\n        width: \"774\",\n        height: \"720\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"This makes for something much closer to the way many of us think about time and scheduling in our heads. In fact it could be particularly helpful for people with conditions, such as dyspraxia, which make planning and time management difficult.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Thanks to an html Canvas, \", _jsx(_components.strong, {\n        children: \"the planner is updated in real time\"\n      }), \", evolving immediately with Vaughn's edits. This is quite a feat for such a complex collection of data.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Vaughn seems to be planning on turning this demo into a fully fleshed out planner app. As of right now he's yet to share more information, but it's looking very promising.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Interested? Go check out the ongoing project on \", _jsxs(_components.strong, {\n        children: [\"Vaughn's \", _jsx(_components.a, {\n          href: \"https://github.com/bvaughn/planner\",\n          children: \"Github\"\n        })]\n      }), \" as well as \", _jsx(_components.a, {\n        href: \"http://www.briandavidvaughn.com/#/home\",\n        children: \"Vaughn's personal website\"\n      }), \".\"]\n    })]\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\nfunction _missingMdxReference(id, component) {\n  throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");\n}\n","frontmatter":{},"scope":{}}},{"slug":"how-to-set-up-a-modern-terminal-for-developers","highlight":"If you're a web developer, you probably spend a whole lot of time in your terminal. But, despite how fundamental terminals are for modern web development, they're incredibly minimal and limited with often quite bad UX.\nThat's why I've spent no less than a couple of years perfecting this cross-platform guide to improving your terminal experience. And it's what I use every day for both personal and professional projects, so I know it works. It's by no means perfect, but it should be enough to get you started.\nOnce you're done, your terminal should look something","content":"If you're a web developer, you probably spend a whole lot of time in your terminal. But, despite how fundamental terminals are for modern web development, they're incredibly minimal and limited with often quite bad UX. \n\nThat's why I've spent no less than a couple of years perfecting this **cross-platform guide to improving your terminal experience**. And it's what I use every day for both personal and professional projects, so I know it works. It's by no means perfect, but it should be enough to get you started. \n\nOnce you're done, your terminal should look something like this:\n\n![](/images/final-result-2-.gif)\n\nThis guide has been written specifically with UNIX systems in mind, so **if you're on Windows I recommend installing WSL**.\n\n## Installing ZSH\n\nIf you're on Linux, or if you're using WSL, it's likely your terminal uses Bash by default. Don't get me wrong, Bash is, well, fine. However, switching it out for ZSH will give us access to a bunch of functionality as well as plugins and customisation options.\n\nYou can find installation instructions for ZSH on [the official ZSH git repository](https://github.com/ohmyzsh/ohmyzsh/wiki/Installing-ZSH). Install the correct one for your OS.\n\n<Notice>\n\n\n\n\n\n\n\n\n\n\n\nIf you're on Mac, you're already using ZSH by default, so you can skip this step entirely.\n\n\n\n\n\n\n\n\n\n\n\n</Notice>\n        \n\nAfter installing ZSH, logout and log back in to allow it to complete setup. You might also be met with this configuration screen:\n\n![](/images/zsh.png)\n\nI selected (2) here, which enables some common settings. Once ZSH is initialised you'll notice your prompt looks different. At this point you'll want to move any specific settings from `.bashrc` to `.zshrc`.\n\nZSH will enable some really cool functionality out of the box, such as tabbing auto completion for certain commands like `cd`, `cat`, and `ls`.\n\nThis means that after writing those commands, you will be able to press Tab to autocomplete it with files from the folder you're currently in!\n\n![](/images/tab-completon.png)\n\nConfiguration for ZSH will be done in `~/.zshrc`. This means if you already have special configuration in your `~/.bashrc` (which is likely if you have been using the system for a while) you should copy it into `~/.zshrc`. For example I moved my path for NVM:\n\n```shell\nexport NVM_DIR=\"$HOME/.nvm\"\n\\[ -s \"$NVM_DIR/nvm.sh\" ] && . \"$NVM_DIR/nvm.sh\"  # This loads nvm\n\\[ -s \"$NVM_DIR/bash_completion\" ] && . \"$NVM_DIR/bash_completion\"  # This loads nvm bash_completion\n```\n\n<Notice>\n\n\n\n\nSpecifically look for lines that [add commands to your $PATH](https://opensource.com/article/17/6/set-path-linux), like NVM, NPM, Node, Android Studio and Java.\n\nIf any commands that used to work previously don't work after installing ZSH, you probably just need to copy those config lines from `~/.bashrc` to `~/.zshrc`\n\n\n\n\n</Notice>\n        \n\n## Installing oh my zsh\n\n![](/images/oh-my-zsh.png)\n\nIf ZSH is the foundation of a good terminal, oh my zsh is the frame(work) that will make it your home. oh my zsh is a framework that allows installation and management of hundreds of amazing plugins and themes. It's what will put all the extra functionality to our terminal.\n\nYou can find instructions on how to install it on [oh my zsh's official github repository](https://github.com/ohmyzsh/ohmyzsh#basic-installation).\n\n<Notice>\n\nYou probably won't notice much difference here, but don't worry, we'll come back to this and install plugins for oh my zsh later in the guide.\n\n</Notice>\n        \n\n## Terminal Client\n\nThere are dozens of terminal clients out there, and they all do very similar things. It doesn't *really* matter which one you choose, but **make sure that you can change its font**. I'd also recommend having a good amount of themes to choose from, but that's up to you.\n\nMy recommendation would be [Hyper](https://hyper.is/). It's node based, really customisable and it has plenty of nifty plugins and themes.\n\n![](/images/hyper_h3nosiaogk.png)\n\n## Themes for Hyper\n\nOne of the reasons I like Hyper is because of the incredible amount of themes available for it.\n\nYou can check some themes out at [the Hyper website](https://hyper.is/themes/newest). But my personal favorite is the [poimandres-theme](https://github.com/drcmda/poimandres-theme).\n\n### WSL on Windows\n\nIf you're planning to use Hyper and WSL together there's some extra configuration you probably want to go through.\n\n#### Make Hyper boot into WSL by default\n\nHyper, by default, will boot into the Windows CMD. You can then use the command `wsl` to boot into WSL. This can get annoying, so if you want to boot directly into WSL you can change Hyper configuration. \n\nPress `CTRL+,` to open the config file and make sure that `shell` and `shellArgs` look like this:\n\n```javascript\nshell: 'C:\\\\Windows\\\\System32\\\\wsl.exe',\nshellArgs: [],\n```\n\nSave and exit to apply the settings.\n\n#### Installing Hyper themes in WSL\n\nSome extra setup is required to install and use themes on WSL. Installing themes is usually done with the Hyper CLI. This means that by running `hyper i hyper-pmndrs` the theme would be downloaded and installed.\n\nSince you're running WSL however, Linux won't have any access to the `hyper` command. To fix this run the following command:\n\n```shell\necho \"\\n\\nalias hyper=\"cmd.exe /c hyper\" >> ~/.zshrc && source ~/.zshrc\n```\n\nThe above will add an alias to make the Hyper CLI work. Once done, try installing your theme of choice again and it should work!\n\n## Installing a Nerd Font\n\nNerd Fonts are monospaced fonts with one big difference: they have been patched to include hundreds of symbols. Installing a nerd font will allow us to customise our terminal even further later on.\n\nInstalling a Nerd Font is pretty easy: simply select a font from [Nerd Fonts](https://www.nerdfonts.com/font-downloads). (I'm currently using Fira Code.)\n\n<Notice>\n\n\n\n\n\n\n\n\n\n\n\nDon't install a mono version of the font. This will cause some icons to be much smaller than they should be. Mine was called **FiraCode Nerd Font.**\n\n\n\n\n\n\n\n\n\n\n\n</Notice>\n        \n\n### Windows\n\nWindows requires a specific version of the font. You can identify the correct files since they include `Windows` in their names. You can search for the following in the extracted folder to save yourself some time:\n\n```shell\n<font-name> windows ttf -mono\n```\n\nDon't forget Windows also allows you to install batches of fonts at the same time from its settings.\n\n![](/images/windows-install-fonts.png)\n\n### Linux / Mac\n\nLinux and Mac should be able to support either TTF or OTF. I'm unaware of a quick way of installing multiple fonts on both platforms, so you might have to do this the old fashioned way. Sorry!\n\n## Setting your Nerd Font to your terminal\n\nBefore we go any further, let's actually set the new fonts we've installed so they can be used by our terminal.\n\nI'm going to assume you're currently using Hyper as your terminal, so to change fonts in Hyper you'll need to edit its configuration. With Hyper open press `CTRL + ,` to bring up the config file. If you've done any Javascript development you'll recognise the syntax immediately.\n\nIn your config simply find `fontFamily` and add your new font to the start of the list. The others are all fallbacks in case the previous isn't available. My setting looks something like this:\n\n```javascript\n// font family with optional fallbacks\nfontFamily: 'FiraCode NF, \"DejaVu Sans Mono\", Consolas, \"Lucida Console\", monospace',\n```\n\n<Notice>\n\n\n\n\n\n\n\nMake sure you use the name of the font as it shows up in your font list! On mac this was `FiraCode Nerd Font` for me, so just make sure you're writing the correct name.\n\n\n\n\n\n\n\n</Notice>\n        \n\nYour terminal window should reload as soon as the config is saved, so you should see the new font immediately.\n\n## Improving your prompt with Starship\n\nIf you've been following along, your prompt will look something like this:\n\n![](/images/before-prompt.png)\n\nIt's okay. We get to know the folder we're currently in and if we're inside a `git` folder we can also tell which branch we have selected.\n\nBut what if we could make this even better? That's where [Starship](https://starship.rs/) comes in. It adds a bunch of information to your prompt which you can easily customise. There's tons of utilities like Starship out there, so it's really up to you which one you choose. Feel free to shop around and pick your favorite.\n\n### All OSs\n\nThere's honestly tons of ways to install Starship depending on your OS. So [just follow the installation guide on their documentation](https://starship.rs/guide/#%F0%9F%9A%80-installation).\n\nThen, since we're on ZSH, type the following command in your terminal.\n\n```shell\necho '\\neval \"$(starship init zsh)\"' >> ~/.zshrc && source ~/.zshrc\n```\n\nThis will tell ZSH to use Starship and then reload the ZSH configuration. If you did everything right you'll see a subtle change in your terminal input to something like this:\n\n![](/images/after-prompt.png)\n\n### Customizing Starship\n\nThe great thing about Starship is that it has tons of customisations available. If this sounds interesting to you, run the following command to create a config file:\n\n```shell\nmkdir -p ~/.config && touch ~/.config/starship.toml\n```\n\nThen run this to start editing it:\n\n```shell\nnano ~/.config/starship.toml\n```\n\nSince earlier in the tutorial we installed a Nerd Font, I like to make use of it for most symbols. Feel free to change those symbols to Emojis though if that's more of your thing. My current Starship configuration is as follows:\n\n```toml\n[aws]\nsymbol = \"  \"\n\n[conda]\nsymbol = \" \"\n\n[dart]\nsymbol = \" \"\n\n[directory]\nread_only = \" \"\n\n[docker_context]\nsymbol = \" \"\n\n[elixir]\nsymbol = \" \"\n\n[elm]\nsymbol = \" \"\n\n[git_branch]\nsymbol = \" \"\n\n[git_status]\nformat = \"[$all_status$ahead_behind]($style)\"\nahead = \"⇡ $count \"\nbehind = \"⇣ $count \"\ndeleted = \"🗑 $count \"\ndiverged = \" $count \"\nstashed = \"📦 $count \"\nmodified = \"פֿ $count \"\nstaged = '[ $count ](green)'\nrenamed = \" $count \"\nuntracked = \"🤷 ‍$count \"\nstyle = \"bold red\"\n\n[golang]\nsymbol = \" \"\n\n[hg_branch]\nsymbol = \" \"\n\n[java]\nsymbol = \" \"\n\n[julia]\nsymbol = \" \"\n\n[memory_usage]\nsymbol = \" \"\n\n[nim]\nsymbol = \" \"\n\n[nix_shell]\nsymbol = \" \"\n\n[package]\nsymbol = \" \"\n\n[perl]\nsymbol = \" \"\n\n[php]\nsymbol = \" \"\n\n[python]\nsymbol = \" \"\n\n[ruby]\nsymbol = \" \"\n\n[rust]\nsymbol = \" \"\n\n[scala]\nsymbol = \" \"\n\n[shlvl]\nsymbol = \" \"\n\n[swift]\nsymbol = \"ﯣ \"\n```\n\n(Some symbols won't appear here, but they'll work on your machine if you have a Nerd Font enabled.)\n\nSave and exit. The configuration will be automatically applied. Here's how mine looks!\n\n![](/images/after-custom-symbols.png)\n\n<Notice>\n\nWant more stuff? Can't be bothered testing it out yourself? Dozens of people have posted their configs on gist. You can find a [bunch of starship configs with a quick search](https://duckduckgo.com/?q=starship+configuration+gist&t=brave&ia=web).\n\n</Notice>\n        \n\n## Installing some plugins\n\nThere are *hundreds* of ZSH plugins. Unfortunately I'm not familiar with all of them, but I do have a few trusty plugins that I think are essential, so let's start with those.\n\n### Choosing a plugin manager\n\nThere are also a bunch of plugin managers to think about. The main difference is how quickly they load/install. Apart from that, they're all much of a muchness. I've found [Antibody](https://getantibody.github.io/) to be my favorite, but feel free to choose another. The plugins will be the same, the only difference being what we use to install them.\n\nFollow [Antibody's installation page](https://getantibody.github.io/install/), then come back here once you're done.\n\n<Notice>\n\nYou might have permission problems while installing Antibody. To fix that you can run `-sfL git.io/antibody | sudo sh -s - -b /usr/local/bin` to install it.\n\n</Notice>\n        \n\nOnce you've installed Antibody we'll do some quick setup to get it working correctly. This command will tell ZSH to load Antibody:\n\n```shell\necho \"\\nsource <(antibody init)\" >> ~/.zshrc\n```\n\nWith this next command we will:\n\n* Create a `.zsh_plugins.txt` file\n* Fill it with some of my must-have plugins\n* Tell ZSH to load our plugins\n\n```shell\ntouch ~/.zsh_plugins.txt && echo \"# Adds autosuggestions \\nzsh-users/zsh-autosuggestions \\n\\n# Adds a customised error when a command isn't found \\nohmyzsh/ohmyzsh path:plugins/command-not-found \\n\\n# Colors our inputs as we type, oooooh \\nzsh-users/zsh-syntax-highlighting \\n\\n# Activates substring search. If you start typing a \\n# command and hit up and down, the commands will be \\n# filtered to ones that match the string you have \\n# already typed. Usage: https://github.com/zsh-users/zsh-history-substring-search#usage \\nzsh-users/zsh-history-substring-search\" >> ~/.zsh_plugins.txt && echo \"\\nantibody bundle < ~/.zsh_plugins.txt\" >> ~/.zshrc\n```\n\nYou can open `.zsh_plugins.txt` to check out what we've installed. I've kept it fairly limited to things that will directly improve your UX.\n\nAdd or remove plugins as you see fit. Then once you're happy with it, run the following command to download and apply them:\n\n```shell\nsource ~/.zshrc\n```\n\n## Make your folders prettier with ColorLS\n\n![](/images/colorls-example.png)\n\nColorLS is a completely useless addition. It just makes listing files in your folders prettier and easier to skim through. Nonetheless I love the look of it and it's never missing from one of my setups.\n\n### Mac\n\n<Notice>\n\n\n\n\nColorLS needs ruby to be installed. I've previously had problems intalling this on Mac as OSX usually comes with Ruby preinstalled. I don't have ready access to a mac for ease of troubleshooting so be careful trying to install this.\n\nI usually skip it altogether on Mac.\n\n\n\n\n</Notice>\n        \n\n### WSL and Linux\n\nFollow the [installation instructions on the colorls Github](https://github.com/athityakumar/colorls#installation).\n\n<Notice>\n\n\n\n\nIf you get an error about 'Not being able to create a makefile', it's likely you're missing `build-essential`! Check how to install it on your OS!\n\n\n\n\n</Notice>\n        \n\nOnce the gem has been installed, run the following command:\n\n```shell\necho \"alias ls='colorls'\" >> ~/.zshrc && echo \"\\n\\n#Automatically runs colorls on cd \\ngretzky/auto-color-ls\" >> ~/.zsh_plugins.txt && source ~/.zshrc\n```\n\nIt will add an alias, so that `ls` will automatically use `colorls` as well as adding a great ZSH plugin to automatically list contents of a folder when moving to it with `cd`!\n\n## Extra - Use your new terminal setup in VsCode\n\nVsCode will use Bash as your default shell, so after all that setup you'll probably want to use oh my zsh. People using Linux and Mac shouldn't need to do this, but in case it's not working by default the following steps should fix it for you.\n\n### Windows with WSL\n\nTo use WSL in VsCode you'll need to install the [Remote WSL plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl). This will allow you to set specific projects to be opened in WSL by default. It offers a fantastic integration with WSL with only minimal setup.\n\n### All OSs\n\nThis is pretty easy! First of all let's find your zsh location by running:\n\n```shell\necho $SHELL\n```\n\nThis will output something along the lines of `/usr/bin/zsh`. Then all you'll have to do is select the little dropdown menu at the top right of your terminal in VsCode and click on \"Select Default Shell\".\n\n![](/images/vscode-default-shell.png)\n\nThis will then open up another menu where you'll see a list of all the shells available. Simply select the value you got from running `echo $SHELL`, restart your VsCode and you'll have your beautiful shell ready.\n\n![](/images/vscode-select-shell.png)\n\n### Correctly display a Nerd Font in VsCode\n\nYou'll probably have noticed that your extra icons are not displaying correctly.\n\nThis is because **VsCode uses its own font for the terminal**, so the solution is pretty simple: edit VsCode's settings. Navigate to the settings menu from \"File > Preferences > Settings\", then search for \"terminal font\". You should see this setting:\n\n![](/images/vscode-font-settings.png)\n\nSimply write in the same value you used for the Hyper terminal settings. In my case it was `FiraCode NF`. As soon as you change the value, the font should also change in the terminal and show your icons!\n\n## Conclusion\n\nThere's a lot of paths one can take when customising your terminal and all of them are right. This is just my personal one, but it's always open to improvements! So please feel free to suggest any you may have in the comments 😊\n","data":{"layout":"blog","title":"How to set up a modern terminal for developers","categories":[{"slug":"technology","highlight":"","content":"","data":{"name":"Technology","visible":true,"description":"Frameworks, libraries, interesting new releases in the world of tech and programming. If this sounds good to you, you’re in the right place."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},{"slug":"ux","highlight":"","content":"","data":{"name":"UX","visible":true,"description":"UX makes the world around. Or at least it does to us."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}}],"author":{"slug":"leonardo-petrucci","highlight":"@creativiii\n","content":"\n[@creativiii](https://twitter.com/creativiii)\n","data":{"name":"Leonardo Petrucci","avatar":"/images/leonardo-petrucci.jpg"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    a: \"a\"\n  }, _provideComponents(), props.components);\n  return _jsx(_components.p, {\n    children: _jsx(_components.a, {\n      href: \"https://twitter.com/creativiii\",\n      children: \"@creativiii\"\n    })\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},"date":"2021-12-27T14:45:08.126Z","thumbnail":"/images/modern-terminal.png","yoast_keyword":"ssaf","published":true},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    strong: \"strong\",\n    img: \"img\",\n    h2: \"h2\",\n    a: \"a\",\n    code: \"code\",\n    pre: \"pre\",\n    span: \"span\",\n    em: \"em\",\n    h3: \"h3\",\n    h4: \"h4\",\n    ul: \"ul\",\n    li: \"li\"\n  }, _provideComponents(), props.components), {Notice} = _components;\n  if (!Notice) _missingMdxReference(\"Notice\", true);\n  return _jsxs(_Fragment, {\n    children: [_jsx(_components.p, {\n      children: \"If you're a web developer, you probably spend a whole lot of time in your terminal. But, despite how fundamental terminals are for modern web development, they're incredibly minimal and limited with often quite bad UX.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"That's why I've spent no less than a couple of years perfecting this \", _jsx(_components.strong, {\n        children: \"cross-platform guide to improving your terminal experience\"\n      }), \". And it's what I use every day for both personal and professional projects, so I know it works. It's by no means perfect, but it should be enough to get you started.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Once you're done, your terminal should look something like this:\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/final-result-2-.gif\",\n        alt: \"\",\n        width: \"980\",\n        height: \"760\"\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"This guide has been written specifically with UNIX systems in mind, so \", _jsx(_components.strong, {\n        children: \"if you're on Windows I recommend installing WSL\"\n      }), \".\"]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Installing ZSH\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"If you're on Linux, or if you're using WSL, it's likely your terminal uses Bash by default. Don't get me wrong, Bash is, well, fine. However, switching it out for ZSH will give us access to a bunch of functionality as well as plugins and customisation options.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"You can find installation instructions for ZSH on \", _jsx(_components.a, {\n        href: \"https://github.com/ohmyzsh/ohmyzsh/wiki/Installing-ZSH\",\n        children: \"the official ZSH git repository\"\n      }), \". Install the correct one for your OS.\"]\n    }), \"\\n\", _jsx(Notice, {\n      children: _jsx(_components.p, {\n        children: \"If you're on Mac, you're already using ZSH by default, so you can skip this step entirely.\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"After installing ZSH, logout and log back in to allow it to complete setup. You might also be met with this configuration screen:\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/zsh.png\",\n        alt: \"\",\n        width: \"571\",\n        height: \"437\"\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"I selected (2) here, which enables some common settings. Once ZSH is initialised you'll notice your prompt looks different. At this point you'll want to move any specific settings from \", _jsx(_components.code, {\n        children: \".bashrc\"\n      }), \" to \", _jsx(_components.code, {\n        children: \".zshrc\"\n      }), \".\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"ZSH will enable some really cool functionality out of the box, such as tabbing auto completion for certain commands like \", _jsx(_components.code, {\n        children: \"cd\"\n      }), \", \", _jsx(_components.code, {\n        children: \"cat\"\n      }), \", and \", _jsx(_components.code, {\n        children: \"ls\"\n      }), \".\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"This means that after writing those commands, you will be able to press Tab to autocomplete it with files from the folder you're currently in!\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/tab-completon.png\",\n        alt: \"\",\n        width: \"930\",\n        height: \"348\"\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Configuration for ZSH will be done in \", _jsx(_components.code, {\n        children: \"~/.zshrc\"\n      }), \". This means if you already have special configuration in your \", _jsx(_components.code, {\n        children: \"~/.bashrc\"\n      }), \" (which is likely if you have been using the system for a while) you should copy it into \", _jsx(_components.code, {\n        children: \"~/.zshrc\"\n      }), \". For example I moved my path for NVM:\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-shell\",\n      children: _jsxs(_components.code, {\n        className: \"language-shell\",\n        children: [_jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token assign-left variable\",\n          children: \"NVM_DIR\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"=\"\n        }), _jsxs(_components.span, {\n          className: \"token string\",\n          children: [\"\\\"\", _jsx(_components.span, {\n            className: \"token environment constant\",\n            children: \"$HOME\"\n          }), \"/.nvm\\\"\"]\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"\\\\\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), \" -s \", _jsxs(_components.span, {\n          className: \"token string\",\n          children: [\"\\\"\", _jsx(_components.span, {\n            className: \"token variable\",\n            children: \"$NVM_DIR\"\n          }), \"/nvm.sh\\\"\"]\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"&&\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \".\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token string\",\n          children: [\"\\\"\", _jsx(_components.span, {\n            className: \"token variable\",\n            children: \"$NVM_DIR\"\n          }), \"/nvm.sh\\\"\"]\n        }), \"  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"# This loads nvm\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"\\\\\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), \" -s \", _jsxs(_components.span, {\n          className: \"token string\",\n          children: [\"\\\"\", _jsx(_components.span, {\n            className: \"token variable\",\n            children: \"$NVM_DIR\"\n          }), \"/bash_completion\\\"\"]\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"&&\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \".\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token string\",\n          children: [\"\\\"\", _jsx(_components.span, {\n            className: \"token variable\",\n            children: \"$NVM_DIR\"\n          }), \"/bash_completion\\\"\"]\n        }), \"  \", _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"# This loads nvm bash_completion\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsxs(Notice, {\n      children: [_jsxs(_components.p, {\n        children: [\"Specifically look for lines that \", _jsx(_components.a, {\n          href: \"https://opensource.com/article/17/6/set-path-linux\",\n          children: \"add commands to your $PATH\"\n        }), \", like NVM, NPM, Node, Android Studio and Java.\"]\n      }), _jsxs(_components.p, {\n        children: [\"If any commands that used to work previously don't work after installing ZSH, you probably just need to copy those config lines from \", _jsx(_components.code, {\n          children: \"~/.bashrc\"\n        }), \" to \", _jsx(_components.code, {\n          children: \"~/.zshrc\"\n        })]\n      })]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Installing oh my zsh\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/oh-my-zsh.png\",\n        alt: \"\",\n        width: \"857\",\n        height: \"348\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"If ZSH is the foundation of a good terminal, oh my zsh is the frame(work) that will make it your home. oh my zsh is a framework that allows installation and management of hundreds of amazing plugins and themes. It's what will put all the extra functionality to our terminal.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"You can find instructions on how to install it on \", _jsx(_components.a, {\n        href: \"https://github.com/ohmyzsh/ohmyzsh#basic-installation\",\n        children: \"oh my zsh's official github repository\"\n      }), \".\"]\n    }), \"\\n\", _jsx(Notice, {\n      children: _jsx(_components.p, {\n        children: \"You probably won't notice much difference here, but don't worry, we'll come back to this and install plugins for oh my zsh later in the guide.\"\n      })\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Terminal Client\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"There are dozens of terminal clients out there, and they all do very similar things. It doesn't \", _jsx(_components.em, {\n        children: \"really\"\n      }), \" matter which one you choose, but \", _jsx(_components.strong, {\n        children: \"make sure that you can change its font\"\n      }), \". I'd also recommend having a good amount of themes to choose from, but that's up to you.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"My recommendation would be \", _jsx(_components.a, {\n        href: \"https://hyper.is/\",\n        children: \"Hyper\"\n      }), \". It's node based, really customisable and it has plenty of nifty plugins and themes.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/hyper_h3nosiaogk.png\",\n        alt: \"\",\n        width: \"846\",\n        height: \"686\"\n      })\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Themes for Hyper\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"One of the reasons I like Hyper is because of the incredible amount of themes available for it.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"You can check some themes out at \", _jsx(_components.a, {\n        href: \"https://hyper.is/themes/newest\",\n        children: \"the Hyper website\"\n      }), \". But my personal favorite is the \", _jsx(_components.a, {\n        href: \"https://github.com/drcmda/poimandres-theme\",\n        children: \"poimandres-theme\"\n      }), \".\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"WSL on Windows\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"If you're planning to use Hyper and WSL together there's some extra configuration you probably want to go through.\"\n    }), \"\\n\", _jsx(_components.h4, {\n      children: \"Make Hyper boot into WSL by default\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Hyper, by default, will boot into the Windows CMD. You can then use the command \", _jsx(_components.code, {\n        children: \"wsl\"\n      }), \" to boot into WSL. This can get annoying, so if you want to boot directly into WSL you can change Hyper configuration.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Press \", _jsx(_components.code, {\n        children: \"CTRL+,\"\n      }), \" to open the config file and make sure that \", _jsx(_components.code, {\n        children: \"shell\"\n      }), \" and \", _jsx(_components.code, {\n        children: \"shellArgs\"\n      }), \" look like this:\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-javascript\",\n      children: _jsxs(_components.code, {\n        className: \"language-javascript\",\n        children: [_jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"shell\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'C:\\\\\\\\Windows\\\\\\\\System32\\\\\\\\wsl.exe'\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"shellArgs\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Save and exit to apply the settings.\"\n    }), \"\\n\", _jsx(_components.h4, {\n      children: \"Installing Hyper themes in WSL\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Some extra setup is required to install and use themes on WSL. Installing themes is usually done with the Hyper CLI. This means that by running \", _jsx(_components.code, {\n        children: \"hyper i hyper-pmndrs\"\n      }), \" the theme would be downloaded and installed.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Since you're running WSL however, Linux won't have any access to the \", _jsx(_components.code, {\n        children: \"hyper\"\n      }), \" command. To fix this run the following command:\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-shell\",\n      children: _jsxs(_components.code, {\n        className: \"language-shell\",\n        children: [_jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"echo\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token string\",\n          children: [\"\\\"\", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"alias hyper=\\\"\"]\n        }), \"cmd.exe /c hyper\\\" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \">>\"\n        }), \" ~/.zshrc \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"&&\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"source\"\n        }), \" ~/.zshrc\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"The above will add an alias to make the Hyper CLI work. Once done, try installing your theme of choice again and it should work!\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Installing a Nerd Font\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Nerd Fonts are monospaced fonts with one big difference: they have been patched to include hundreds of symbols. Installing a nerd font will allow us to customise our terminal even further later on.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Installing a Nerd Font is pretty easy: simply select a font from \", _jsx(_components.a, {\n        href: \"https://www.nerdfonts.com/font-downloads\",\n        children: \"Nerd Fonts\"\n      }), \". (I'm currently using Fira Code.)\"]\n    }), \"\\n\", _jsx(Notice, {\n      children: _jsxs(_components.p, {\n        children: [\"Don't install a mono version of the font. This will cause some icons to be much smaller than they should be. Mine was called \", _jsx(_components.strong, {\n          children: \"FiraCode Nerd Font.\"\n        })]\n      })\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Windows\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Windows requires a specific version of the font. You can identify the correct files since they include \", _jsx(_components.code, {\n        children: \"Windows\"\n      }), \" in their names. You can search for the following in the extracted folder to save yourself some time:\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-shell\",\n      children: _jsxs(_components.code, {\n        className: \"language-shell\",\n        children: [_jsx(_components.span, {\n          className: \"token operator\",\n          children: \"<\"\n        }), \"font-name\", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \">\"\n        }), \" windows ttf -mono\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Don't forget Windows also allows you to install batches of fonts at the same time from its settings.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/windows-install-fonts.png\",\n        alt: \"\",\n        width: \"929\",\n        height: \"648\"\n      })\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Linux / Mac\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Linux and Mac should be able to support either TTF or OTF. I'm unaware of a quick way of installing multiple fonts on both platforms, so you might have to do this the old fashioned way. Sorry!\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Setting your Nerd Font to your terminal\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Before we go any further, let's actually set the new fonts we've installed so they can be used by our terminal.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"I'm going to assume you're currently using Hyper as your terminal, so to change fonts in Hyper you'll need to edit its configuration. With Hyper open press \", _jsx(_components.code, {\n        children: \"CTRL + ,\"\n      }), \" to bring up the config file. If you've done any Javascript development you'll recognise the syntax immediately.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"In your config simply find \", _jsx(_components.code, {\n        children: \"fontFamily\"\n      }), \" and add your new font to the start of the list. The others are all fallbacks in case the previous isn't available. My setting looks something like this:\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-javascript\",\n      children: _jsxs(_components.code, {\n        className: \"language-javascript\",\n        children: [_jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// font family with optional fallbacks\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token literal-property property\",\n          children: \"fontFamily\"\n        }), _jsx(_components.span, {\n          className: \"token operator\",\n          children: \":\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'FiraCode NF, \\\"DejaVu Sans Mono\\\", Consolas, \\\"Lucida Console\\\", monospace'\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \",\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(Notice, {\n      children: _jsxs(_components.p, {\n        children: [\"Make sure you use the name of the font as it shows up in your font list! On mac this was \", _jsx(_components.code, {\n          children: \"FiraCode Nerd Font\"\n        }), \" for me, so just make sure you're writing the correct name.\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Your terminal window should reload as soon as the config is saved, so you should see the new font immediately.\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Improving your prompt with Starship\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"If you've been following along, your prompt will look something like this:\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/before-prompt.png\",\n        alt: \"\",\n        width: \"1005\",\n        height: \"784\"\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"It's okay. We get to know the folder we're currently in and if we're inside a \", _jsx(_components.code, {\n        children: \"git\"\n      }), \" folder we can also tell which branch we have selected.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"But what if we could make this even better? That's where \", _jsx(_components.a, {\n        href: \"https://starship.rs/\",\n        children: \"Starship\"\n      }), \" comes in. It adds a bunch of information to your prompt which you can easily customise. There's tons of utilities like Starship out there, so it's really up to you which one you choose. Feel free to shop around and pick your favorite.\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"All OSs\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"There's honestly tons of ways to install Starship depending on your OS. So \", _jsx(_components.a, {\n        href: \"https://starship.rs/guide/#%F0%9F%9A%80-installation\",\n        children: \"just follow the installation guide on their documentation\"\n      }), \".\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Then, since we're on ZSH, type the following command in your terminal.\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-shell\",\n      children: _jsxs(_components.code, {\n        className: \"language-shell\",\n        children: [_jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"echo\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'\\\\neval \\\"$(starship init zsh)\\\"'\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \">>\"\n        }), \" ~/.zshrc \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"&&\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"source\"\n        }), \" ~/.zshrc\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"This will tell ZSH to use Starship and then reload the ZSH configuration. If you did everything right you'll see a subtle change in your terminal input to something like this:\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/after-prompt.png\",\n        alt: \"\",\n        width: \"1005\",\n        height: \"784\"\n      })\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Customizing Starship\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"The great thing about Starship is that it has tons of customisations available. If this sounds interesting to you, run the following command to create a config file:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-shell\",\n      children: _jsxs(_components.code, {\n        className: \"language-shell\",\n        children: [_jsx(_components.span, {\n          className: \"token function\",\n          children: \"mkdir\"\n        }), \" -p ~/.config \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"&&\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: \"touch\"\n        }), \" ~/.config/starship.toml\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Then run this to start editing it:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-shell\",\n      children: _jsxs(_components.code, {\n        className: \"language-shell\",\n        children: [_jsx(_components.span, {\n          className: \"token function\",\n          children: \"nano\"\n        }), \" ~/.config/starship.toml\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Since earlier in the tutorial we installed a Nerd Font, I like to make use of it for most symbols. Feel free to change those symbols to Emojis though if that's more of your thing. My current Starship configuration is as follows:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-toml\",\n      children: _jsxs(_components.code, {\n        className: \"language-toml\",\n        children: [_jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"aws\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"  \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"conda\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"dart\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"directory\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"read_only\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"docker_context\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"elixir\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"elm\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"git_branch\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"git_status\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"format\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"[$all_status$ahead_behind]($style)\\\"\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"ahead\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"⇡ $count \\\"\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"behind\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"⇣ $count \\\"\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"deleted\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"🗑 $count \\\"\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"diverged\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" $count \\\"\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"stashed\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"📦 $count \\\"\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"modified\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"פֿ $count \\\"\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"staged\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"'[ $count ](green)'\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"renamed\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" $count \\\"\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"untracked\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"🤷 ‍$count \\\"\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"style\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"bold red\\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"golang\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"hg_branch\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"java\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"julia\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"memory_usage\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"nim\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"nix_shell\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"package\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"perl\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"php\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"python\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"ruby\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"rust\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"scala\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"shlvl\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\" \\\"\"\n        }), \"\\n\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"[\"\n        }), _jsx(_components.span, {\n          className: \"token table class-name\",\n          children: \"swift\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"]\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token key property\",\n          children: \"symbol\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"=\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"ﯣ \\\"\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"(Some symbols won't appear here, but they'll work on your machine if you have a Nerd Font enabled.)\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Save and exit. The configuration will be automatically applied. Here's how mine looks!\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/after-custom-symbols.png\",\n        alt: \"\",\n        width: \"1005\",\n        height: \"784\"\n      })\n    }), \"\\n\", _jsx(Notice, {\n      children: _jsxs(_components.p, {\n        children: [\"Want more stuff? Can't be bothered testing it out yourself? Dozens of people have posted their configs on gist. You can find a \", _jsx(_components.a, {\n          href: \"https://duckduckgo.com/?q=starship+configuration+gist&t=brave&ia=web\",\n          children: \"bunch of starship configs with a quick search\"\n        }), \".\"]\n      })\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Installing some plugins\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"There are \", _jsx(_components.em, {\n        children: \"hundreds\"\n      }), \" of ZSH plugins. Unfortunately I'm not familiar with all of them, but I do have a few trusty plugins that I think are essential, so let's start with those.\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Choosing a plugin manager\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"There are also a bunch of plugin managers to think about. The main difference is how quickly they load/install. Apart from that, they're all much of a muchness. I've found \", _jsx(_components.a, {\n        href: \"https://getantibody.github.io/\",\n        children: \"Antibody\"\n      }), \" to be my favorite, but feel free to choose another. The plugins will be the same, the only difference being what we use to install them.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Follow \", _jsx(_components.a, {\n        href: \"https://getantibody.github.io/install/\",\n        children: \"Antibody's installation page\"\n      }), \", then come back here once you're done.\"]\n    }), \"\\n\", _jsx(Notice, {\n      children: _jsxs(_components.p, {\n        children: [\"You might have permission problems while installing Antibody. To fix that you can run \", _jsx(_components.code, {\n          children: \"-sfL git.io/antibody | sudo sh -s - -b /usr/local/bin\"\n        }), \" to install it.\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Once you've installed Antibody we'll do some quick setup to get it working correctly. This command will tell ZSH to load Antibody:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-shell\",\n      children: _jsxs(_components.code, {\n        className: \"language-shell\",\n        children: [_jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"echo\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token string\",\n          children: [\"\\\"\", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"source <(antibody init)\\\"\"]\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \">>\"\n        }), \" ~/.zshrc\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"With this next command we will:\"\n    }), \"\\n\", _jsxs(_components.ul, {\n      children: [\"\\n\", _jsxs(_components.li, {\n        children: [\"Create a \", _jsx(_components.code, {\n          children: \".zsh_plugins.txt\"\n        }), \" file\"]\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Fill it with some of my must-have plugins\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Tell ZSH to load our plugins\"\n      }), \"\\n\"]\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-shell\",\n      children: _jsxs(_components.code, {\n        className: \"language-shell\",\n        children: [_jsx(_components.span, {\n          className: \"token function\",\n          children: \"touch\"\n        }), \" ~/.zsh_plugins.txt \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"&&\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"echo\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token string\",\n          children: [\"\\\"# Adds autosuggestions \", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"zsh-users/zsh-autosuggestions \", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"# Adds a customised error when a command isn't found \", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"ohmyzsh/ohmyzsh path:plugins/command-not-found \", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"# Colors our inputs as we type, oooooh \", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"zsh-users/zsh-syntax-highlighting \", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"# Activates substring search. If you start typing a \", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"# command and hit up and down, the commands will be \", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"# filtered to ones that match the string you have \", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"# already typed. Usage: https://github.com/zsh-users/zsh-history-substring-search#usage \", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"zsh-users/zsh-history-substring-search\\\"\"]\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \">>\"\n        }), \" ~/.zsh_plugins.txt \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"&&\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"echo\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token string\",\n          children: [\"\\\"\", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"antibody bundle < ~/.zsh_plugins.txt\\\"\"]\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \">>\"\n        }), \" ~/.zshrc\\n\"]\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"You can open \", _jsx(_components.code, {\n        children: \".zsh_plugins.txt\"\n      }), \" to check out what we've installed. I've kept it fairly limited to things that will directly improve your UX.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Add or remove plugins as you see fit. Then once you're happy with it, run the following command to download and apply them:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-shell\",\n      children: _jsxs(_components.code, {\n        className: \"language-shell\",\n        children: [_jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"source\"\n        }), \" ~/.zshrc\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Make your folders prettier with ColorLS\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/colorls-example.png\",\n        alt: \"\",\n        width: \"980\",\n        height: \"760\"\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"ColorLS is a completely useless addition. It just makes listing files in your folders prettier and easier to skim through. Nonetheless I love the look of it and it's never missing from one of my setups.\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Mac\"\n    }), \"\\n\", _jsxs(Notice, {\n      children: [_jsx(_components.p, {\n        children: \"ColorLS needs ruby to be installed. I've previously had problems intalling this on Mac as OSX usually comes with Ruby preinstalled. I don't have ready access to a mac for ease of troubleshooting so be careful trying to install this.\"\n      }), _jsx(_components.p, {\n        children: \"I usually skip it altogether on Mac.\"\n      })]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"WSL and Linux\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Follow the \", _jsx(_components.a, {\n        href: \"https://github.com/athityakumar/colorls#installation\",\n        children: \"installation instructions on the colorls Github\"\n      }), \".\"]\n    }), \"\\n\", _jsx(Notice, {\n      children: _jsxs(_components.p, {\n        children: [\"If you get an error about 'Not being able to create a makefile', it's likely you're missing \", _jsx(_components.code, {\n          children: \"build-essential\"\n        }), \"! Check how to install it on your OS!\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Once the gem has been installed, run the following command:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-shell\",\n      children: _jsxs(_components.code, {\n        className: \"language-shell\",\n        children: [_jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"echo\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token string\",\n          children: \"\\\"alias ls='colorls'\\\"\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \">>\"\n        }), \" ~/.zshrc \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"&&\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"echo\"\n        }), \" \", _jsxs(_components.span, {\n          className: \"token string\",\n          children: [\"\\\"\", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"#Automatically runs colorls on cd \", _jsx(_components.span, {\n            className: \"token entity\",\n            title: \"\\\\n\",\n            children: \"\\\\n\"\n          }), \"gretzky/auto-color-ls\\\"\"]\n        }), \" \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \">>\"\n        }), \" ~/.zsh_plugins.txt \", _jsx(_components.span, {\n          className: \"token operator\",\n          children: \"&&\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"source\"\n        }), \" ~/.zshrc\\n\"]\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"It will add an alias, so that \", _jsx(_components.code, {\n        children: \"ls\"\n      }), \" will automatically use \", _jsx(_components.code, {\n        children: \"colorls\"\n      }), \" as well as adding a great ZSH plugin to automatically list contents of a folder when moving to it with \", _jsx(_components.code, {\n        children: \"cd\"\n      }), \"!\"]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Extra - Use your new terminal setup in VsCode\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"VsCode will use Bash as your default shell, so after all that setup you'll probably want to use oh my zsh. People using Linux and Mac shouldn't need to do this, but in case it's not working by default the following steps should fix it for you.\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Windows with WSL\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"To use WSL in VsCode you'll need to install the \", _jsx(_components.a, {\n        href: \"https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl\",\n        children: \"Remote WSL plugin\"\n      }), \". This will allow you to set specific projects to be opened in WSL by default. It offers a fantastic integration with WSL with only minimal setup.\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"All OSs\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"This is pretty easy! First of all let's find your zsh location by running:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-shell\",\n      children: _jsxs(_components.code, {\n        className: \"language-shell\",\n        children: [_jsx(_components.span, {\n          className: \"token builtin class-name\",\n          children: \"echo\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token environment constant\",\n          children: \"$SHELL\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"This will output something along the lines of \", _jsx(_components.code, {\n        children: \"/usr/bin/zsh\"\n      }), \". Then all you'll have to do is select the little dropdown menu at the top right of your terminal in VsCode and click on \\\"Select Default Shell\\\".\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/vscode-default-shell.png\",\n        alt: \"\",\n        width: \"429\",\n        height: \"163\"\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"This will then open up another menu where you'll see a list of all the shells available. Simply select the value you got from running \", _jsx(_components.code, {\n        children: \"echo $SHELL\"\n      }), \", restart your VsCode and you'll have your beautiful shell ready.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/vscode-select-shell.png\",\n        alt: \"\",\n        width: \"796\",\n        height: \"353\"\n      })\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"Correctly display a Nerd Font in VsCode\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"You'll probably have noticed that your extra icons are not displaying correctly.\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"This is because \", _jsx(_components.strong, {\n        children: \"VsCode uses its own font for the terminal\"\n      }), \", so the solution is pretty simple: edit VsCode's settings. Navigate to the settings menu from \\\"File > Preferences > Settings\\\", then search for \\\"terminal font\\\". You should see this setting:\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/vscode-font-settings.png\",\n        alt: \"\",\n        width: \"799\",\n        height: \"130\"\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Simply write in the same value you used for the Hyper terminal settings. In my case it was \", _jsx(_components.code, {\n        children: \"FiraCode NF\"\n      }), \". As soon as you change the value, the font should also change in the terminal and show your icons!\"]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Conclusion\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"There's a lot of paths one can take when customising your terminal and all of them are right. This is just my personal one, but it's always open to improvements! So please feel free to suggest any you may have in the comments 😊\"\n    })]\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\nfunction _missingMdxReference(id, component) {\n  throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");\n}\n","frontmatter":{},"scope":{}}},{"slug":"react-atomic-design-a-first-year-retrospective","highlight":"Atomic Design in React is an (allegedly) popular way of structuring React projects which is said to offer great scalability. Before 2020 I never worked on a project big enough to need something like this, but as Staffscanner's features grew I felt the need to enforce a more scalable structure. So here's some thoughts on my first year with React and Atomic Design.\n\nHow does Atomic Design work?\nAtomic Design at its core is fairly simple. It mainly consists of dividing up your components depending","content":"Atomic Design in React is an (allegedly) popular way of structuring React projects which is said to offer great scalability. Before 2020 I never worked on a project big enough to need something like this, but as [Staffscanner](https://staffscanner.co.uk/)'s features grew I felt the need to enforce a more scalable structure. So here's some thoughts on my first year with React and Atomic Design.\n\n![](/images/frame-130.png)\n\n## How does Atomic Design work?\n\nAtomic Design at its core is fairly simple. It mainly consists of dividing up your components depending on their hierarchy within your app.\n\n![](/images/33235048-d083dca6-d217-11e7-9aea-9a5ef5ae6fe7.png)\n\n* Atoms are the most reusable parts of your app\n* Molecules are often instances of Atoms for specific uses\n* Organisms are made up of one or more Molecules\n* Templates set contexts and place components where they should be on the page\n* Pages pass down components to the templates and fetch data to be displayed\n\n(This is a very simplified explanation of Atomic Design in React. You can find a more thorough explanation at [danilowoz/react-atomic-design](https://github.com/danilowoz/react-atomic-design).)\n\nOn the surface, Atomic Design might seem pretty simple. Nevertheless, I found myself somewhat confused while putting it into practice. Not because of its complexity but because certain rules and situations didn't seem to quite fit the model.\n\n## Atomic Design in React: The role of templates and pages\n\nWhile atoms, molecules and organisms are simple concepts to get your head around, templates and pages are a bit more complicated. The way Atomic Design in React envisions templates is as **layout-only** components that receive organisms and molecules to place them in their correct positions.\n\nI assume it should probably look something like this:\n\n```jsx\nexport default function App() {\n  return (\n    <Template>\n      <Template.Element1>A component here</Template.Element1>\n      <Template.Element2>A component here</Template.Element2>\n      <Template.Element3>A component here</Template.Element3>\n    </Template>\n  );\n}\n```\n\n### The problem\n\nWhile I like the idea of templates existing exclusively to position other components, I found the practice of passing those components as props to be needlessly complex. Don't get me wrong, this practice does make templates **much more reusable**, but in my situation it seemed to add a lot of unneeded prop drilling and made the hierarchy much more difficult to read.\n\n### My solution\n\nAfter trying the *\"correct way\"* for a while I started to realize that many of my pages were simply too different from each other and that I rarely ever reused templates. I was giving myself a lot of overhead where it simply wasn't needed.\n\nSo, rather that making templates as reusable as possible, templates essentially became my pages. They import the needed components and place them where they're supposed to be rendered on the page. This then allows me to demote pages to simply be used for Routing, which mirrors Next.js' routing setup which I'm very fond of.\n\n## Atomic Design in React: Using pages as routes\n\nIf you've ever used Next.js it's very likely you've used its [built-in routing](https://nextjs.org/docs/routing/introduction) functionality at some point. Files inside the `pages` folder automatically render as routes:\n\n* `pages/blog/first-post.js` → `/blog/first-post`\n* `pages/dashboard/settings/username.js` → `/dashboard/settings/username`\n\nI like this pattern. I think it makes it easy to quickly explore how the app is structured. If I want to know what components are used in `blog/first-post`, I can just go to the folder that renders the page and drill down to the rendered components.\n\nEven for someone ***not at all familiar with the codebase***, this is easy to understand.\n\nA lot of my pages then simply end up looking like this in case they have sub-routes to render:\n\n```jsx\n// src/pages/posts\nexport default function App() {\n  return (\n    <Switch>\n      <Route path={`${match.path}/:postId`}>\n        {/* The page responsible for rendering a single post */}\n        <PostPage />\n      </Route>\n      <Route path=\"/\">\n        {/* The page responsible for rendering a list of all posts */}\n        <PostListPage />\n      </Route>\n     </Switch>\n  )\n}\n```\n\nAnd if they are simpler they usually just render a template, maybe with some protection if certain users should not be able to see them.\n\n```jsx\n// src/pages/posts/post\nexport default function PostPage() {\n  return (\n    <Protect>\n      {/* The template responsible for rendering a single post */}\n      <PostTemplate />\n    </Protect>\n  )\n}\n```\n\nI found that leaving this layer as simple as possible then also helped in those few situations where an extra context was needed but I couldn't re-architect a template. It's a safety net that's served me well.\n\n## Atomic Design in React: Prop Drilling and Contexts\n\nAtomic design doesn't specifically mention anything about where props should be used or where contexts should be used but I found this to be a crucial decision to keep the application scalable.\n\n### The problem\n\nA lot of my data fetching and mutating is handled exclusively by hooks. So I'll have a hook called `usePosts()` which returns the post data but will also contain methods like `doDelete` or `doEdit`. This is great for keeping everything separate and easy to test, but at some point it needs to be imported in a component for the data to be displayed.\n\nOnce the hook is imported in a component, that component will be forever dependent on that specific context exiting somewhere higher up in the component tree. It makes code simple to read but could potentially kill the reusability of that component.\n\n### My solution\n\nWhile this is an entirely arbitrary solution, I decided very early on to only use hook and contexts in:\n\n* **Templates** - Where the contexts are usually set up\n* **Organisms** - Where contexts are usually consumed\n\nAny data that needs to be displayed in molecules is passed down as a prop. This allows molecules to be as reusable as possible while organisms (which are usually page specific) can still enjoy the benefits of using hooks and contexts.\n\n## Atomic Design in React: The gap component saved my life\n\nA key rule of Atomic Design in React is to never add margins or paddings to molecules and organisms. This seems silly, but it helps a lot with reusability. Some components might need padding in certain situations, but not in others! \n\nThis is a good rule to follow on paper, but in practice it means **adding a lot of divs** just to have spacing, which pads out code and looks really nasty. What helped a lot in this situation was Tailwind's `space` class:\n\n![](/images/screenshot-2021-11-28-161003.png)\n\nSpace works much like the [CSS gap property](https://developer.mozilla.org/en-US/docs/Web/CSS/gap), except it's actually supported by all browsers. Gap doesn't have widespread support among older Apple devices so it might still be a bit before we can use it!\n\nIn case you're not using Tailwind or you're not in the mood to get CSS hacks together, I would suggest replicating [Ant Design's `<Space>` component](https://ant.design/components/space/) which works much the same but uses props rather than CSS.\n\n## Final thoughts about Atomic Design in React\n\nMy main reason for using Atomic Design was to make our codebase easier for people with little to no experience in React to easily find their way, and while I didn't end up following it exactly it has definitely worked. Components are clearly separated while still being easy to test and reuse.\n\nI really like how it has a very strong base, but isn't strict enough to stop experimentation and rule-bending. I guess time will tell if my changes are terrible or if they don't end up impacting a lot, but as of now I'm very satisfied with the results.\n","data":{"layout":"blog","title":"Atomic Design in React: A first year retrospective","categories":[{"slug":"react","highlight":"","content":"","data":{"name":"React","visible":true,"description":"How to's and tutorials on our favorite Javascript library."},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  return _jsx(_Fragment, {});\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}}],"author":{"slug":"leonardo-petrucci","highlight":"@creativiii\n","content":"\n[@creativiii](https://twitter.com/creativiii)\n","data":{"name":"Leonardo Petrucci","avatar":"/images/leonardo-petrucci.jpg"},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    a: \"a\"\n  }, _provideComponents(), props.components);\n  return _jsx(_components.p, {\n    children: _jsx(_components.a, {\n      href: \"https://twitter.com/creativiii\",\n      children: \"@creativiii\"\n    })\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}},"date":"2021-11-28T13:45:06.245Z","thumbnail":"/images/frame-130.png","description":"A reflection of the past year of working with Atomic Design in React, what worked, what didn't work and what confused me.","yoast_keyword":"Atomic Design in React","published":true},"isEmpty":false,"excerpt":"","mdx":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n  const _components = Object.assign({\n    p: \"p\",\n    a: \"a\",\n    img: \"img\",\n    h2: \"h2\",\n    ul: \"ul\",\n    li: \"li\",\n    strong: \"strong\",\n    pre: \"pre\",\n    code: \"code\",\n    span: \"span\",\n    h3: \"h3\",\n    em: \"em\"\n  }, _provideComponents(), props.components);\n  return _jsxs(_Fragment, {\n    children: [_jsxs(_components.p, {\n      children: [\"Atomic Design in React is an (allegedly) popular way of structuring React projects which is said to offer great scalability. Before 2020 I never worked on a project big enough to need something like this, but as \", _jsx(_components.a, {\n        href: \"https://staffscanner.co.uk/\",\n        children: \"Staffscanner\"\n      }), \"'s features grew I felt the need to enforce a more scalable structure. So here's some thoughts on my first year with React and Atomic Design.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/frame-130.png\",\n        alt: \"\",\n        width: \"1200\",\n        height: \"630\"\n      })\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"How does Atomic Design work?\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Atomic Design at its core is fairly simple. It mainly consists of dividing up your components depending on their hierarchy within your app.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/33235048-d083dca6-d217-11e7-9aea-9a5ef5ae6fe7.png\",\n        alt: \"\",\n        width: \"1968\",\n        height: \"448\"\n      })\n    }), \"\\n\", _jsxs(_components.ul, {\n      children: [\"\\n\", _jsx(_components.li, {\n        children: \"Atoms are the most reusable parts of your app\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Molecules are often instances of Atoms for specific uses\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Organisms are made up of one or more Molecules\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Templates set contexts and place components where they should be on the page\"\n      }), \"\\n\", _jsx(_components.li, {\n        children: \"Pages pass down components to the templates and fetch data to be displayed\"\n      }), \"\\n\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"(This is a very simplified explanation of Atomic Design in React. You can find a more thorough explanation at \", _jsx(_components.a, {\n        href: \"https://github.com/danilowoz/react-atomic-design\",\n        children: \"danilowoz/react-atomic-design\"\n      }), \".)\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"On the surface, Atomic Design might seem pretty simple. Nevertheless, I found myself somewhat confused while putting it into practice. Not because of its complexity but because certain rules and situations didn't seem to quite fit the model.\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Atomic Design in React: The role of templates and pages\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"While atoms, molecules and organisms are simple concepts to get your head around, templates and pages are a bit more complicated. The way Atomic Design in React envisions templates is as \", _jsx(_components.strong, {\n        children: \"layout-only\"\n      }), \" components that receive organisms and molecules to place them in their correct positions.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"I assume it should probably look something like this:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-jsx\",\n      children: _jsxs(_components.code, {\n        className: \"language-jsx\",\n        children: [_jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"default\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"function\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"App\"\n          })\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"\\n    \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Template\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n      \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Template.Element1\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"A component here\"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Template.Element1\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n      \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Template.Element2\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"A component here\"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Template.Element2\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n      \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Template.Element3\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"A component here\"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Template.Element3\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Template\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \";\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"The problem\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"While I like the idea of templates existing exclusively to position other components, I found the practice of passing those components as props to be needlessly complex. Don't get me wrong, this practice does make templates \", _jsx(_components.strong, {\n        children: \"much more reusable\"\n      }), \", but in my situation it seemed to add a lot of unneeded prop drilling and made the hierarchy much more difficult to read.\"]\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"My solution\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"After trying the \", _jsx(_components.em, {\n        children: \"\\\"correct way\\\"\"\n      }), \" for a while I started to realize that many of my pages were simply too different from each other and that I rarely ever reused templates. I was giving myself a lot of overhead where it simply wasn't needed.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"So, rather that making templates as reusable as possible, templates essentially became my pages. They import the needed components and place them where they're supposed to be rendered on the page. This then allows me to demote pages to simply be used for Routing, which mirrors Next.js' routing setup which I'm very fond of.\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Atomic Design in React: Using pages as routes\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"If you've ever used Next.js it's very likely you've used its \", _jsx(_components.a, {\n        href: \"https://nextjs.org/docs/routing/introduction\",\n        children: \"built-in routing\"\n      }), \" functionality at some point. Files inside the \", _jsx(_components.code, {\n        children: \"pages\"\n      }), \" folder automatically render as routes:\"]\n    }), \"\\n\", _jsxs(_components.ul, {\n      children: [\"\\n\", _jsxs(_components.li, {\n        children: [_jsx(_components.code, {\n          children: \"pages/blog/first-post.js\"\n        }), \" → \", _jsx(_components.code, {\n          children: \"/blog/first-post\"\n        })]\n      }), \"\\n\", _jsxs(_components.li, {\n        children: [_jsx(_components.code, {\n          children: \"pages/dashboard/settings/username.js\"\n        }), \" → \", _jsx(_components.code, {\n          children: \"/dashboard/settings/username\"\n        })]\n      }), \"\\n\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"I like this pattern. I think it makes it easy to quickly explore how the app is structured. If I want to know what components are used in \", _jsx(_components.code, {\n        children: \"blog/first-post\"\n      }), \", I can just go to the folder that renders the page and drill down to the rendered components.\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Even for someone \", _jsx(_components.em, {\n        children: _jsx(_components.strong, {\n          children: \"not at all familiar with the codebase\"\n        })\n      }), \", this is easy to understand.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"A lot of my pages then simply end up looking like this in case they have sub-routes to render:\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-jsx\",\n      children: _jsxs(_components.code, {\n        className: \"language-jsx\",\n        children: [_jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// src/pages/posts\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"default\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"function\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"App\"\n          })\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"\\n    \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Switch\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n      \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Route\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"path\"\n          }), _jsxs(_components.span, {\n            className: \"token script language-javascript\",\n            children: [_jsx(_components.span, {\n              className: \"token script-punctuation punctuation\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"{\"\n            }), _jsxs(_components.span, {\n              className: \"token template-string\",\n              children: [_jsx(_components.span, {\n                className: \"token template-punctuation string\",\n                children: \"`\"\n              }), _jsxs(_components.span, {\n                className: \"token interpolation\",\n                children: [_jsx(_components.span, {\n                  className: \"token interpolation-punctuation punctuation\",\n                  children: \"${\"\n                }), \"match\", _jsx(_components.span, {\n                  className: \"token punctuation\",\n                  children: \".\"\n                }), _jsx(_components.span, {\n                  className: \"token property-access\",\n                  children: \"path\"\n                }), _jsx(_components.span, {\n                  className: \"token interpolation-punctuation punctuation\",\n                  children: \"}\"\n                })]\n              }), _jsx(_components.span, {\n                className: \"token string\",\n                children: \"/:postId\"\n              }), _jsx(_components.span, {\n                className: \"token template-punctuation string\",\n                children: \"`\"\n              })]\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"}\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n        \"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"/* The page responsible for rendering a single post */\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n        \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"PostPage\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n      \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Route\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n      \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Route\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token attr-name\",\n            children: \"path\"\n          }), _jsxs(_components.span, {\n            className: \"token attr-value\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation attr-equals\",\n              children: \"=\"\n            }), _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            }), \"/\", _jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"\\\"\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n        \"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"/* The page responsible for rendering a list of all posts */\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n        \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"PostListPage\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n      \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Route\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n     \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Switch\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"And if they are simpler they usually just render a template, maybe with some protection if certain users should not be able to see them.\"\n    }), \"\\n\", _jsx(_components.pre, {\n      className: \"language-jsx\",\n      children: _jsxs(_components.code, {\n        className: \"language-jsx\",\n        children: [_jsx(_components.span, {\n          className: \"token comment\",\n          children: \"// src/pages/posts/post\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"export\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword module\",\n          children: \"default\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token keyword\",\n          children: \"function\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token function\",\n          children: _jsx(_components.span, {\n            className: \"token maybe-class-name\",\n            children: \"PostPage\"\n          })\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token keyword control-flow\",\n          children: \"return\"\n        }), \" \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"(\"\n        }), \"\\n    \", _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Protect\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n      \"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"{\"\n        }), _jsx(_components.span, {\n          className: \"token comment\",\n          children: \"/* The template responsible for rendering a single post */\"\n        }), _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n      \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"<\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"PostTemplate\"\n            })]\n          }), \" \", _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \"/>\"\n          })]\n        }), _jsx(_components.span, {\n          className: \"token plain-text\",\n          children: \"\\n    \"\n        }), _jsxs(_components.span, {\n          className: \"token tag\",\n          children: [_jsxs(_components.span, {\n            className: \"token tag\",\n            children: [_jsx(_components.span, {\n              className: \"token punctuation\",\n              children: \"</\"\n            }), _jsx(_components.span, {\n              className: \"token class-name\",\n              children: \"Protect\"\n            })]\n          }), _jsx(_components.span, {\n            className: \"token punctuation\",\n            children: \">\"\n          })]\n        }), \"\\n  \", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \")\"\n        }), \"\\n\", _jsx(_components.span, {\n          className: \"token punctuation\",\n          children: \"}\"\n        }), \"\\n\"]\n      })\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"I found that leaving this layer as simple as possible then also helped in those few situations where an extra context was needed but I couldn't re-architect a template. It's a safety net that's served me well.\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Atomic Design in React: Prop Drilling and Contexts\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Atomic design doesn't specifically mention anything about where props should be used or where contexts should be used but I found this to be a crucial decision to keep the application scalable.\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"The problem\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"A lot of my data fetching and mutating is handled exclusively by hooks. So I'll have a hook called \", _jsx(_components.code, {\n        children: \"usePosts()\"\n      }), \" which returns the post data but will also contain methods like \", _jsx(_components.code, {\n        children: \"doDelete\"\n      }), \" or \", _jsx(_components.code, {\n        children: \"doEdit\"\n      }), \". This is great for keeping everything separate and easy to test, but at some point it needs to be imported in a component for the data to be displayed.\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Once the hook is imported in a component, that component will be forever dependent on that specific context exiting somewhere higher up in the component tree. It makes code simple to read but could potentially kill the reusability of that component.\"\n    }), \"\\n\", _jsx(_components.h3, {\n      children: \"My solution\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"While this is an entirely arbitrary solution, I decided very early on to only use hook and contexts in:\"\n    }), \"\\n\", _jsxs(_components.ul, {\n      children: [\"\\n\", _jsxs(_components.li, {\n        children: [_jsx(_components.strong, {\n          children: \"Templates\"\n        }), \" - Where the contexts are usually set up\"]\n      }), \"\\n\", _jsxs(_components.li, {\n        children: [_jsx(_components.strong, {\n          children: \"Organisms\"\n        }), \" - Where contexts are usually consumed\"]\n      }), \"\\n\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"Any data that needs to be displayed in molecules is passed down as a prop. This allows molecules to be as reusable as possible while organisms (which are usually page specific) can still enjoy the benefits of using hooks and contexts.\"\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Atomic Design in React: The gap component saved my life\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"A key rule of Atomic Design in React is to never add margins or paddings to molecules and organisms. This seems silly, but it helps a lot with reusability. Some components might need padding in certain situations, but not in others!\"\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"This is a good rule to follow on paper, but in practice it means \", _jsx(_components.strong, {\n        children: \"adding a lot of divs\"\n      }), \" just to have spacing, which pads out code and looks really nasty. What helped a lot in this situation was Tailwind's \", _jsx(_components.code, {\n        children: \"space\"\n      }), \" class:\"]\n    }), \"\\n\", _jsx(_components.p, {\n      children: _jsx(_components.img, {\n        src: \"/images/screenshot-2021-11-28-161003.png\",\n        alt: \"\",\n        width: \"847\",\n        height: \"433\"\n      })\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"Space works much like the \", _jsx(_components.a, {\n        href: \"https://developer.mozilla.org/en-US/docs/Web/CSS/gap\",\n        children: \"CSS gap property\"\n      }), \", except it's actually supported by all browsers. Gap doesn't have widespread support among older Apple devices so it might still be a bit before we can use it!\"]\n    }), \"\\n\", _jsxs(_components.p, {\n      children: [\"In case you're not using Tailwind or you're not in the mood to get CSS hacks together, I would suggest replicating \", _jsxs(_components.a, {\n        href: \"https://ant.design/components/space/\",\n        children: [\"Ant Design's \", _jsx(_components.code, {\n          children: \"<Space>\"\n        }), \" component\"]\n      }), \" which works much the same but uses props rather than CSS.\"]\n    }), \"\\n\", _jsx(_components.h2, {\n      children: \"Final thoughts about Atomic Design in React\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"My main reason for using Atomic Design was to make our codebase easier for people with little to no experience in React to easily find their way, and while I didn't end up following it exactly it has definitely worked. Components are clearly separated while still being easy to test and reuse.\"\n    }), \"\\n\", _jsx(_components.p, {\n      children: \"I really like how it has a very strong base, but isn't strict enough to stop experimentation and rule-bending. I guess time will tell if my changes are terrible or if they don't end up impacting a lot, but as of now I'm very satisfied with the results.\"\n    })]\n  });\n}\nfunction MDXContent(props = {}) {\n  const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n  return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n    children: _jsx(_createMdxContent, props)\n  })) : _createMdxContent(props);\n}\nreturn {\n  default: MDXContent\n};\n","frontmatter":{},"scope":{}}}]