<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:base="https://gergotakacs.dev/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Gergő Takács</title>
    <link>https://gergotakacs.dev/</link>
    <atom:link href="https://gergotakacs.dev/feed.xml" rel="self" type="application/rss+xml" />
    <description>This is a longer description about your blog.</description>
    <language>en</language>
    <item>
      <title>What do I use AI for?</title>
      <link>https://gergotakacs.dev/blog/what-do-i-use-ai-for/</link>
      <description>&lt;p&gt;For better or worse generative AI is a part of our lives now. As a tool it can be &lt;a href=&quot;https://kotaku.com/twitch-streamer-ai-jesus-fortnite-star-wars-chatgpt-1850533473&quot;&gt;entertaining&lt;/a&gt; but useless, very handy, or even downright &lt;a href=&quot;https://arstechnica.com/information-technology/2024/02/deepfake-scammer-walks-off-with-25-million-in-first-of-its-kind-ai-heist/&quot;&gt;scary&lt;/a&gt;. People&#39;s opinion on it is just as varied. Doomers think the current generation of AI is the harbinger of a more powerful &lt;abbr title=&quot;Artificial General Intelligence&quot;&gt;AGI&lt;/abbr&gt; that will bring the &lt;a href=&quot;https://futureoflife.org/open-letter/pause-giant-ai-experiments/&quot;&gt;end of civilization&lt;/a&gt;. On the other end of the spectrum there are people who think it&#39;s the best thing since sliced bread. For companies it is a money printing machine. Everyone is trying to replicate OpenAI&#39;s success. This is how you end up with &lt;a href=&quot;https://daringfireball.net/linked/2024/05/06/hackett-logitech-mouse-driver&quot;&gt;AI in your mouse software&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&#39;m – and I assume most people are – somewhere in the middle. I find most of the criticism against generative AI to be genuinely concerning, I don&#39;t think we should be pouring as much money into it as we are now. However I don&#39;t see it as the destroyer of worlds, neither do I think it will drastically change how I work. It&#39;s just another tool in my toolbox.&lt;/p&gt;
&lt;h2 id=&quot;the-bad&quot; tabindex=&quot;-1&quot;&gt;The bad&lt;/h2&gt;
&lt;p&gt;Generative AI in its current form is far from being ethical or environmentally friendly. As is often the case with technological advancements, regulators are playing catch-up. It is used by malicious actors to spread misinformation, it is being &lt;a href=&quot;https://www.wired.com/story/perplexity-is-a-bullshit-machine/&quot;&gt;trained on content it was told to ignore&lt;/a&gt;, it requires a &lt;a href=&quot;https://www.washingtonpost.com/business/2024/10/08/google-meta-omaha-data-centers/&quot;&gt;shit-ton of electricity&lt;/a&gt; to train and run... I could go on for paragraphs. Does this mean I completely avoid using these tools? No, just as I still use a car and travel by plane, even though I&#39;m aware of their impact on our planet. However I try to be considerate – even conservative – in my usage of AI.&lt;/p&gt;
&lt;h2 id=&quot;the-good&quot; tabindex=&quot;-1&quot;&gt;The good&lt;/h2&gt;
&lt;p&gt;Now to answer the question in the title, I will go over some use cases where I&#39;ve found AI (more specifically LLMs) to be genuinely helpful.&lt;/p&gt;
&lt;p&gt;One such area is search. Traditional search engines can be pretty good at knowing what you are looking for, even if you are not searching for the right words. However if you are looking for something that you can&#39;t easily express in a couple of keywords, finding the exact thing you need can seem impossible. A piece of relevant context, if it does not appear in the page you are looking for, can completely derail your keyword search, but can be just what ChatGPT needs to point you in the right direction.&lt;/p&gt;
&lt;p&gt;Considering how shitty Google search results have become, I can&#39;t wait for more AI based search engines to emerge&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://gergotakacs.dev/blog/what-do-i-use-ai-for/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;As a non-english speaker I also reach for an LLM when I&#39;m struggling to make a sentence sound professional. This is an area where I really want to avoid overusing it. I only use it as a last resort, and only for rephrasing no more than a single sentence. It should improve my vocabulary, not make me lazy&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://gergotakacs.dev/blog/what-do-i-use-ai-for/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;It is also really good at reading documentation, so you don&#39;t have to &lt;abbr title=&quot;Read The Fucking Manual&quot;&gt;RTFM&lt;/abbr&gt;. I work a lot with a datagrid library called &lt;a href=&quot;https://ag-grid.com&quot;&gt;AG Grid&lt;/a&gt;. It has a crazy number of configuration options, so sometimes it can be a pain to figure out which ones I need to “make it work like Excel”. Often the easiest way is to just describe to ChatGPT what I need and let it figure it out for me. For a popular library like AG Grid it works pretty well. Some companies even provide an LLM-backed chat interface right in their documentation. This lets them train the model on their docs to provide even better answers&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://gergotakacs.dev/blog/what-do-i-use-ai-for/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;When it comes to writing code, I don&#39;t rely on AI tools too much. My typing speed is not what prevents me from shipping features faster, so tools like &lt;a href=&quot;https://github.com/features/copilot&quot;&gt;GitHub Copilot&lt;/a&gt; – although impressive – don&#39;t provide too much value to me. The times when I reach for ChatGPT are when I&#39;m working on repetitive, but hard to automate tasks, typically refactoring.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;As these tools mature I can see myself incorporating them into my workflow in more ways. More and more tools are popping up where AI is not just an optional feature but the whole premise. Tools like Vercel&#39;s &lt;a href=&quot;https://v0.dev/&quot;&gt;v0&lt;/a&gt; or StackBlitz&#39;s &lt;a href=&quot;https://bolt.new/&quot;&gt;bolt.new&lt;/a&gt; are already empowering people to quickly prototype their ideas even if they lack the technical expertise to develop something from scratch. I&#39;m certain our IDE of the future will look a lot like these tools. As to what this means for the quality of our software? Well...&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Since I&#39;ve started writing this article OpenAI has released &lt;a href=&quot;https://openai.com/index/introducing-chatgpt-search/&quot;&gt;ChatGPT Search&lt;/a&gt;, which – as a non-premium user – I have not had a chance to try yet. &lt;a href=&quot;https://gergotakacs.dev/blog/what-do-i-use-ai-for/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I don&#39;t use it for blog posts though. On this site you will only find 100% handcrafted, artisan, freerange sentences. &lt;a href=&quot;https://gergotakacs.dev/blog/what-do-i-use-ai-for/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://houston.astro.build/&quot;&gt;https://houston.astro.build/&lt;/a&gt; &lt;a href=&quot;https://gergotakacs.dev/blog/what-do-i-use-ai-for/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Thu, 14 Nov 2024 24:00:00 GMT</pubDate>
      <dc:creator>Gergő Takács</dc:creator>
      <guid>https://gergotakacs.dev/blog/what-do-i-use-ai-for/</guid>
    </item>
    <item>
      <title>What can YOU do for a more accessible web?</title>
      <link>https://gergotakacs.dev/blog/what-can-you-do-for-a-more-accessible-web/</link>
      <description>&lt;p&gt;In most of the teams I&#39;ve worked in, accessibility was an afterthought. Early in my career it was my own ignorance, later I was actively discouraged by managers from spending time on it. I care about the work I do, and I feel like it is - at least partly - my responsibility to make sure the products I work on are accessible to everyone. I&#39;ve found a few ways how I, a single developer, can spread awareness and start meaningful change in the teams I work in.&lt;/p&gt;
&lt;h2 id=&quot;step-zero&quot; tabindex=&quot;-1&quot;&gt;Step zero&lt;/h2&gt;
&lt;p&gt;First things first, &lt;strong&gt;educate yourself&lt;/strong&gt; on the topic. If you have opened this article, you probably already have this box ticked. If you feel like doing a brush-up on the topic, I&#39;ve listed some great resources at the end of the article.&lt;/p&gt;
&lt;h2 id=&quot;convincing-stakeholders&quot; tabindex=&quot;-1&quot;&gt;Convincing stakeholders&lt;/h2&gt;
&lt;p&gt;Depending on what kind of product you are working on, getting management on board can be &lt;strong&gt;either easy or impossible&lt;/strong&gt;. If your team is developing internal tools, your manager will be quick to point out, that they personally know all the users, and they all have 20/20 vision, three perfectly healthy hands, and ears like a bat. I&#39;d still argue that these tools should be accessible, but you will have a hard time convincing your boss.&lt;/p&gt;
&lt;p&gt;You will have better chances at success if you are working on something public. Corporations only speak the language of money, so you should try to make your case by letting your manager know &lt;strong&gt;how much money the company could lose by neglecting accessibility&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;they-lose-customers&quot; tabindex=&quot;-1&quot;&gt;They lose customers&lt;/h3&gt;
&lt;p&gt;Nearly a &lt;strong&gt;quarter of people aged 16 years or over in the EU had a disability in 2024&lt;/strong&gt;.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://gergotakacs.dev/blog/what-can-you-do-for-a-more-accessible-web/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; If people cannot use your company&#39;s product, they will go to a competitor.&lt;/p&gt;
&lt;p&gt;Creating accessible websites can also indirectly boost SEO. Writing well-structured, semantic HTML helps both users of assistive technologies and web crawlers access a site&#39;s contents.&lt;/p&gt;
&lt;h3 id=&quot;they-can-face-fines&quot; tabindex=&quot;-1&quot;&gt;They can face fines&lt;/h3&gt;
&lt;p&gt;If your company operates in the EU, its products might be &lt;strong&gt;legally required to meet a certain level of &lt;a href=&quot;https://www.w3.org/WAI/standards-guidelines/wcag/&quot;&gt;WCAG&lt;/a&gt; compliance.&lt;/strong&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://gergotakacs.dev/blog/what-can-you-do-for-a-more-accessible-web/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; Businesses failing to comply can face serious fines.&lt;/p&gt;
&lt;h3 id=&quot;accessibility-overlays&quot; tabindex=&quot;-1&quot;&gt;Accessibility overlays&lt;/h3&gt;
&lt;p&gt;As a quick aside I want to mention accessibility overlays. Companies like AccessiBe or AudiEye advertise their products as a &lt;strong&gt;quick and easy solution&lt;/strong&gt; to make a website accessible, and avoid fines. Just add a single third-party script and *poof*, your site is accessible. However, the truth is that these tools not only &lt;strong&gt;fail to fulfill this promise&lt;/strong&gt;, in some cases they can even make it harder for disabled users to use your site.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://gergotakacs.dev/blog/what-can-you-do-for-a-more-accessible-web/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt; Their pitch does sound good, so I don&#39;t blame businesses for falling for it. It is your job to let your boss know what they risk by taking this shortcut. &lt;a href=&quot;https://overlayfactsheet.com/en/&quot;&gt;Overlay Fact Sheet&lt;/a&gt; is a great resource to help you convince them.&lt;/p&gt;
&lt;h2 id=&quot;fostering-an-accessibility-culture&quot; tabindex=&quot;-1&quot;&gt;Fostering an accessibility culture&lt;/h2&gt;
&lt;p&gt;Having everyone on board is a good start, but not enough. In my experience, most companies don&#39;t have a dedicated accessibility team, so &lt;strong&gt;it is up to you - the developer - to make sure your team&#39;s work is accessible&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Automate as much as you can. Most testing frameworks and linters have accessibility add-ons. Use them! Make them part of your CI process!&lt;/p&gt;
&lt;p&gt;Manual testing is also important, so make sure it is not forgotten. Even a single checklist item in your issue or PR template can go a long way. As an example here is what my team uses:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;[] I have reviewed the &lt;strong&gt;accessibility&lt;/strong&gt; impact of my changes and tested new UI features following our accessibility evaluation guide, or confirmed that no UI changes were made.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Good intentions are not enough if you don&#39;t know what you are doing. Compile a list of resources and tools to help your team properly test their work. I&#39;ve listed some of my recommendations at the end of this article.&lt;/p&gt;
&lt;p&gt;Do you have some downtime between tickets? Load up a page and conduct an audit. Let your manager know the results, so they can plan how you are going to tackle the issues.&lt;/p&gt;
&lt;h2 id=&quot;can-ai-help%3F&quot; tabindex=&quot;-1&quot;&gt;Can AI help?&lt;/h2&gt;
&lt;p&gt;You cannot write an article in 2025 without mentioning AI. I&#39;ve found &lt;strong&gt;some use cases where generative AI shines&lt;/strong&gt;, however &lt;strong&gt;accessibility is not one of them&lt;/strong&gt;. The reason for this is that LLM&#39;s are trained on the web, and let&#39;s be honest, the web is in large, inaccessible.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://gergotakacs.dev/blog/what-can-you-do-for-a-more-accessible-web/#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt; Surely, they can be used to generate alt text, newer models are great at describing images. Well, not so much... Yes, good alt text should describe what&#39;s on a particular image. But it should also capture context and nuance. For example, take the following alt text I&#39;ve generated using ChatGPT. Try to imagine what the original image would look like.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“An older man with a white beard and a light-colored shirt is smiling and giving a thumbs up, sitting indoors in a bright room.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, take a look at &lt;a href=&quot;https://gergotakacs.dev/blog/what-can-you-do-for-a-more-accessible-web/harold.png&quot;&gt;the image&lt;/a&gt;. If you are unfamiliar with this person, he is known by the name &lt;a href=&quot;https://knowyourmeme.com/memes/hide-the-pain-harold&quot;&gt;Hide the Pain Harold&lt;/a&gt;.
He got popular because of his facial expression that seems to hide some discomfort behind a forced smile. In the LLM&#39;s description this nuance is completely lost.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Even though recent legislation brings more attention to the topic, without proper education and advocates, accessibility will not be solved. Are my tips groundbreaking? Definitely not. With a little attention and some proactivity, even a single dev can do a lot for a more accessible internet.&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot; tabindex=&quot;-1&quot;&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Accessibility/What_is_accessibility#so_what_is_accessibility&quot;&gt;MDN: What is accessibility?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.a11yproject.com/checklist/&quot;&gt;Checklist - The A11Y Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webaim.org/standards/wcag/checklist&quot;&gt;WebAIM - WCAG 2 Checklist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/quickref/&quot;&gt;How to meet WCAG?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/&quot;&gt;Accessible UI patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.freecodecamp.org/news/how-to-perform-a-web-accessibility-audit/&quot;&gt;How to perform an accessibility audit?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2025/04/fostering-accessibility-culture/&quot;&gt;Fostering an accessibility culture&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://ec.europa.eu/eurostat/statistics-explained/index.php?title=Population_with_disability&quot;&gt;https://ec.europa.eu/eurostat/statistics-explained/index.php?title=Population_with_disability&lt;/a&gt; &lt;a href=&quot;https://gergotakacs.dev/blog/what-can-you-do-for-a-more-accessible-web/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://commission.europa.eu/strategy-and-policy/policies/justice-and-fundamental-rights/disability/union-equality-strategy-rights-persons-disabilities-2021-2030/european-accessibility-act_en&quot;&gt;https://commission.europa.eu/strategy-and-policy/policies/justice-and-fundamental-rights/disability/union-equality-strategy-rights-persons-disabilities-2021-2030/european-accessibility-act_en&lt;/a&gt; &lt;a href=&quot;https://gergotakacs.dev/blog/what-can-you-do-for-a-more-accessible-web/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://www.vice.com/en/article/people-with-disabilities-say-this-ai-tool-is-making-the-web-worse-for-them/&quot;&gt;https://www.vice.com/en/article/people-with-disabilities-say-this-ai-tool-is-making-the-web-worse-for-them/&lt;/a&gt; &lt;a href=&quot;https://gergotakacs.dev/blog/what-can-you-do-for-a-more-accessible-web/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://almanac.httparchive.org/en/2024/accessibility&quot;&gt;https://almanac.httparchive.org/en/2024/accessibility&lt;/a&gt; &lt;a href=&quot;https://gergotakacs.dev/blog/what-can-you-do-for-a-more-accessible-web/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Fri, 26 Sep 2025 18:22:55 GMT</pubDate>
      <dc:creator>Gergő Takács</dc:creator>
      <guid>https://gergotakacs.dev/blog/what-can-you-do-for-a-more-accessible-web/</guid>
    </item>
    <item>
      <title>Showcasing my demos</title>
      <link>https://gergotakacs.dev/blog/showcasing-my-demos/</link>
      <description>&lt;p&gt;I have a &lt;a href=&quot;https://github.com/spiroka/demos&quot;&gt;repository for my demos and experiments&lt;/a&gt; that I wanted to showcase on my website. I wanted to keep these separate from and agnostic of my site code. For this I needed a set of constraints that each demo follows, that are flexible enough to allow me to build them any way I want.&lt;/p&gt;
&lt;h2 id=&quot;first-rule%3A-each-demo-should-be-a-static-website&quot; tabindex=&quot;-1&quot;&gt;First rule: each demo should be a static website&lt;/h2&gt;
&lt;p&gt;This is a static site, built with &lt;a href=&quot;https://11ty.dev&quot;&gt;11ty&lt;/a&gt; and hosted on a CDN. I wanted my demos to be a directory that I can just copy as-is to my 11ty build output. The demos repository is an npm workspaces project with a build script in the root project, that just calls the build script of each subproject. The build step of each subproject can be anything, as long as the result is a directory in the root project&#39;s build folder with &lt;strong&gt;at least an &lt;code&gt;index.html&lt;/code&gt;&lt;/strong&gt; in it.&lt;/p&gt;
&lt;p&gt;Since all these projects are and will be web-related, this rule was easy to follow.&lt;/p&gt;
&lt;p&gt;The repository is added as a git submodule to my main site repo and built separately before the 11ty build.&lt;/p&gt;
&lt;h2 id=&quot;second-rule%3A-each-demo-should-be-able-to-describe-itself&quot; tabindex=&quot;-1&quot;&gt;Second rule: each demo should be able to describe itself&lt;/h2&gt;
&lt;p&gt;I needed some metadata about each demo to be able to display them in a collection. For this I chose the &lt;a href=&quot;https://ogp.me/&quot;&gt;Open Graph protocol&lt;/a&gt;. &lt;strong&gt;Open Graph tags&lt;/strong&gt; are easy to parse and 11ty agnostic so they fit the bill perfectly. For scraping the metadata from the html content of each demo, I chose the &lt;a href=&quot;https://github.com/jshemas/openGraphScraperLite&quot;&gt;open-graph-scraper-lite&lt;/a&gt; npm package.&lt;/p&gt;
&lt;h2 id=&quot;bringing-it-all-together&quot; tabindex=&quot;-1&quot;&gt;Bringing it all together&lt;/h2&gt;
&lt;p&gt;Now all I needed was to make each demo reachable as a page on my site and to have them available as an &lt;a href=&quot;https://www.11ty.dev/docs/collections/&quot;&gt;11ty collection&lt;/a&gt;, so I can render them into a list.&lt;/p&gt;
&lt;p&gt;For the prior all I needed was a simple &lt;a href=&quot;https://www.11ty.dev/docs/copy/&quot;&gt;passthrough copy&lt;/a&gt; to copy the demos folder to the build output.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addPassthroughCopy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;demos/build&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/demos&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To create a collection I needed to read all directories in the demos folder, scrape the Open Graph tags and add each item to the &lt;code&gt;demos&lt;/code&gt; collection.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ogs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;open-graph-scraper-lite&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addCollection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;demos&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// read all directories&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; demoDirs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readdir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;demos/build&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;withFileTypes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;dirent&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; dirent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isDirectory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;demoDirs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// get html content&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; contents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;demos/build&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;index.html&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// scrape OG tags&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
        &lt;span class=&quot;token literal-property property&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ogTitle&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ogDescription&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; articleTag &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ogs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; contents&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ogTitle&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ogDescription&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/demos/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; articleTag&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last step was to create a page for showcasing the demos. Behold &lt;a href=&quot;https://gergotakacs.dev/the-shed&quot;&gt;the shed&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Sun, 24 Mar 2024 18:47:27 GMT</pubDate>
      <dc:creator>Gergő Takács</dc:creator>
      <guid>https://gergotakacs.dev/blog/showcasing-my-demos/</guid>
    </item>
    <item>
      <title>How I shaved off megabytes from our React applications&#39; bundle size</title>
      <link>https://gergotakacs.dev/blog/how-i-halved-the-bundle-size-of-our-react-applications/</link>
      <description>&lt;p&gt;Single page application frameworks get a lot of (well deserved) flak for producing enormous JavaScript bundles. Although some of this bloat cannot be avoided, it is worth taking a closer look at your setup, because a misconfigured toolchain can add KBs or even MBs to your app&#39;s final size.&lt;/p&gt;
&lt;p&gt;In this post I explain how I shaved off almost half the size of some of our applications by changing how our internal NPM libraries are built.&lt;/p&gt;
&lt;h2 id=&quot;initial-setup&quot; tabindex=&quot;-1&quot;&gt;Initial setup&lt;/h2&gt;
&lt;p&gt;For the purpose of showing the issue I&#39;ve created a stripped-down version of our app. It is a monorepo setup of a &lt;a href=&quot;https://vite.dev&quot;&gt;Vite&lt;/a&gt; based React application and a component library, both written in TypeScript. The library package uses an open-source general purpose component library called &lt;a href=&quot;https://blueprintjs.com/&quot;&gt;BlueprintJS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The example app renders a single BlueprintJS button imported from the component library.&lt;/p&gt;
&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// app/src/App.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; MyButton &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;lib&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MyButton&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; App&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// lib/index.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Button &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@blueprintjs/core&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; IconNames &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@blueprintjs/icons&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyButton&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Button&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;rightIcon&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;IconNames&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;COG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simple enough, right? The app bundle shouldn&#39;t be more than a few kilobytes. Let&#39;s do a prod build!&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://gergotakacs.dev/img/sbvbems-gR-1016.webp 1016w&quot;&gt;&lt;img src=&quot;https://gergotakacs.dev/img/sbvbems-gR-1016.png&quot; alt=&quot;Output of the Vite build with initial setup. The resulting bundle is more then 2MBs in size.&quot; width=&quot;1016&quot; height=&quot;258&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;HOLY CANNOLI! How did THAT happen?! That bundle is so fat, it has its own ZIP code. Let&#39;s take a look inside the bundle and see what we can find out. We can use &lt;a href=&quot;https://www.npmjs.com/package/vite-bundle-visualizer&quot;&gt;vite-bundle-visualizer&lt;/a&gt; for that.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://gergotakacs.dev/img/XyBD2ESRFK-2414.webp 2414w&quot;&gt;&lt;img src=&quot;https://gergotakacs.dev/img/XyBD2ESRFK-2414.png&quot; alt=&quot;Output of vite-bundle-visualizer showing many files inside our bundle.&quot; width=&quot;2414&quot; height=&quot;1149&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;&lt;a href=&quot;https://gergotakacs.dev/blog/how-i-halved-the-bundle-size-of-our-react-applications/bundle1.png&quot;&gt;See the image in full&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Looks like the entire BlueprintJS library has been included into our bundle. To understand how this happened we need to take a closer look at our component library and learn a bit about how bundlers work.&lt;/p&gt;
&lt;p&gt;Before we got ES modules, JavaScript had several non-standard module systems. Historically npm packages used a module system called CommonJS, since that was the default for NodeJS. By design CommonJS is dynamic, which makes it hard to statically analyze. The problem with this is that bundlers analyze your modules so that in the final bundle only the code that you actually use is included. This process is called tree-shaking. Nowadays most npm packages are provided as both ES and CommonJS modules as well. This is true for BlueprintJS as well. So how come we ended up with Godzilla in our build folder?&lt;/p&gt;
&lt;p&gt;Before being imported into our app, the component library is run through the TypeScript compiler. Let&#39;s take a look at the compiler&#39;s output.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;use strict&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;exports&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;__esModule&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
exports&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;MyButton &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MyButton&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; jsx_runtime_1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;react/jsx-runtime&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; core_1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@blueprintjs/core&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; icons_1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@blueprintjs/icons&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyButton&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; jsx_runtime_1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jsx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;core_1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Button&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;rightIcon&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; icons_1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;IconNames&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;COG&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those &lt;code&gt;require()&lt;/code&gt; calls are a clear sign that
this code is using CommonJS. So even if our app uses ES modules, we will end up with the CommonJS variant of BlueprintJS because of how our component library is built.&lt;/p&gt;
&lt;p&gt;Let&#39;s fix this!&lt;/p&gt;
&lt;h2 id=&quot;the-fix&quot; tabindex=&quot;-1&quot;&gt;The fix&lt;/h2&gt;
&lt;p&gt;Thankfully we don&#39;t have to do much to tell the TypeScript compiler what module system to use.&lt;/p&gt;
&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;// tsconfig.json
{
...
&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  &quot;module&quot;: &quot;commonjs&quot;,
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &quot;module&quot;: &quot;esnext&quot;,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &quot;moduleResolution&quot;: &quot;bundler&quot;,
&lt;/span&gt;...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First we set &lt;code&gt;module&lt;/code&gt; to &lt;code&gt;esnext&lt;/code&gt; to tell TypeScript that the compiled code should use ES modules. When using this option we are also required to set the &lt;code&gt;moduleResolution&lt;/code&gt; option to tell TypeScript how it should resolve imports. If your code will be bundled – like in our case – the recommended value to use is &lt;code&gt;bundler&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As I mentioned above, it is possible for a library to provide both ES and CommonJS modules, but I will not be getting into that in this article. If you would like to learn more about creating npm packages, I suggest you take a look at this &lt;a href=&quot;https://www.totaltypescript.com/how-to-create-an-npm-package&quot;&gt;wonderful article by Matt Pocock&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;results&quot; tabindex=&quot;-1&quot;&gt;Results&lt;/h2&gt;
&lt;p&gt;Now that our tsconfig is updated, let&#39;s do another build and see how our output changes.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; jsx &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; _jsx &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react/jsx-runtime&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Button &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@blueprintjs/core&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; IconNames &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@blueprintjs/icons&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyButton&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_jsx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Button&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;rightIcon&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; IconNames&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;COG&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time the compiled code is almost identical to our original source code, it is no longer using CommonJS. Only the jsx parts have been transpiled.&lt;/p&gt;
&lt;p&gt;Let&#39;s see how this change affects our application bundle.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://gergotakacs.dev/img/4r0c60fhxV-981.webp 981w&quot;&gt;&lt;img src=&quot;https://gergotakacs.dev/img/4r0c60fhxV-981.png&quot; alt=&quot;Output of the Vite build after updating the component library. The resulting bundle is split into 3 javascript bundles, totalling at around 700KBs.&quot; width=&quot;981&quot; height=&quot;394&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;This looks much better. Our bundle is now split into three much smaller JavaScript files. The code-splitting occured because the ES module variant of BlueprintJS utilizes dynamic imports, which if encountered by Vite will cause a split.&lt;/p&gt;
&lt;h2 id=&quot;takeaways&quot; tabindex=&quot;-1&quot;&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;Although this article focuses on a specific issue and its solution, my main takeaways are more general. First of all the bundle should not be treated as a black box, you can and should take a look inside to spot potential issues. And most importantly, you should familiarize yourself with the tools you use in order to make the best possible version of your app.&lt;/p&gt;
&lt;p&gt;You can find the source code of the example here: &lt;a href=&quot;https://github.com/spiroka/bundle-size-demo&quot;&gt;https://github.com/spiroka/bundle-size-demo&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Fri, 06 Dec 2024 24:00:00 GMT</pubDate>
      <dc:creator>Gergő Takács</dc:creator>
      <guid>https://gergotakacs.dev/blog/how-i-halved-the-bundle-size-of-our-react-applications/</guid>
    </item>
    <item>
      <title>Color theory essentials for CSS</title>
      <link>https://gergotakacs.dev/blog/color-theory-for-dummies/</link>
      <description>&lt;p&gt;I was having a rough time recently trying to understand how the &lt;a href=&quot;https://developer.mozilla.org/en-US/blog/css-color-module-level-4/&quot;&gt;new CSS color functions&lt;/a&gt; work and why they are better than what we had before. I&#39;ve been using colors in CSS for a decade, but besides knowing what the three letters in RGB stood for, I knew nothing about color theory.&lt;/p&gt;
&lt;p&gt;This article assumes that you have at least heard about the new CSS color features. Its goal is to clear up the most common terms in the topic, it is not meant to be a deep dive by any means – it is probably not even entirely accurate – but thinking about them this way helped me make sense of all the new color features.&lt;/p&gt;
&lt;h2 id=&quot;color-space&quot; tabindex=&quot;-1&quot;&gt;Color space&lt;/h2&gt;
&lt;p&gt;A color space is a &lt;strong&gt;range of colors&lt;/strong&gt;, like the &lt;a href=&quot;https://en.wikipedia.org/wiki/CIE_1931_color_space&quot;&gt;range of colors visible to the human eye&lt;/a&gt;. Historically in CSS we could only define colors in the sRGB space, which is roughly one third of the visible color spectrum.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://gergotakacs.dev/blog/color-theory-for-dummies/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; Modern displays are capable of showing way more colors than that. We will call the colors that fall into this wider range, high definition colors.&lt;/p&gt;
&lt;p&gt;The CSS Color Level 4 spec introduced several &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color#colorspace&quot;&gt;new color spaces&lt;/a&gt; that we can utilize with the new functions. These are already supported in most browsers&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://gergotakacs.dev/blog/color-theory-for-dummies/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;, so you can start making your websites more colorful.&lt;/p&gt;
&lt;h2 id=&quot;color-model&quot; tabindex=&quot;-1&quot;&gt;Color model&lt;/h2&gt;
&lt;p&gt;A color model is a &lt;strong&gt;mathematical model for expressing colors&lt;/strong&gt;. Think of them as functions, that take some parameters and return a color. For example in CSS the &lt;code&gt;rgb()&lt;/code&gt; and &lt;code&gt;hsl()&lt;/code&gt; color functions are based on models with the same names.&lt;/p&gt;
&lt;p&gt;Although technically incorrect, it is common to refer to models as color spaces&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://gergotakacs.dev/blog/color-theory-for-dummies/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;, which confused the hell out of me initially. The reason for this is that in practice, models are accompanied by a mapping function which maps the values of the model to a color in a color space. This means that a particular combination of model and mapping function will identify a color space.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://gergotakacs.dev/img/7SDWctdvTW-500.webp 500w&quot;&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;https://gergotakacs.dev/img/7SDWctdvTW-500.png 500w&quot;&gt;&lt;img src=&quot;https://gergotakacs.dev/img/7SDWctdvTW-500.jpeg&quot; alt=&quot;A meme making fun of how I would correct someone when they use the term &amp;quot;color space&amp;quot; incorrectly.&quot; width=&quot;500&quot; height=&quot;567&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Choosing what model to use is not just about preference. Let&#39;s say I want the background color of a button to be slightly lighter when it is hovered. If the original color is defined as a hex value, I would probably reach for a color picker to get the lighter version. With the introduction of &lt;code&gt;hsl()&lt;/code&gt; into CSS, manipulating color got a lot simpler. It makes more sense what changing each value will do to the color. With &lt;code&gt;hsl()&lt;/code&gt;, getting the lighter color is just a matter of increasing the value of the third (lightness) parameter, I don&#39;t even have to leave my editor.&lt;/p&gt;
&lt;p&gt;The Color Level 4 spec introduced a bunch of &lt;a href=&quot;https://developer.mozilla.org/en-US/blog/css-color-module-level-4/#new_functional_notation_for_colors&quot;&gt;new color functions&lt;/a&gt;, that – besides giving us a broader range of colors to choose from – have further improved the way we work with colors.&lt;/p&gt;
&lt;h2 id=&quot;gamut&quot; tabindex=&quot;-1&quot;&gt;Gamut&lt;/h2&gt;
&lt;p&gt;A gamut – just like a color space – is a &lt;strong&gt;range of colors&lt;/strong&gt;. The difference is that gamut refers to the colors that &lt;strong&gt;a device&lt;/strong&gt; (eg. a monitor or printer) &lt;strong&gt;can display or reproduce within a color space&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;With the new color spaces in CSS we can take advantage of wide gamut displays. While browsers are smart enough to approximate high definition colors on devices that don&#39;t support them, providing a fallback ourselves can yield better results. Just like with other device characteristics, we will use a media query to check if the user&#39;s display supports a specific gamut.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* fallback color */&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;/* check if the user&#39;s browser supports oklch() */&lt;/span&gt;
  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@supports&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* check if the display supports the p3 gamut */&lt;/span&gt;
    &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;color-gamut&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; p3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;45% 0.3 264&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To know what gamut to test for, given a certain color, you can use a color picker that provides this information (eg. &lt;a href=&quot;https://oklch.com&quot;&gt;oklch.com&lt;/a&gt;) or use the &lt;a href=&quot;https://github.com/fpetrakov/stylelint-gamut&quot;&gt;stylelint-gamut&lt;/a&gt; Stylelint plugin.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;My goal with this post was to summarize the things that have helped me understand the CSS Color Level 4 spec. Having a basic understanding of these three terms should be enough to be able to comfortably use the new color functions.&lt;/p&gt;
&lt;p&gt;If you wish to learn more about the new CSS features, I&#39;ve listed some great articles below.&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot; tabindex=&quot;-1&quot;&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/blog/css-color-module-level-4/&quot;&gt;https://developer.mozilla.org/en-US/blog/css-color-module-level-4/&lt;/a&gt; – An introduction to the spec by MDN.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/css-ui/high-definition-css-color-guide&quot;&gt;https://developer.chrome.com/docs/css-ui/high-definition-css-color-guide&lt;/a&gt; – Lengthy article about the new features by Adam Argyle. Also goes into some color theory.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl&quot;&gt;https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl&lt;/a&gt; – Why the folks at Evil Martians moved to &lt;code&gt;oklch()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/SRGB#/media/File:SRGB_chromaticity_CIE1931.svg&quot;&gt;https://en.wikipedia.org/wiki/SRGB#/media/File:SRGB_chromaticity_CIE1931.svg&lt;/a&gt; &lt;a href=&quot;https://gergotakacs.dev/blog/color-theory-for-dummies/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://caniuse.com/?search=color%20function&quot;&gt;https://caniuse.com/?search=color%20function&lt;/a&gt; &lt;a href=&quot;https://gergotakacs.dev/blog/color-theory-for-dummies/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://developer.chrome.com/docs/css-ui/high-definition-css-color-guide&quot;&gt;https://developer.chrome.com/docs/css-ui/high-definition-css-color-guide&lt;/a&gt; &lt;a href=&quot;https://gergotakacs.dev/blog/color-theory-for-dummies/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Fri, 19 Jan 2024 24:00:00 GMT</pubDate>
      <dc:creator>Gergő Takács</dc:creator>
      <guid>https://gergotakacs.dev/blog/color-theory-for-dummies/</guid>
    </item>
  </channel>
</rss>