<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Javi's Dev Log - Software and Game Development - by Javier Aguilar, Berlin.]]></title><description><![CDATA[Tech blog about software and game development. PHP, Symfony, Golang, JS, React, TypeScript, Unity, Godot, Career Development, Dev Community, Company Culture, Technology and more...]]></description><link>https://blog.itsjavi.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 23 Apr 2026 00:29:34 GMT</lastBuildDate><atom:link href="https://blog.itsjavi.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Styling a sticky element when it gets pinned using React]]></title><description><![CDATA[https://codepen.io/itsjavi/pen/OJGxZeq]]></description><link>https://blog.itsjavi.com/styling-a-sticky-element-when-it-gets-pinned-using-react</link><guid isPermaLink="true">https://blog.itsjavi.com/styling-a-sticky-element-when-it-gets-pinned-using-react</guid><category><![CDATA[React]]></category><category><![CDATA[CSS]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Sat, 30 Mar 2024 01:23:20 GMT</pubDate><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/itsjavi/pen/OJGxZeq">https://codepen.io/itsjavi/pen/OJGxZeq</a></div>
]]></content:encoded></item><item><title><![CDATA[Build your own Full-Stack framework]]></title><description><![CDATA[The state of the Web ecosystem in 2024
Over the last 3 to 4 years, we've witnessed an explosion in the number of frontend and full-stack frameworks and libraries. This boom has added significant variety to an already diverse ecosystem, introducing te...]]></description><link>https://blog.itsjavi.com/build-your-own-js-full-stack-framework</link><guid isPermaLink="true">https://blog.itsjavi.com/build-your-own-js-full-stack-framework</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[full stack]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[vite]]></category><category><![CDATA[React]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Tue, 19 Mar 2024 18:04:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/tOYiQxF9-Ys/upload/84af5d632c28a867a82151d9bfe91f6d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-the-state-of-the-web-ecosystem-in-2024">The state of the Web ecosystem in 2024</h2>
<p>Over the last 3 to 4 years, we've witnessed an explosion in the number of frontend and full-stack frameworks and libraries. This boom has added significant variety to an already diverse ecosystem, introducing technologies like Solid, Svelte, Qwik, Astro, Remix, Vite, Lume, HonoX, Tailwind CSS, Panda CSS, StyleX, and Shadcn UI, among others.</p>
<p>In addition to libraries and frameworks, we've seen the emergence of new and impressively fast JavaScript runtimes, such as Deno, Bun, and WinterJS.</p>
<p>Serverless computing and edge development have also surged in popularity, particularly within the JavaScript community. Platforms like AWS, CloudFlare, and Vercel offer runtime environments specifically tailored to these paradigms, including AWS Lambda with Node, CloudFlare Workers &amp; Pages, and Vercel's Edge Runtime.</p>
<p>In frontend development, we've observed a revival of old paradigms, such as SSG (Static Site Generation), SSR (Server-Side Rendering), and more recently, RSC (React Server Components) and HTML streaming. While some of these concepts aren't new to other programming languages like PHP, they represent fresh approaches within the JavaScript ecosystem.</p>
<p>Another technology that has significantly impacted the industry is Generative AI, influencing the adoption of new technologies (especially HTML streaming) and shaping new paradigms and patterns for developers to learn and adopt.</p>
<p>Given the rapid introduction of these technologies, it's understandable that many of us experience information fatigue. The list of concepts to grasp is extensive, and technology evolves faster than our ability to integrate it sustainably. The new code you write today may well become obsolete in 5 years or less!</p>
<h2 id="heading-nextjs-a-sweet-and-convenient-trap">Next.js: A sweet and convenient trap</h2>
<p>Here's the lowdown on Next.js from a dev's perspective. We're in a golden era of web development, with more tools and frameworks at our disposal than ever before. In this sea of innovation, Next.js stands out, especially for those of us knee-deep in React. It's packed with features that make you want to dive right in. But, it's not all sunshine and rainbows.</p>
<p>The catch with Next.js? It's a bit too cozy with Vercel. Sure, Vercel's free plan is great for starters, but once your project picks up steam, the costs can sneak up on you. As a React developer, I appreciate everything Next.js offers, but the moment you try to step outside the Vercel ecosystem, you hit a wall. It feels like you're boxed in, specially when features like image optimization don't work as good as it does in Vercel, or are simply not supported.</p>
<p>I get it, Vercel is a business and they need to make profit, and they have open sourced the <a target="_blank" href="https://vercel.com/docs/build-output-api/v3">Build Output API</a>, which is a step in the right direction, but the feeling of being locked in doesn't go away. Whenever a big update drops, you're left wondering how it'll affect your project if you're not fully on board with Vercel.</p>
<p>There's some hope with SST and OpenStack working to offer more flexibility, but it's not perfect. Hosting Next.js yourself, say with Docker, means missing out on some features and optimizations (e.g. caching of optimized images).</p>
<p>Then there's the dev server debate. Next.js comes with its own, but Vite is taking the developer world by storm by being adopted in every other major framework and tool. Vite is fast, flexible, and its plugin system is very good. It's hard not to envy Vite users when you're looking for a streamlined and efficient development environment. Parcel is also worth mentioning, looking awesome and all-batteries included since version 2.</p>
<p>In a nutshell, Next.js is great if you're all in with Vercel, but the moment you want more freedom, you start feeling the constraints. It's a bit like being given the best tools for a job but only being allowed to use them in one specific room. We're all searching for that perfect balance of features, flexibility, and freedom. For now, Next.js is a compelling option, but with a few strings attached.</p>
<p>What If I want to deploy certain serverless functions to AWS and others to CloudFlare? Not possible with Next.js alone, you need to integrate CDK or Wrangler in your project and make REST API calls from your Next.js project, making Server Actions pointless.</p>
<h3 id="heading-other-frameworks">Other frameworks</h3>
<p>Other frameworks like Remix and Astro are cool, but they don't offer all features Next.js has.</p>
<p>Astro, for instance, is more focused on offering Static Site Generation rather than dynamic and interactive (although it is still possible).</p>
<p>Remix announced they are studying the possibility to support RSC, but I don't expect it any time soon (probably after React 19 becomes stable).</p>
<p>I personally love React Server Components and the files &amp; layout system of the App Router, but unfortunately I didn't find other frameworks offering something similar yet.</p>
<p>Remix and Astro are projects to follow closely. They have a great developer experience and a good freedom/democracy when it comes to platform interoperability / exportability. Things may get interesting during this and the next year.</p>
<h2 id="heading-the-state-of-react-just-why">The State of React: just why??</h2>
<p>The React team recently announced the upcoming changes that we can expect for React 19.0.</p>
<p>There hasn't been any new React release since Summer 2021, everything has been cooked internally as canary releases that have been adopted by "stable" Next.js releases (sold as production-ready 👀): specially React Server Components and Server Actions.</p>
<p>I am not very happy with these (kind of opaque) decisions. Communication and documentation has been poor in the last years, to the point that the community didn't know at the beginning if RSC &amp; Server Actions were part of React or only specific to Next.js.</p>
<p>I've been also considering changing to Vue, Solid or Svelte, even Astro, but professionally I am still using React every day, so It wouldn't make sense for me to do the switch, I would just consider any of them for small experimental side projects.</p>
<p>The fatigue I talked about in the intro is real, and changing to a new framework wouldn't be productive for me. At the end all you want is to ship great things rather than spending most of your time worrying about the technology: researching, learning, prototyping and then start over again because it didn't work as expected. Learning and research is also part of our job as developers, it is also important, but it becomes problem when it affects our productivity.</p>
<p>All I hope is that, from React 19 on, things start to get easier and more clear for us, and the React team goes back to a normal pace of release cycles.</p>
<h2 id="heading-build-your-own-framework">Build your own framework</h2>
<p>So, after all that's been said and done, you might be feeling like stepping off this wild ride and starting fresh. Why not build your own framework? Just the essentials, nothing more, nothing less.</p>
<p>Honestly, there's never been a better time to do it. As web developers, we've got more resources, tools, and community support than ever before. And it looks like it's only going to get easier from here.</p>
<p>If there's something I miss from my PHP days is having a composable framework like Symfony, the PHP framework. You can adopt Symfony entirely as your only framework or just use some of its components as dependency. You can also build another framework on top of Symfony components, like Laravel did. We should have something similar for full-stack web development in TS/JS.</p>
<p>The thing is, we've been missing the right set of tools to truly go head-to-head with something as feature-rich as Next.js, especially when it comes to stuff like RSC support.</p>
<p>Projects and initiatives like <a target="_blank" href="https://vike.dev/">Vike</a> and <a target="_blank" href="https://vinxi.vercel.app/">Vinxi</a> (both powered by Vite) are making efforts in that sense, even though they're still in the early stages. I specially like Vinxi: it offers full freedom in terms of routing (you can decide how to organize your files and which router library to use) and it recently added support for RSC with its own implementation (very similar to Next.js's). Vike felt more restrictive.</p>
<p>What I don't like from both is their documentation and how complex is to understand what their code is doing. I'd rather have a paper / documentation / example-first approach for projects like thes, rather than code-first.</p>
<p>First define your target architecture, how should it work, document it, then implement it. Iterate.</p>
<p>The idea behind "build your own framework" is to exactly no depend on other frameworks, and to not be forced to the ways and conventions of specific libraries.</p>
<h2 id="heading-pizzajs">PizzaJS 🍕</h2>
<p>So here comes my concept, how my ideal framework should be, my journey to shape and bring to life the "Symfony" counterpart of the JavaScript/TS world.</p>
<p>For some months I've been in a research phase, and I even got a name!</p>
<p>I named it PizzaJS, because everyone loves Pizza. The funny part is that I want Pizza's different pieces to be named after the ingredients of a pizza: Basil, Mozzarella, Pomodoro, like the colors of the italian flag 🇮🇹 as well.</p>
<p>I am taking inspiration from Symfony, Next.js, Vike, Vinxi and also Hono/HonoX (and will probably using parts of them as well).</p>
<h3 id="heading-the-pizza-philosophy">The Pizza Philosophy</h3>
<ol>
<li><p><strong>Documentation-first</strong>: First the concept and theory, then the code. PizzaJS will first have the documented theory of how it should work, backed by coded proofs of concepts.</p>
</li>
<li><p><strong>Universal and Interoperable</strong>: It should be compatible with all major JS runtimes and cloud services: Node, Deno, Bun, Winter, Edge, etc.</p>
</li>
<li><p><strong>Modular, Composable and Pluggable:</strong> Developers should be able to decide to integrate all components or just some of them. They should also be able to replace any component with their own custom implementation.</p>
</li>
<li><p><strong>Unopinionated</strong>: Components shouldn't be tightly coupled to each other (e.g. the server component shouldn't directly depend on the router one). Developers should have the freedom to replace one component with another library / implementation.</p>
</li>
<li><p><strong>Familiar</strong>: It should feel familiar to use the framework or some of its components. Don't reinvent the wheel. Use (and respect) Web standards and community conventions as much as possible. Build on top of Vite as well.</p>
</li>
<li><p><strong>Extensible</strong>: The framework should support extensibility via a Vite-compatible plugin API. It should also be able to pass configuration to Vite. Initially with a React flavor only, but the components should be agnostic enough to bring other frameworks to the pizza party.</p>
</li>
<li><p><strong>No surprises</strong>: I take the principle of least surprise/astonishment very seriously. No surprises, no magic or black boxes. No side-effects or pollution of native APIs (like redefining how <code>fetch</code> works). Again, respect web standards and how they are intended to work.</p>
</li>
<li><p><strong>Declarative</strong>: Explicit and declarative rather than of by convention. Devs should know what their code is doing all the time, and where/how it will be executed.</p>
</li>
<li><p><strong>Multimodal</strong>: SPAs, MPAs, PWAs, SSG, SSR, RSC, HTML Streaming... all should be eventually supported in a declarative way.</p>
</li>
<li><p><strong>Performant and Compact</strong>: I'd rather have a minimal set of dependencies, small bundle size, and well tested code that is able to scale, backed by data and benchmarks.</p>
</li>
</ol>
<p>It is a very ambitious project that I have a lot of uncertainties about, but the journey it's what matters. For sure I will learn a lot about JS framework internals, runtimes, etc., things I wouldn't learn much about if I stayed in my comfort zone as a full stack dev.</p>
<p>I want (or will try) to document my journey about going framework-free in this blog. I will be talking about both JS and CSS frameworks/libs, and probably about new promising HTML technologies as well.</p>
<p>Stay tuned here and on <a target="_blank" href="https://github.com/pizzajsdev">https://github.com/pizzajsdev</a></p>
]]></content:encoded></item><item><title><![CDATA[Mocking the IntersectionObserver in Jest for testing React components]]></title><description><![CDATA[The IntersectionObserver is a powerful API for tracking elements' visibility within the viewport. Many modern web applications use it to implement lazy loading, infinite scrolling, or other interactions that depend on an element's visibility.
When it...]]></description><link>https://blog.itsjavi.com/mocking-the-intersectionobserver-in-jest-for-testing-react-components</link><guid isPermaLink="true">https://blog.itsjavi.com/mocking-the-intersectionobserver-in-jest-for-testing-react-components</guid><category><![CDATA[Jest]]></category><category><![CDATA[Testing]]></category><category><![CDATA[React]]></category><category><![CDATA[jest dom]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Sun, 22 Oct 2023 22:00:00 GMT</pubDate><content:encoded><![CDATA[<p>The IntersectionObserver is a powerful API for tracking elements' visibility within the viewport. Many modern web applications use it to implement lazy loading, infinite scrolling, or other interactions that depend on an element's visibility.</p>
<p>When it comes to testing React components that rely on IntersectionObserver, mocking this API is essential to ensure your tests are reliable and predictable since as of today jest DOM doesn't provide an implementation for it.</p>
<p>In this blog post, you will learn how to mock this API to test React components effectively.</p>
<h2 id="heading-why-mock-intersectionobserver"><strong>Why Mock IntersectionObserver?</strong></h2>
<p>Mocking IntersectionObserver is crucial for several reasons:</p>
<ol>
<li><p><strong>Predictable Testing</strong>: Mocking ensures that your tests aren't dependent on the user's actual scrolling behavior, making them predictable and consistent.</p>
</li>
<li><p><strong>Fast Testing</strong>: Testing real interactions can be slow, especially if you have complex intersection logic. Mocking allows you to run tests quickly without needing to scroll or interact with the page.</p>
</li>
<li><p><strong>Isolation</strong>: By isolating your component from external dependencies, you can focus on testing the component's specific behavior. For unit testing, you just want to test the code that is triggered on intersecting, not the actual browser API.</p>
</li>
</ol>
<h2 id="heading-mocking-intersectionobserver"><strong>Mocking IntersectionObserver</strong></h2>
<p>To mock IntersectionObserver in Jest, we can use a helper function that creates a mock instance of the IntersectionObserver and allows us to control its behavior during testing. Here's an example:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// utils/testing/mockIntersectionObserver.ts</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mockIntersectionObserver</span>(<span class="hljs-params">isIntersectingItems?: <span class="hljs-built_in">Array</span>&lt;<span class="hljs-built_in">boolean</span>&gt;</span>):
[<span class="hljs-title">jest</span>.<span class="hljs-title">MockedObject</span>&lt;<span class="hljs-title">IntersectionObserver</span>&gt;, <span class="hljs-title">jest</span>.<span class="hljs-title">MockedFn</span>&lt;<span class="hljs-title">any</span>&gt;] </span>{
    <span class="hljs-keyword">const</span> intersectionObserverInstanceMock: <span class="hljs-built_in">any</span> = {
        root: <span class="hljs-literal">null</span>,
        rootMargin: <span class="hljs-string">''</span>,
        thresholds: [<span class="hljs-number">0</span>],
        observe: jest.fn(),
        unobserve: jest.fn(),
        disconnect: jest.fn(),
        takeRecords: jest.fn(),
    };

    <span class="hljs-built_in">window</span>.IntersectionObserver = jest.fn()
        .mockImplementation(
            (callback: <span class="hljs-function">(<span class="hljs-params">entries: <span class="hljs-built_in">Array</span>&lt;IntersectionObserverEntry&gt;
            </span>) =&gt;</span> <span class="hljs-built_in">void</span>) =&gt; {
                <span class="hljs-keyword">if</span> (isIntersectingItems === <span class="hljs-literal">undefined</span>) {
                    callback([]);

                    <span class="hljs-keyword">return</span> intersectionObserverInstanceMock;
                }

                <span class="hljs-keyword">const</span> rect = {top: <span class="hljs-number">0</span>, left: <span class="hljs-number">0</span>, bottom: <span class="hljs-number">0</span>, right: <span class="hljs-number">0</span>, x: <span class="hljs-number">0</span>, y: <span class="hljs-number">0</span>, width: <span class="hljs-number">0</span>, height: <span class="hljs-number">0</span>, toJSON: <span class="hljs-function">() =&gt;</span> <span class="hljs-string">''</span>};
                callback(isIntersectingItems.map(<span class="hljs-function">(<span class="hljs-params">isIntersecting</span>) =&gt;</span> ({
                    isIntersecting,
                    intersectionRatio: <span class="hljs-number">0</span>,
                    intersectionRect: rect,
                    rootBounds: rect,
                    boundingClientRect: rect,
                    target: <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'div'</span>),
                    time: <span class="hljs-number">0</span>,
                })));

                <span class="hljs-keyword">return</span> intersectionObserverInstanceMock;
            },
        );

    <span class="hljs-keyword">return</span> [intersectionObserverInstanceMock, <span class="hljs-built_in">window</span>.IntersectionObserver <span class="hljs-keyword">as</span> jest.MockedFn&lt;<span class="hljs-built_in">any</span>&gt;];
}
</code></pre>
<p>This helper accepts a list of booleans (which represents the entries and whether they're intersected or not) and returns an array with 2 elements:</p>
<ul>
<li><p>an IntersectionObserver object mock</p>
</li>
<li><p>a constructor function mock (that you can use to make argument-based assertions).</p>
</li>
</ul>
<p>Here's an example of how to use it in a test:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>;
<span class="hljs-keyword">import</span> MyComponent <span class="hljs-keyword">from</span> <span class="hljs-string">'./MyComponent'</span>; <span class="hljs-comment">// Replace with your component file.</span>
<span class="hljs-keyword">import</span> { mockIntersectionObserver } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/utils/testing/mockIntersectionObserver.ts'</span>

describe(<span class="hljs-string">'MyComponent'</span>, <span class="hljs-function">() =&gt;</span> {
    it(<span class="hljs-string">'should render when intersecting'</span>, <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> onIntersect = jest.fn();
        <span class="hljs-keyword">const</span> [intersectionObserver] = mockIntersectionObserver([<span class="hljs-literal">true</span>]);
        render(&lt;MyComponent onIntersect={onIntersect} /&gt;);
        <span class="hljs-keyword">const</span> element = screen.getByText(<span class="hljs-string">'Visible Content'</span>);

        expect(element).toBeInTheDocument();
        expect(intersectionObserver.observe).toHaveBeenCalledTimes(<span class="hljs-number">1</span>);
        expect(onIntersect).toHaveBeenCalledTimes(<span class="hljs-number">1</span>);
        <span class="hljs-comment">// (other assertions...)</span>
    });

    it(<span class="hljs-string">'should not render when not intersecting'</span>, <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> onIntersect = jest.fn();
        <span class="hljs-keyword">const</span> [intersectionObserver] = mockIntersectionObserver([<span class="hljs-literal">false</span>]);
        render(&lt;MyComponent onIntersect={onIntersect} /&gt;);
        <span class="hljs-keyword">const</span> element = screen.queryByText(<span class="hljs-string">'Hidden Content'</span>);

        expect(element).toBeNull();
        expect(intersectionObserver.observe).toHaveBeenCalledTimes(<span class="hljs-number">1</span>);
        expect(onIntersect).not.toHaveBeenCalled();
        <span class="hljs-comment">// (other assertions...)</span>
    });
});
</code></pre>
<p>This approach allows you to thoroughly test your components' visibility logic without relying on real user interactions.</p>
<p>Happy testing!</p>
]]></content:encoded></item><item><title><![CDATA[StoryLite 0.6.0 released]]></title><description><![CDATA[The addon system has been completely rewritten, so now you can also provide your own or turn off default ones.
The UI also looks much better, especially on mobile. The styles have been reworked so the look and feel are more similar to StoryBook's UI....]]></description><link>https://blog.itsjavi.com/storylite-060-released</link><guid isPermaLink="true">https://blog.itsjavi.com/storylite-060-released</guid><category><![CDATA[Storybook]]></category><category><![CDATA[React]]></category><category><![CDATA[vite]]></category><category><![CDATA[Design Systems]]></category><category><![CDATA[components]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Sat, 26 Aug 2023 05:10:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1693026277269/2c94175f-965d-48b0-8440-ecfbd9c0fe55.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The addon system has been completely rewritten, so now you can also provide your own or turn off default ones.</p>
<p>The UI also looks much better, especially on mobile. The styles have been reworked so the look and feel are more similar to StoryBook's UI.</p>
<p>You can read more and watch a small video clip with the changes here <a target="_blank" href="https://github.com/itsjavi/storylite/releases/tag/v0.6.0">https://github.com/itsjavi/storylite/releases/tag/v0.6.0</a></p>
]]></content:encoded></item><item><title><![CDATA[Introducing StoryLite ⚡️, a lightweight alternative to StoryBook]]></title><description><![CDATA[As developers we understand the importance of efficiently testing and showcasing our components, that's why some months ago I embarked on a journey to create StoryLite, a lightweight (~36KB) and user-friendly alternative to Storybook, with built-in s...]]></description><link>https://blog.itsjavi.com/introducing-storylite-a-lightweight-alternative-to-storybook</link><guid isPermaLink="true">https://blog.itsjavi.com/introducing-storylite-a-lightweight-alternative-to-storybook</guid><category><![CDATA[Storybook]]></category><category><![CDATA[React]]></category><category><![CDATA[vite]]></category><category><![CDATA[Design Systems]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Fri, 11 Aug 2023 15:55:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691768168010/589bfa2c-7588-40b7-95e7-42ad49f8ae92.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As developers we understand the importance of efficiently testing and showcasing our components, that's why some months ago I embarked on a journey to create <strong>StoryLite</strong>, a lightweight (~36KB) and user-friendly alternative to Storybook, with built-in support for <a target="_blank" href="https://storybook.js.org/docs/react/api/csf">Component Story Format</a> v3 (CSF), <a target="_blank" href="https://www.componentdriven.org/">the open standard</a> to write stories.</p>
<p>Written in TypeScript and powered by the blazing-fast Vite, StoryLite offers a streamlined way to preview your components in an isolated environment without the overhead of a full-fledged Storybook setup.</p>
<p>You only need to configure a Vite server with the StoryLite plugin, instantiate the StoryLite React app and voilà!</p>
<p>Thanks to the power of Vite, StoryLite also supports Static-Site generation (SSG) out of the box!</p>
<h3 id="heading-inception-and-motivation"><strong>Inception and Motivation</strong></h3>
<p>The idea for StoryLite sprouted from a simple need: to have a quick and hassle-free way of visually testing my React components during development. While Storybook is an incredible tool, its complexity and setup sometimes felt like overkill for smaller projects or when a rapid iteration cycle was crucial. I wanted a solution that would provide a similar experience but without the configuration overhead. StoryBook has also a lot of package dependencies.</p>
<h3 id="heading-getting-started-with-storylite"><strong>Getting Started with StoryLite</strong></h3>
<p>Getting StoryLite up and running in your React project is a breeze. With a few simple steps, you can start previewing your components in isolation from your full app:</p>
<ol>
<li><p><strong>Installation</strong>: You can install StoryLite with the package manager of your choice, with one of the following commands:</p>
<pre><code class="lang-bash"> <span class="hljs-comment"># npm</span>
 npm i -D @storylite/storylite

 <span class="hljs-comment"># yarn</span>
 yarn add -D @storylite/storylite

 <span class="hljs-comment">#pnpm</span>
 pnpm add -D @storylite/storylite
</code></pre>
</li>
<li><p><strong>Install Vite</strong>: Install Vite and the React plugins (if you don't have these dependencies already in your project).</p>
<pre><code class="lang-bash"> <span class="hljs-comment"># npm</span>
 npm i -D vite @storylite/vite-plugin @vitejs/plugin-react-swc

 <span class="hljs-comment"># yarn</span>
 yarn add -D vite @storylite/vite-plugin @vitejs/plugin-react-swc

 <span class="hljs-comment">#pnpm</span>
 pnpm add -D vite @storylite/vite-plugin @vitejs/plugin-react-swc
</code></pre>
</li>
<li><p><strong>Configure Vite</strong>: Create a <code>vite.config.ts</code> file at the root of your project. This is where you can tell Vite and the StoryLite plugin where to find your stories. Here's a basic example:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">/// &lt;reference types="vite/client" /&gt;</span>

 <span class="hljs-keyword">import</span> storylitePlugin <span class="hljs-keyword">from</span> <span class="hljs-string">'@storylite/vite-plugin'</span>
 <span class="hljs-keyword">import</span> react <span class="hljs-keyword">from</span> <span class="hljs-string">'@vitejs/plugin-react-swc'</span>
 <span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'vite'</span>

 <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
   plugins: [
     storylitePlugin({
       stories: <span class="hljs-string">'stories/**/*.stories.tsx'</span>, <span class="hljs-comment">// relative to process.cwd()</span>
     }),
     react(),
   ],
 })
</code></pre>
</li>
<li><p><strong>Configure typescript</strong>: You need a couple of changes in your <code>tsconfig.json</code> for TypeScript to detect the types correctly, especially the stories collected by the Vite plugin at run-time. Merge the following with your own config:</p>
<pre><code class="lang-json"> {
   <span class="hljs-attr">"include"</span>: [<span class="hljs-string">"src"</span>,  <span class="hljs-string">"stories"</span>, <span class="hljs-string">"storylite.tsx"</span>],
   <span class="hljs-attr">"compilerOptions"</span>: {
     <span class="hljs-attr">"types"</span>: [<span class="hljs-string">"@storylite/vite-plugin/virtual"</span>]
   }
 }
</code></pre>
</li>
<li><p><strong>Add the entry points</strong>: Create <code>index.tsx</code> and <code>index.html</code> in your project (or somewhere else) with the content you can find in this demo (you can customize it to your needs): <a target="_blank" href="https://stackblitz.com/edit/storylite-demo?file=src%2Findex.tsx,index.html">https://stackblitz.com/edit/storylite-demo?file=src%2Findex.tsx,index.html</a></p>
<p> The StoryLiteApp component is a full-screen React Single-Page app (it uses a hash-based router), and it can be mounted anywhere you wish.</p>
<p> If you already have a Vite project or an <code>index.html</code> file in the root of your project, it's recommended that you setup StoryLite in a new package (if you are in a mono-repo) or in another directory.</p>
<blockquote>
<p>Remember that you also need <code>react</code> and <code>react-dom</code> as dependencies.</p>
</blockquote>
</li>
<li><p><strong>Run StoryLite</strong>: Launch the StoryLite development server using Vite's lightning-fast build system. For that, we can add two simple scripts to our <code>package.json</code> :</p>
<pre><code class="lang-json"> {
   <span class="hljs-attr">"scripts"</span>: {
     <span class="hljs-attr">"stories:build"</span>: <span class="hljs-string">"vite build"</span>,
     <span class="hljs-attr">"stories:dev"</span>: <span class="hljs-string">"vite --port=7007 --host=0.0.0.0 --open"</span>
   }
 }
</code></pre>
<p> Then, run <code>npm run stories:dev</code> , <code>yarn run stories:dev</code><br /> or <code>pnpm stories:dev</code></p>
</li>
<li><p><strong>Preview Your Components</strong>: Visit <code>http://localhost:7007</code> in your browser to explore your component stories. You can also use any other port in your script.</p>
</li>
<li><p><strong>Generate a static version</strong>: When you run <code>stories:build</code> , you will be generating a static version (SPA) of your StoryLite instance, with your stories. That's useful if you want to host it somewhere, like in your Github Pages.</p>
</li>
</ol>
<p>All these examples are compatible with StoryLite <code>&gt;=0.9.*</code> at the time of writing this article.</p>
<p>You can check the example code in the repository as well: <a target="_blank" href="https://github.com/itsjavi/storylite/tree/main/packages/examples/react">https://github.com/itsjavi/storylite/tree/main/packages/examples/react</a></p>
<h3 id="heading-the-current-state-version-090"><strong>The Current State: Version 0.9.0</strong></h3>
<p>As of now, StoryLite has reached version 0.9.0. While it may not yet offer the full spectrum of customization options that Storybook boasts, it certainly provides the essentials to get you started on the right foot. With this version, you can effortlessly create and visualize your component stories, making development and debugging a smoother experience.</p>
<p>Porting your stories from StoryBook won't be much of a problem, since StoryLite is almost fully compatible with CSF 3.0.</p>
<p><strong>Current Limitations</strong></p>
<ul>
<li><p>Only compatible with React (for now)</p>
</li>
<li><p>No support for StoryBook features like "auto docs", "code snippets", "knobs", "controls", "actions" or "events"</p>
</li>
<li><p>No support for MD/MDX files (yet)</p>
</li>
<li><p>Styles are not mounted/unmounted per component, they can only be global at the moment (loaded by your entry point).</p>
</li>
</ul>
<p>While it would be nice to support a wide variety of tools, we want to keep things as simple as possible.</p>
<h3 id="heading-whats-next-for-storylite"><strong>What's Next for StoryLite</strong></h3>
<p>The journey of StoryLite has just begun, and there's a lot to look forward to in upcoming releases.</p>
<p><strong>CSF</strong>: My plans include finishing the story definition API to close the final gaps with the StoryBook's CSF 3.0 spec and StoryBook's compatibility, ensuring a seamless migration process for those transitioning.</p>
<p><strong>Props editor</strong>: The Controls panel (where we can adjust the props) is also a must-have and will come in the next versions.</p>
<p><strong>Test runner</strong>: My dream is to bring component testing to the browser, by using Jest and maybe React Testing Library. I would like to facilitate this via the CSF's play() function.</p>
<p>Finally, I would also like to rework the Addons and the Addons API, so you could bring your own and fully customize the toolbars, in a similar approach to StoryBook's.</p>
<h3 id="heading-join-the-storylite-project"><strong>Join the StoryLite project</strong></h3>
<p>StoryLite is a project fuelled by the developer community. Your feedback, suggestions, and contributions are invaluable in shaping the future of this tool.</p>
<p>Whether you have ideas for new features, encounter bugs, or simply want to share your success stories, I encourage you to join the discussion and development process on GitHub: <a target="_blank" href="http://github.com/itsjavi/storylite"><strong>github.com/itsjavi/storylite</strong></a>.</p>
<p>While the scope of this library is to support React components (and probably RSC), you are welcome to contribute to adding support for other frameworks and environments.</p>
<h3 id="heading-final-thoughts"><strong>Final Thoughts</strong></h3>
<p>In conclusion, StoryLite is here to simplify and streamline your component testing workflow. If you're looking for a lightweight, TypeScript-powered alternative to Storybook, give StoryLite a try.</p>
<p>Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[How to test the Error cause with Jest and TypeScript]]></title><description><![CDATA[When developing applications, it's essential to handle errors effectively, and throwing errors is a common way to signal that something has gone wrong. However, defining multiple error classes for each error scenario can quickly become overwhelming a...]]></description><link>https://blog.itsjavi.com/how-to-test-the-error-cause-with-jest-and-typescript</link><guid isPermaLink="true">https://blog.itsjavi.com/how-to-test-the-error-cause-with-jest-and-typescript</guid><category><![CDATA[Jest]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Testing]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Thu, 09 Feb 2023 22:37:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1675982182190/3a15833e-7ff9-40e2-a3be-50edcc6e6760.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When developing applications, it's essential to handle errors effectively, and throwing errors is a common way to signal that something has gone wrong. However, defining multiple error classes for each error scenario can quickly become overwhelming and make our codebase cluttered.</p>
<p>To avoid this, many developers opt for using error codes instead of error classes. These error codes are simply strings or numbers that represent the type of error that has occurred.</p>
<p>When using error codes, it's common to pass additional information about the error in the error message. But testing the error message makes tests a little ugly and has some drawbacks:</p>
<ul>
<li><p>You have to use RegExp to test the error message</p>
</li>
<li><p>Many errors may have similar error messages, leading to misleading tests with false positives/negatives</p>
</li>
<li><p>When error message changes, you have to change your tests</p>
</li>
</ul>
<p>This is where the <code>options</code> parameter of the JS <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Error"><code>Error</code></a> class comes in. It allows us to pass additional information about the error that can be useful in understanding why the error was thrown.</p>
<p>You can pass an <code>options</code> object as a second argument of the <code>Error</code> constructor. It can have a <code>cause</code> property that can be of any type or another <code>Error</code>.</p>
<p>This pattern of throwing errors with a <code>cause</code> is widely used in JavaScript, and testing the value of the <code>cause</code> can make your tests more robust.</p>
<p>Unfortunately, Jest's built-in matchers do not provide a way to test extra properties of an Error, and that's where extending the Jest matchers in TypeScript comes in handy.</p>
<p>All you have to do is to define your custom matchers in your <code>setupTests.js</code> file, by calling <code>expect.extend()</code></p>
<pre><code class="lang-js"><span class="hljs-comment">// setupTests.js</span>
<span class="hljs-keyword">const</span> catchError = <span class="hljs-function">(<span class="hljs-params">callback</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    callback()
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">return</span> error
  }
}

<span class="hljs-comment">/**
 * <span class="hljs-doctag">@type <span class="hljs-type">{ExpectExtendMap &amp; MatchersExtend&lt;any&gt;}</span></span>
 */</span>
<span class="hljs-keyword">const</span> customMatchers = {
  toThrowWithCause(received, cause) {
    <span class="hljs-keyword">const</span> err = catchError(received)
    <span class="hljs-keyword">const</span> passes = (err <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Error</span>) &amp;&amp; (err.cause === cause)
    <span class="hljs-keyword">const</span> actualCause = <span class="hljs-built_in">String</span>(err ? <span class="hljs-string">`got: <span class="hljs-subst">${err.cause}</span>`</span> : <span class="hljs-string">'no error was thrown'</span>)
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error Cause'</span>, actualCause)

    <span class="hljs-keyword">if</span> (err &amp;&amp; err.cause === <span class="hljs-literal">undefined</span>) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error was thrown, but cause was undefined. Error:'</span>, err)
    }

    <span class="hljs-keyword">return</span> passes ? ({
      <span class="hljs-attr">pass</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// not.toThrowWithCause</span>
      <span class="hljs-attr">message</span>: <span class="hljs-function">() =&gt;</span> <span class="hljs-string">`Expected callback not to throw an Error with cause '<span class="hljs-subst">${cause}</span>'`</span>,
    }) : ({
      <span class="hljs-attr">pass</span>: <span class="hljs-literal">false</span>, <span class="hljs-comment">// .toThrowWithCause</span>
      <span class="hljs-attr">message</span>: <span class="hljs-function">() =&gt;</span> <span class="hljs-string">`Expected callback to throw an Error with cause '<span class="hljs-subst">${cause}</span>', but <span class="hljs-subst">${actualCause}</span>`</span>,
    })
  },
}

expect.extend(customMatchers)
</code></pre>
<p>You also need to extend the Jest types:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// setupTests.d.ts</span>

<span class="hljs-keyword">export</span> {}
<span class="hljs-keyword">declare</span> <span class="hljs-built_in">global</span> {
  <span class="hljs-keyword">namespace</span> jest {
    <span class="hljs-keyword">interface</span> AsymmetricMatchers {
      toThrowWithCause(cause: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">Error</span>): <span class="hljs-built_in">void</span>
    }

    <span class="hljs-keyword">interface</span> Matchers&lt;R&gt; {
      toThrowWithCause(cause: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">Error</span>): R
    }

    <span class="hljs-keyword">type</span> MatcherNames = keyof Matchers&lt;<span class="hljs-built_in">any</span>&gt;

    <span class="hljs-keyword">type</span> MatchersExtend&lt;R&gt; = {
      [Key <span class="hljs-keyword">in</span> MatcherNames]: <span class="hljs-function">(<span class="hljs-params">
        received: <span class="hljs-built_in">any</span>,
        ...params: Parameters&lt;Matchers&lt;R | <span class="hljs-built_in">void</span>&gt;[Key]&gt;
      </span>) =&gt;</span> R | <span class="hljs-built_in">void</span>
    }
  }
}
</code></pre>
<p>And then you can use it in your tests like this:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> myParser = <span class="hljs-function">(<span class="hljs-params">version: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
  <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Invalid version <span class="hljs-subst">${version}</span>`</span>, { cause: <span class="hljs-string">'INVALID_VERSION'</span> })
}

it(<span class="hljs-string">'throws an error if the version is wrong'</span>, <span class="hljs-function">() =&gt;</span> {
  expect(<span class="hljs-function">() =&gt;</span> myParser(<span class="hljs-string">'0.,4'</span>)).toThrowWithCause(<span class="hljs-string">'INVALID_VERSION'</span>)
})
</code></pre>
<p>By using custom matchers to catch the error, we will not only make it more reusable, but we will also make our linters happy since it's considered a bad practice to catch errors manually inside tests.</p>
]]></content:encoded></item><item><title><![CDATA[Speed-Up your Docker containers on macOS by enabling the new Virtualization Framework and VirtioFS]]></title><description><![CDATA[If you are a software engineer that uses Docker containers on your macOS for development, you might have experienced how slow can they get sometimes, especially when they start up or with I/O intensive operations like installing dependencies.
Since m...]]></description><link>https://blog.itsjavi.com/speed-up-your-docker-containers-on-macos-by-enabling-the-new-virtualization-framework-and-virtiofs</link><guid isPermaLink="true">https://blog.itsjavi.com/speed-up-your-docker-containers-on-macos-by-enabling-the-new-virtualization-framework-and-virtiofs</guid><category><![CDATA[Docker]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[macOS]]></category><category><![CDATA[Developer Tools]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Sat, 11 Jun 2022 23:53:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1654990717318/9ECTgLf8D.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you are a software engineer that uses Docker containers on your macOS for development, you might have experienced how slow can they get sometimes, especially when they start up or with I/O intensive operations like installing dependencies.</p>
<p>Since macOS Big Sur, there is a new Virtualization Framework that software like Docker can use to access the computer resources more effectively. This, when combined with the new VirtioFS introduced in macOS Monterey 12.2 will make your containers fly like never before.</p>
<p>I especially notice the difference when starting my NextJS apps (it went from ~20 secs to ~3) or when installing dependencies (time is drastically better here).</p>
<p>With 3 NextJS apps running, I can see how much better my resources are used:</p>
<p>CPU (Idle containers: 3 - 5 %)
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654990595909/uM_2Lw55F.png" alt="image.png" /></p>
<p>Allocated Memory (8.02 GB of the maximum configured for Docker,  8.00 GB)
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654990623923/3lEtzRJhU.png" alt="image.png" /></p>
<p>Before this, Docker was using <code>qemu</code> and it was eating a lot of memory (more than the limit I configured).</p>
<p>All you need to do, if you have macOS 12.2 or greater, is to enable these experimental features in your Docker for Mac settings, and restart it:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654991431541/TODLCQZii.png" alt="image.png" /></p>
]]></content:encoded></item><item><title><![CDATA[How to successfully set up a NextJS monorepo and deploy it on Vercel]]></title><description><![CDATA[For people that are new to monorepos like me, there are a lot of struggles that you will face and no one talks about them in the articles you can find out there, especially when it comes to monorepos with NextJS apps.
Setup a monorepo with NPM or Yar...]]></description><link>https://blog.itsjavi.com/how-to-successfully-set-up-a-nextjs-monorepo-and-deploy-it-on-vercel</link><guid isPermaLink="true">https://blog.itsjavi.com/how-to-successfully-set-up-a-nextjs-monorepo-and-deploy-it-on-vercel</guid><category><![CDATA[Vercel]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[monorepos]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Sat, 11 Jun 2022 23:21:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1654989610678/rtGDgK1XS.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For people that are new to monorepos like me, there are a lot of struggles that you will face and no one talks about them in the articles you can find out there, especially when it comes to monorepos with NextJS apps.</p>
<h2 id="heading-setup-a-monorepo-with-npm-or-yarn">Setup a monorepo with NPM or Yarn</h2>
<p>You can setup monorepos in various ways: with <code>npm</code>, <code>yarn</code>, <code>pnpm</code>,  <code>nx</code>, <code>lerna</code>, <code>bit.dev</code>, etc. but since my project doesn't need to maintain/publish packages to the npm repository, I chose to go simple and try with npm and yarn.</p>
<p>To add monorepo support in npm or yarn, you simply have to add a <code>workspaces</code> entry to your <code>package.json</code> file in the root directory of your monorepo project, like this: </p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"private"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">"workspaces"</span>: [
    <span class="hljs-string">"packages/*"</span>
  ]
}
</code></pre>
<p>Initially, I wanted to have <code>apps/*</code> and <code>packages/*</code> separately, but that was just making my tooling &amp; scripts more complicated, unnecessarily. So I decided to put everything (NextJS apps and shared packages) under <code>packages/*</code>, for simplicity.</p>
<p>Now here comes the tricky part, because I had a very hard time understanding how could I reuse my packages (written in TypeScript and CSS modules) in my NextJS apps.</p>
<p>The <code>npm</code> workspaces documentation is very deficient and doesn't tell anything about how to import your packages. So I thought I could just include them as a dependency, using local package resolution:</p>
<pre><code>{
   <span class="hljs-attr">"dependencies"</span>: {
      <span class="hljs-attr">"@myorg/designsystem"</span>: <span class="hljs-string">"file:../designsystem"</span>
   }
}
</code></pre><p>Then you run <code>npm install</code> and your local package is hard-linked in the <code>node_modules</code> folder of the package that requires it. </p>
<p>With <code>yarn</code>, instead of the file resolution, you would use <code>workspace:*</code>.</p>
<p>The difference between yarn and npm when it comes to workspaces is that yarn is more efficient: it keeps a single <code>node_modules</code> folder in the root, instead of one per package (like npm does). Yarns also prune the dependencies automatically.</p>
<p>The only problem with having a single node_modules is when you or some of your dependencies require a different version of React. When some of your packages need a different version of a dependency that is shared with other of your packages, you end up with the same package in the root node_modules and in your package's node_modules folder that needs a particular version.</p>
<p>This can cause problems, especially in NextJS apps, which don't like to have another version of React in the parent <code>node_modules</code>, so you need to take special care of that.</p>
<p>So, after understanding how dependencies were working for each package manager, then the problem came when I tried to import the source files (in TS) of my packages. The compiler will complain that there is no loader configured for that (sorry, what??).</p>
<p>Yes, I had to compile my packages to JS before they could be used by the others. Somehow I felt this wasn't the right approach and that it wasn't going to work for me, as it was making my developer experience very bad and frustrating.</p>
<p>If you try to import TypeScript files directly, that won't work, unless you enable NextJS experimental features to include external files and configure your <code>tsconfig.json</code> files to include all packages TS/TSX.
I tried that and it felt ugly and hacky. CSS Modules don't work with this approach.</p>
<h2 id="heading-the-official-vercel-approach-for-monorepos">The official Vercel approach for monorepos</h2>
<p>I was about to surrender and abandon the idea of having a monorepo with my related NextJS apps,
and then <a target="_blank" href="https://github.com/vercel/next.js/blob/189fc985a709bf67986ef58502c0c599abdb2ff2/examples/with-yarn-workspaces">I found this official Vercel example</a> of how to configure workspaces with <code>yarn</code>.</p>
<p>It saved my life. You only need to configure your workspaces with yarn, and use the <a target="_blank" href="https://github.com/vercel/next.js/blob/189fc985a709bf67986ef58502c0c599abdb2ff2/examples/with-yarn-workspaces/packages/web-app/next.config.js"><code>next-transpile-modules</code> NextJS plugin</a> to start being able to import your packages directly.</p>
<p>No manual compilation steps, no need to add it as a dependency, and no need for tsconfig.json changes! All works out of the box: JS, JSX, TS, TSX, including JSON and CSS Modules.</p>
<p>This is the configuration I used for my NextJS apps:</p>
<pre><code class="lang-js"><span class="hljs-comment">// next.config.js</span>
<span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('next').NextConfig}</span> </span>*/</span>
<span class="hljs-keyword">const</span> nextConfig = {
  <span class="hljs-attr">reactStrictMode</span>: <span class="hljs-literal">true</span>
}

<span class="hljs-keyword">const</span> sharedPackages = [<span class="hljs-string">"../designsystem"</span>, <span class="hljs-string">"../core"</span>]

<span class="hljs-keyword">const</span> withTM = <span class="hljs-built_in">require</span>(<span class="hljs-string">"next-transpile-modules"</span>)(sharedPackages) <span class="hljs-comment">// monorepo support</span>

<span class="hljs-comment">// withTM needs to be the further-most plugin you wrap your config with.</span>
<span class="hljs-built_in">module</span>.exports = withTM(nextConfig)
</code></pre>
<p>After this, you can import your packages using their package name:</p>
<pre><code class="lang-tsx">import { Button } from "@myorg/designsystem/forms"
</code></pre>
<p>You only need to have a <code>index.ts</code> or <code>index.js</code> file in the root of every package (even if they just have an empty export), in order for the <code>next-transpile-modules</code> to work, but you can organize your code in folders, you don't need to export everything in the main index file.</p>
<p>I still need to figure out whether this will also work inside NextJS server-side scripts (e.g. importing node js/ts files of my packages in <code>pages/api/*</code> files), but for now this solution covers all the needs I had of reusing my components in different NextJS apps.</p>
<p>It works so seamlessly that every time you change your packages, NextJS will detect that and make a hot reload while you are developing, which makes the developer experience really great.</p>
<h2 id="heading-deploying-the-apps-of-your-monorepo-on-vercel">Deploying the apps of your monorepo on Vercel</h2>
<p>Once you are done, to deploy every NextJS separately in Vercel, you only need to configure the root directory in your Vercel app's settings. For example, if your app is under <code>packages/myapp</code>, this should be the value in the Vercel settings.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654989436681/WNn9r9boD.png" alt="image.png" /></p>
<p>You also should set up the Git Ignore Build Step section, to ignore the build if the files of your app directory didn't change, by adding <code>git diff HEAD^ HEAD --quiet .</code>. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654989465482/wqSjaXhRd.png" alt="image.png" /></p>
<p>Otherwise, new deployments will be triggered even if you changed files of other apps.
If you changed a component dependency that is under another package folder, then you will need to trigger the build manually or write a more advanced git check.</p>
<p>To know more, check this <a target="_blank" href="https://vercel.com/guides/deploying-yarn-monorepos-to-vercel">guide on Vercel's website</a> and <a target="_blank" href="https://vercel.com/blog/monorepos">this other article from them</a>.</p>
]]></content:encoded></item><item><title><![CDATA[How to mock TypeScript interfaces with Jest]]></title><description><![CDATA[Last week I was creating a NodeJS + ExpressJS app in TypeScript and I was wondering how to apply the  Onion Architecture successfully. In practice that was not a problem (I will write an article about it soon) until the moment of testing.
There is li...]]></description><link>https://blog.itsjavi.com/how-to-mock-typescript-interfaces-with-jest</link><guid isPermaLink="true">https://blog.itsjavi.com/how-to-mock-typescript-interfaces-with-jest</guid><category><![CDATA[Jest]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Testing]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Sat, 17 Apr 2021 18:59:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1618685916871/wWRGLWUV_.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last week I was creating a NodeJS + ExpressJS app in TypeScript and I was wondering how to apply the  <a target="_blank" href="https://blog.itsjavi.com/target-software-architectures-the-onion-architecture">Onion Architecture</a> successfully. In practice that was not a problem (I will write an article about it soon) until the moment of testing.</p>
<p>There is little to no documentation about how to mock TypeScript interfaces in Jest and what I found was most of the time misleading or not what I was looking for. </p>
<p>First I used  <a target="_blank" href="https://github.com/marchaos/jest-mock-extended">jest-mock-extended</a>  but I was not very convinced and I ended up playing around with jest until I came up with a working solution.</p>
<p>I think that this could be applied to both NodeJS and browser JS apps. First, you obviously need <code>jest</code> and <code>ts-jest</code> as <code>devDependencies</code>.</p>
<p>Now let's say I have this code under <code>src/DomainModel/Reply</code> and I want to test a class called <code>ReplyService</code>, mocking its dependencies.</p>
<p><code>src/DomainModel/Reply/ReplyInterface.js</code></p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> ReplyInterface {
    text: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p><code>src/DomainModel/Reply/ReplyRepositoryInterface.js</code></p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> {ReplyInterface} <span class="hljs-keyword">from</span> <span class="hljs-string">"./ReplyInterface"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> ReplyRepositoryInterface {
    findOneByIntent: <span class="hljs-function">(<span class="hljs-params">intentName: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-built_in">Promise</span>&lt;ReplyInterface&gt;
}
</code></pre>
<p><code>src/DomainModel/Reply/ReplyService.js</code></p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> {ReplyRepositoryInterface} <span class="hljs-keyword">from</span> <span class="hljs-string">"./ReplyRepositoryInterface"</span>;
<span class="hljs-keyword">import</span> {ReplyInterface} <span class="hljs-keyword">from</span> <span class="hljs-string">"./ReplyInterface"</span>;
<span class="hljs-keyword">import</span> {ReplyNotFoundError} <span class="hljs-keyword">from</span> <span class="hljs-string">"./ReplyNotFoundError"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ReplyService {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">private</span> replyRepository: ReplyRepositoryInterface
    </span>) {
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> getReply(intent: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">string</span>&gt; {
        <span class="hljs-keyword">let</span> reply: ReplyInterface

        <span class="hljs-keyword">try</span> {
            reply = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.replyRepository.findOneByIntent(intent);
        } <span class="hljs-keyword">catch</span> (e) {
            <span class="hljs-keyword">if</span> (!(e <span class="hljs-keyword">instanceof</span> ReplyNotFoundError)) {
                <span class="hljs-keyword">throw</span> e
            }
            reply = {text: <span class="hljs-string">`Sorry, I cannot help you with '<span class="hljs-subst">${intent}</span>' in this moment...`</span>};
        }

        <span class="hljs-keyword">return</span> reply.text;
    }
}
</code></pre>
<p>Here you can see that <code>ReplyService</code> has a dependency on <code>ReplyRepositoryInterface</code> but, how can we mock this interface to test our service in isolation as a real unit test?</p>
<p>To mock a TypeScript interface in jest, you only need an object that has the same functions as the interface. In our case, we need to mock a function that returns a promise. We can do that with <code>jest.fn()</code>:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> replyRepositoryMock = {
  findOneByIntent: jest.fn().mockReturnValue(<span class="hljs-built_in">Promise</span>.resolve({text: replyText}))
};
</code></pre>
<p>And this is how one of the tests would look like:</p>
<p><code>src/DomainModel/Reply/ReplyService.test.js</code></p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> {ReplyService} <span class="hljs-keyword">from</span> <span class="hljs-string">"./ReplyService"</span>;

test(<span class="hljs-string">'getReply returns the expected reply text'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> intent = <span class="hljs-string">'baz'</span>
    <span class="hljs-keyword">const</span> replyText = <span class="hljs-string">'ok'</span>

    <span class="hljs-keyword">const</span> replyRepositoryMock = {
        findOneByIntent: jest.fn().mockReturnValue(<span class="hljs-built_in">Promise</span>.resolve({text: replyText}))
    };
    <span class="hljs-keyword">const</span> replyService = <span class="hljs-keyword">new</span> ReplyService(replyRepositoryMock);

    <span class="hljs-keyword">return</span> replyService
        .getReply(intent)
        .then(<span class="hljs-function"><span class="hljs-params">reply</span> =&gt;</span> {
            expect(replyRepositoryMock.findOneByIntent).toBeCalledWith(intent);
            expect(reply).toBe(replyText)
        })
});
</code></pre>
<p>Jest is very flexible and it also allows you to mock entire packages, like <code>axios</code>:</p>
<p><code>src/Infrastructure/UltimateAi/IntentSearchService.test.js</code></p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> {IntentSearchService} <span class="hljs-keyword">from</span> <span class="hljs-string">"./IntentSearchService"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
jest.mock(<span class="hljs-string">'axios'</span>);

test(<span class="hljs-string">'example axios mock'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> resp = {
        data: {
            intents: [
                {name: <span class="hljs-string">"Foo"</span>, ratio: <span class="hljs-number">0.7</span>},
                {name: <span class="hljs-string">"Bar"</span>, ratio: <span class="hljs-number">0.2</span>},
                {name: <span class="hljs-string">"Baz"</span>, ratio: <span class="hljs-number">0.5</span>},
                {name: <span class="hljs-string">"Foo2"</span>, ratio: <span class="hljs-number">0.71</span>},
                {name: <span class="hljs-string">"Bar2"</span>, ratio: <span class="hljs-number">0.2</span>},
            ]
        }
    };

    <span class="hljs-keyword">const</span> axiosMock = axios <span class="hljs-keyword">as</span> jest.Mocked&lt;<span class="hljs-keyword">typeof</span> axios&gt;
    axiosMock.create.mockReturnValue(axiosMock)
    axiosMock.post.mockResolvedValue(resp)

    <span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> IntentSearchService(axiosMock)
});
</code></pre>
<p>As you can see you can mock pretty much anything with Jest, it's pretty simple and you don't need any other libraries to accomplish the same.</p>
<div class="hn-embed-widget" id="coffee"></div>]]></content:encoded></item><item><title><![CDATA[Getting quickly started with React Router and vanilla React JS in 2021]]></title><description><![CDATA[Last month I've been migrating my living Pokédex project, LivingDex , from Gatsby to a pure React JS application and I had to learn lots of things as I was rewriting the project, one of them is how React Router works.
First of all I have to say I am ...]]></description><link>https://blog.itsjavi.com/getting-quickly-started-with-react-router-and-vanilla-react-js-in-2021</link><guid isPermaLink="true">https://blog.itsjavi.com/getting-quickly-started-with-react-router-and-vanilla-react-js-in-2021</guid><category><![CDATA[React]]></category><category><![CDATA[react router]]></category><category><![CDATA[ReactHooks]]></category><category><![CDATA[frontend]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Sat, 10 Apr 2021 01:11:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1617210578776/4O72pkyQc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last month I've been migrating my living Pokédex project, <a target="_blank" href="https://itsjavi.com/livingdex">LivingDex</a> , from Gatsby to a pure React JS application and I had to learn lots of things as I was rewriting the project, one of them is how React Router works.</p>
<p>First of all I have to say I am not a React JS expert and this article may contain mistakes or things that can be improved, but it is what worked for me so far.</p>
<p>Before jumping directly into learning how to manage location data with a global state like with e.g. Redux, I wanted to see how can I do it with only what React + React Router offer out of the box.</p>
<h2 id="setup">Setup</h2>
<p>You can bootstrap a new app using <a target="_blank" href="https://github.com/facebook/create-react-app">Create React App</a> or you can use an existing one. Either way, you'll have to install React Router:</p>
<pre><code class="lang-bash">
npm install react-router-dom
</code></pre>
<blockquote>
<p>At the moment of writing this article, I am using <code>react-router-dom@^5.2.0</code>.</p>
</blockquote>
<h2 id="wrapping-your-application">Wrapping your application</h2>
<p>Next thing to do would be to <strong>wrap a component with a Router component</strong>. In my case I wanted to wrap my whole app with a <code>HashRouter</code> component (there are <a target="_blank" href="https://reactrouter.com/web/guides/primary-components/routers">many types of routers</a>), which changes the location hash.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/App/App"</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> serviceWorker <span class="hljs-keyword">from</span> <span class="hljs-string">"./app/serviceWorker"</span>
<span class="hljs-keyword">import</span> { HashRouter <span class="hljs-keyword">as</span> Router } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>

ReactDOM.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Router</span> <span class="hljs-attr">basename</span>=<span class="hljs-string">"/"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Router</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>,
  <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>),
)

<span class="hljs-comment">// ...</span>
</code></pre>
<p>This will enable us to use React Router specific hooks such as <code>useLocation</code>, <code>useHistory</code>, etc. in our App component, since we can only use them in the children of Router components, not outside.</p>
<p>Make sure you set up the <code>basename</code> attribute correctly, depending on the router type you chose.</p>
<p>Be aware that if you are using <em>BrowserRouter</em>, which changes the URL with the HTML5 History API, you may not be able to share permalinks since it may need server-side changes. </p>
<p>I had that problem when hosting my app in Github Pages: if you refresh a page containing a route, it will show a Github 404 error page. My solution was to use a <em>HashRouter</em> instead.</p>
<h2 id="render-a-component-based-on-a-route">Render a component based on a route</h2>
<p>In order to match a route and render a specific part of your application, you need to have a <code>Switch</code> component. In my case, I added it as part of my <code>App</code> component, because I only need one switch.</p>
<p>Whenever you define a Switch, you are telling the Router what to render in each path, whenever your location changes:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Route, Switch } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>
<span class="hljs-keyword">import</span> PokedexPage <span class="hljs-keyword">from</span> <span class="hljs-string">"../pages/PokedexPage/PokedexPage"</span>
<span class="hljs-keyword">import</span> PokeDetailsPage <span class="hljs-keyword">from</span> <span class="hljs-string">"../pages/PokeDetailsPage/PokeDetailsPage"</span>
<span class="hljs-keyword">import</span> BoxesPage <span class="hljs-keyword">from</span> <span class="hljs-string">"../pages/BoxesPage/BoxesPage"</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Switch</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/pokedex"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">PokedexPage</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Route</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">{</span>`/<span class="hljs-attr">pokemon</span>/<span class="hljs-attr">:slug</span>`}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">PokeDetailsPage</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Route</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">BoxesPage</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Route</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Switch</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>As you can see, I defined many routes as <code>/pokedex</code>, another one with a parameter named <code>/pokemon/:slug</code> and at the end the home page as <code>/</code>.</p>
<p>Inside a route component, you define what will be rendered in each route.</p>
<p>Let's take a look at the <code>PokeDetailsPage</code> component:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { Link, useParams } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PokeDetailsPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> { slug } = useParams()

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Pokemon: {{ slug }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"/<span class="hljs-attr">pokedex</span>"}&gt;</span>Go back<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> PokeDetailsPage
</code></pre>
<p>In this page we retrieve the path parameter <code>:slug</code>, we render it and we display a link to the Pokedex page.</p>
<p>But wait, why nothing happens when we click the <code>Go back</code> link?
The answer is that we didn't make our components dependent on the location state.</p>
<h2 id="location-aware-components">Location-aware components</h2>
<p>One simple way to make our app to be re-rendered on location changes is to add a <code>key</code> attribute to the top most element that will need re-rendering. The <code>key</code> should represent the state of the location.</p>
<p>For example:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// ...</span>
<span class="hljs-keyword">import</span> { Route, Switch, useLocation } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> loc = useLocation()
  <span class="hljs-keyword">const</span> locationState = loc.pathname + <span class="hljs-string">"@"</span> + loc.hash + <span class="hljs-string">"@"</span> + loc.search.toString()

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Switch</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{locationState}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/pokedex"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">PokedexPage</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Route</span>&gt;</span>
      {/*...*/}
    <span class="hljs-tag">&lt;/<span class="hljs-name">Switch</span>&gt;</span></span>
  )
}
<span class="hljs-comment">// ...</span>
</code></pre>
<p>In this case, every time the location hash or query string changes, a page component of the Switch will be re-rendered.</p>
<p>This is of course not optimal because it basically renders the whole page again, but it is a quick way to make your application aware of the location changes.</p>
<p>I am sure there are more efficient ways to accomplish the same. What do you think?</p>
<p>I hope that at least this article was useful for you to get things done and working, which was my intention.</p>
<div class="hn-embed-widget" id="coffee"></div>]]></content:encoded></item><item><title><![CDATA[Domain Driven Design and The Onion Architecture]]></title><description><![CDATA[Domain-Driven Design or DDD is an approach to software development that centers the development on programming a domain model that has a rich understanding of the processes and rules of a domain.
In Domain Driven Design, the Domain Model represents t...]]></description><link>https://blog.itsjavi.com/target-software-architectures-the-onion-architecture</link><guid isPermaLink="true">https://blog.itsjavi.com/target-software-architectures-the-onion-architecture</guid><category><![CDATA[Symfony]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[PHP]]></category><category><![CDATA[best practices]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Sun, 21 Mar 2021 04:49:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1627029994048/aSktSy5AT.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://martinfowler.com/bliki/DomainDrivenDesign.html">Domain-Driven Design</a> or DDD is an approach to software development that centers the development on programming a domain model that has a rich understanding of the processes and rules of a domain.</p>
<p>In Domain Driven Design, the Domain Model represents the processes and rules of your application and its main business, is the central and most important part of your application. </p>
<p>There are many ways to implement this concept, some of them being the Hexagonal Architecture or the Onion Architecture.</p>
<p>In this article I will talk a special variant of the <a target="_blank" href="https://en.wikipedia.org/wiki/Hexagonal_architecture_%28software%29">Hexagonal Architecture</a>, which I personally find more convenient, because it feels more natural when developing and is easier to understand: the <a target="_blank" href="https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/">Onion Architecture</a>, proposed by Jeffrey Palermo in 2008.</p>
<h2 id="hexagonal-vs-onion-architecture">Hexagonal vs Onion Architecture</h2>
<p>Whilst the Hexagonal Architecture has really no layers necessarily and talks about ports and adapters (which in my opinion they are kind of an inflexible concept), the Onion Architecture encourages you to do a better separation of concerns and good use of the <a target="_blank" href="https://en.wikipedia.org/wiki/Dependency_injection">Dependency Injection</a> (DI) and  <a target="_blank" href="https://en.wikipedia.org/wiki/Dependency_inversion_principle">Inversion of Control</a> (IoC) patterns from the start.</p>
<p>In the Onion Architecture, the dependencies are always pointing inwards. The inner layer is the <strong>Domain Model</strong> and the outer one is the <strong>Infrastructure</strong> layer, which takes care of communicating with the external world.</p>
<p>Between the Domain Model and Infrastructure layers, you can have as many layers as your application or team needs, but in this article, I will only cover the <strong>Application</strong> and <strong>Presentation</strong> layers additionally.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616302698196/n_JobCmWO.png" alt="onion architecture" /></p>
<p>As you can see in my proposal, the Presentation layer shares the same "level" as the Infrastructure one. Why is that? Because of the golden rule.</p>
<h2 id="the-main-rule">The main rule</h2>
<p>The main rule of the Onion Architecture is pretty simple: <strong>the outer layers can use elements from the same layer or inner layers, but not the other way around</strong>.</p>
<blockquote>
<p>On the diagram, Presentation cannot be at a lower level than Infrastructure or vice-versa because they cannot use each other.</p>
</blockquote>
<p>Code is always coupled towards the center which is the Domain Model and,
since the Domain Model is the center, it can be only coupled to itself.</p>
<p>The parts of the software that are more subtle to change are or that we have less control about are in the most outer layers, while in the inner layers we have the most meaningful parts of our application.</p>
<p>The Onion Architecture relies heavily on the 
<a target="_blank" href="http://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency Inversion principle</a>: 
the Domain Model (the core) needs implementation for its interfaces, 
and if those implementing classes reside at the edges of the application, 
we need some mechanism for injecting that code at runtime. </p>
<p>If you are a PHP developer like me, you'll know that Symfony is the most indicated framework to accomplish that.</p>
<p>In the JavaScript world it's not so easy unless you use TypeScript and interfaces and do the dependency injections manually or with a library.</p>
<h2 id="the-domain-model-layer">The Domain Model Layer</h2>
<p>The first and most important layer is the Domain layer, the inner most one. This is the life of your application. It represents your app's domain, the business logic and its functional implementation, everything it can do.</p>
<p>Classes (that we will call services from now on) created in this layer are business-logic related: e.g. a service that defines all operations we can do on an entity.</p>
<p>It consists of the following types of objects:</p>
<ul>
<li>Domain Services: Each component of the domain represents a private service that matters only within the domain, e.g. a state machine manager.<ul>
<li>Interfaces that represent the outside world</li>
<li>Factories</li>
<li>Value Objects (a.ka. DTOs or classes with no business logic, only properties)</li>
</ul>
</li>
<li>Repository Interfaces</li>
<li>Entities / Domain Objects (similar to Value Objects)</li>
<li>Collections</li>
<li>Object Factories</li>
<li>Domain Events, e.g.: an order got paid.</li>
<li>Domain-level Exceptions</li>
</ul>
<p>All these types of objects together represent the business logic of the project.</p>
<h3 id="domain-model-layer-rules">Domain Model Layer Rules</h3>
<ol>
<li><p>This layer MUST NOT have interaction with the outside world or any other layer.
That means that code from the other layers MUST NOT be used here.</p>
</li>
<li><p>The only responsibility of the domain layer is to define how your business work, not how data is queried or persisted, that's why we SHOULD NOT use repositories directly here but define and use their interfaces instead.</p>
</li>
<li><p>Database layer abstractions occur in the Infrastructure layer, the Domain Model only defines its interfaces, which is the one the business code should always refer to when writing strict type-hinting.</p>
</li>
</ol>
<h2 id="the-application-layer">The Application Layer</h2>
<p>The application layer is where all our application features or "use cases" live.</p>
<p>It basically wraps around the domain layer, adding specific business rules on top (e.g. how much fees should the app charge to a customer, etc). </p>
<p>These are features and rules that are not necessarily part of the Domain Model, but that define the app's business. This layer is also called "Domain Rules" or "Domain Services".</p>
<p>May consist of the following types of objects:</p>
<ul>
<li>Use Cases or Application Services: wrap around the domain layer, adding extra logic or conditions specific to the use case.</li>
<li>Application Events, something that happen internally in the application itself,
  e.g.: a specific method was called, the app has started/finished doing something, etc.</li>
<li>Application Event Subscribers</li>
<li>Application-level Exceptions</li>
</ul>
<p><strong>Use Cases</strong> are Application Services that wrap around the domain layer with. They are typically used via Use Case Request and Response value objects.</p>
<p>Product features like "confirm a payment", "create an order", etc. should be defined here.</p>
<p>Use Cases can also be seen as all the possible actions that an actor can perform in your service.</p>
<h3 id="application-layer-rules">Application Layer Rules</h3>
<ol>
<li><p>The application layer SHOULD only know about the Domain Model layer and nothing about the Presentation or Infrastructure ones.</p>
</li>
<li><p>Use Case(s) SHOULD have a single purpose, therefore they MAY have just one method, e.g <code>execute</code>.</p>
</li>
<li><p>Use Cases SHOULD always use value objects as method arguments and as return values. </p>
</li>
<li><p>If there is no returned value, it SHOULD be declared explicitly, e.g. as <code>void</code>.</p>
</li>
<li><p>Use Cases SHOULD only throw Application-layer exceptions, catching the expected ones from the Domain Model.</p>
</li>
<li><p>Multiple small Domain Model components/services SHOULD be used instead of having large Use Case classes.</p>
</li>
<li><p>Use Case(s) SHOULD NOT extend other Use Case nor depend on another Use Case: they SHOULD be independent. Services or Components of the Domain Model are the way to go for code modularization/reusability.</p>
</li>
</ol>
<h2 id="the-presentation-layer">The Presentation Layer</h2>
<p>This is the outermost layer (together with Infrastructure) and it is the window of the external clients to your application. It defines the interface of your application for the outside world.</p>
<p>It may consist of the following types of objects:</p>
<ul>
<li>HTTP controllers which handle HTTP requests and responses</li>
<li>Forms or HTTP Request transformers (e.g. transforming requests to value objects to be used in the use cases)</li>
<li>Input Validation</li>
<li>Security (Authentication, Authorization, Roles)</li>
<li>Response factories (from use cases, exception to response converters, etc.)</li>
<li>CLI commands (console)</li>
<li>Message Queue producers (outgoing messages).</li>
<li>Message Queue consumers (incoming messages), consuming the Domain Events of external services.</li>
</ul>
<h3 id="presentation-layer-rules">Presentation Layer Rules</h3>
<ol>
<li><p>The Presentation layer SHOULD only know about the Application or DomainModel layers and nothing about the Infrastructure one.</p>
</li>
<li><p>HTTP Controllers are just a presentation layer of the Use Case(s).</p>
</li>
<li><p>HTTP Controllers SHOULD catch Application layer exceptions and resolve them into an HTTP response with a proper HTTP status code.</p>
</li>
</ol>
<h2 id="the-infrastructure-layer">The Infrastructure Layer</h2>
<p>The infrastructure layer is where we will implement the adapters of the interfaces of the other layers, most of them being typically in the Domain Model.</p>
<p>This layer mainly has everything related to external parties, e.g:</p>
<ul>
<li>DB adapters / repository interface implementations</li>
<li>HTTP clients for external services</li>
<li>Wrappers for vendor libraries or implementations of their interfaces</li>
</ul>
<h3 id="infrastructure-layer-rules">Infrastructure Layer Rules</h3>
<ol>
<li><p>This layer will mainly need code from the Domain Model, but will probably not use any of the other layers. To keep code clean, it's recommended to use only the Domain Model layer.</p>
</li>
<li><p>Domain Model repository / API client interfaces SHOULD be implemented here.</p>
</li>
</ol>
<h3 id="code-organization-example-of-an-onion-based-symfony-app">Code organization example of an onion-based Symfony app</h3>
<p>This is an example structure similar to the one I use on my Symfony applications in my current company. It's not perfect but after some years using the Onion structure we've made some changes to make it more evident where to put everything.</p>
<pre><code>/tests
/src
    /Application
        /UseCase
            /CreateOrder
                CreateOrderRequest
                CreateOrderResponse
                CreateOrderUseCase
    /DomainModel
        /<span class="hljs-keyword">Order</span>
            /Service
                OrderCodeGenerator
                OrderStateMachine
            /Factory
                OrderFactory
            /Entity
                OrderEntity
            /Event
                OrderCreatedEvent
                OrderShippedEvent
            /Repository
                OrderRepositoryInterface
    /Presentation
        /Http
            /Transformer
                RequestDataTransformer
                ExceptionResponseTransformer
            /EventSubscriber
                ExceptionSubscriber
            /Controller
                CreateOrderController
            /ResponsePayloadFactory
                CreateOrderPayload
        /Cli
            /Command
                CreateOrderCommand
        /Mq
            /MessageProducer
                OrderCreatedMessageProducer
            /MessageConsumer
                PaymentTransactionMessageConsumer
    /Infrastructure
        /Repository
            /Mysql
                OrderRepository
        /PaymentProvider
            /PaymentProviderClient
        /FileStorage
            /FileSystemClient
            /S3Client
        /Symfony
            /Authentication
        /(<span class="hljs-keyword">any</span> vendor library)
            /MyVendorLibraryExtension
    /Support
        TokenGenerator
        DateFormatter
</code></pre><h2 id="conclusion">Conclusion</h2>
<p>After more than 10 years of experience as a PHP developer, this is the cleanest structure I've worked with, and believe me, PHP projects can get really messy very quickly. </p>
<p>One of the most important things in a team, an organization is that you have common software development guidelines where you explicitly define what's the Target Architecture(*) of your different services, well-explained documentation that everyone understands and adopts in their daily work. It should be the reference in everyone's code reviews and it should be something you all agreed on as a group.</p>
<p>(*) A Target Architecture provides the details of a future state of a software architecture being developed within an organization.</p>
<p>There also is this video from Eric Normand, where he explains the Onion Architecture more in detail in a very friendly way while driving his car 😎.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=U8LOb0dyiB8">https://www.youtube.com/watch?v=U8LOb0dyiB8</a></div>
<h2 id="references">References</h2>
<ul>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Hexagonal_architecture_(software">Hexagonal Architecture (Wikipedia)</a>)</li>
<li><a target="_blank" href="https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/">The Onion Architecture by Jeffrey Palermo</a></li>
<li><a target="_blank" href="https://www.thinktocode.com/2018/03/12/three-layered-architecture-in-symfony/">Three Layered Architecture in Symfony</a></li>
<li><a target="_blank" href="https://github.com/carlosas/phpat">phpat</a> is a library that will help you respect your architectural rules in PHP projects.</li>
<li><a target="_blank" href="https://www.linkedin.com/pulse/clean-architecture-reza-bazghaleh">The Clean Architecture</a> - Another approach similar to the Hexagon and Onion architectures</li>
</ul>
<div class="hn-embed-widget" id="coffee"></div>]]></content:encoded></item><item><title><![CDATA[I'm creating an Isometric TileSet editor app with React and HTML5 Canvas because why not]]></title><description><![CDATA[Isometric TileSet Studio is a 3D-like tool for quickly prototyping isometric pixel-art worlds and tile sets.

With this tool you will be able to work in an isometric grid and create mock-ups of your isometric tiles, that you can later edit in your fa...]]></description><link>https://blog.itsjavi.com/im-creating-an-isometric-tileset-editor-app-with-react-and-html5-canvas-because-why-not</link><guid isPermaLink="true">https://blog.itsjavi.com/im-creating-an-isometric-tileset-editor-app-with-react-and-html5-canvas-because-why-not</guid><category><![CDATA[graphics]]></category><category><![CDATA[Game Development]]></category><category><![CDATA[HTML Canvas]]></category><category><![CDATA[React]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Sat, 20 Mar 2021 00:14:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1616283259567/kmzzl9bfJ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Isometric TileSet Studio is a 3D-like tool for quickly prototyping isometric pixel-art worlds and tile sets.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616283560167/9nyXAqgNo.png" alt="g1kP7H.png" /></p>
<p>With this tool you will be able to work in an isometric grid and create mock-ups of your isometric tiles, that you can later edit in your favorite pixel art editor.</p>
<p>The expected workflow will be: you create a shape (or a composition of them) in this editor and then you copy-paste it in your favorite pixel-art editor, e.g. <a target="_blank" href="https://www.aseprite.org/">Aseprite</a>.</p>
<p>You will be able to compose them in multiple layers, resize, change colors, stroke, rotation, tile size, etc.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616283612348/JiLQtA65L.gif" alt="kS190i.gif" /></p>
<p>If you are familiar with 3D editors, this tool will be very intuitive to use.</p>
<p>I spent a whole week working on this project but at least now it is a little usable.</p>
<p>I hope to make it more useful in the future, adding more features, making it more usable and efficient, but that depends on the expectation and interest I see in your comments :)</p>
<p>You can find this project on my Github:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/itsjavi/isometric-tileset-studio">https://github.com/itsjavi/isometric-tileset-studio</a></div>
<p>Editor home page: https://itsjavi.com/isometric-tileset-studio</p>
<div class="hn-embed-widget" id="coffee"></div>]]></content:encoded></item><item><title><![CDATA[Is Apple Silicon the end of Windows over Bootcamp? What does it mean for gamers and game developers?]]></title><description><![CDATA[Last year in 2020 Apple released new MacBook and Mac mini models with M1, a brand new ARM-based SoC, replacing completely Intel CPU and integrated GPU, as well as the memory modules that are now integrated into the SoC itself.
This year Apple will li...]]></description><link>https://blog.itsjavi.com/is-apple-silicon-the-end-of-windows-over-bootcamp-what-does-it-mean-for-gamers</link><guid isPermaLink="true">https://blog.itsjavi.com/is-apple-silicon-the-end-of-windows-over-bootcamp-what-does-it-mean-for-gamers</guid><category><![CDATA[Apple]]></category><category><![CDATA[macOS]]></category><category><![CDATA[bootcamp]]></category><category><![CDATA[gaming]]></category><category><![CDATA[Game Development]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Fri, 19 Mar 2021 20:23:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1616184320086/eh-yLTGc3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last year in 2020 Apple released new MacBook and Mac mini models with M1, a brand new ARM-based SoC, replacing completely Intel CPU and integrated GPU, as well as the memory modules that are now integrated into the SoC itself.</p>
<p>This year Apple will likely release new mac models (14" and 16" MacBooks and probably a new iMac) that will only integrate Apple Silicon chips (rumors talk about M1X or M2, doubling power), removing the option of Intel macs forever.</p>
<p>What does that mean for people that use Windows over Bootcamp to use Windows-based software or games?</p>
<p>Of course, Apple will probably still have old Intel-based models available for a while, but we might not see Windows compatibility for a while in Silicon macs.</p>
<p>The decision depends on Microsoft, whether they want to make their ARM-based Windows 10 compatible with the M1 chip or not.</p>
<p>Then they'll have to negotiate with Apple to upgrade Bootcamp in the next macOS versions to support Windows for ARM.</p>
<p>Right now Windows for ARM has some other important limitations: it is only compatible with 32-bit applications, although they're  <a target="_blank" href="https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewARM64">already working on an ARM64</a> version. Some <a target="_blank" href="https://www.youtube.com/watch?v=G7Qfk8hhA-c">users made it work on M1 chips via Parallels</a>, but support is far from perfect.</p>
<p>For gamers, it means that even if Windows ends supporting M1 chips and macOS, all the Windows games will also need to be compatible with ARM processors, and here comes the biggest issue: there is still a  <a target="_blank" href="https://www.reddit.com/r/Surface/comments/dv4b0n/surface_pro_x_game_compatibility_on_steam_epic/">very little catalog of games compatible with ARM</a> desktop processors. We might see this trend changing in the upcoming years, but support is still in the early stages.</p>
<p>If you are a game developer, you won't have many problems with Silicon macs, because most game development IDEs support or will support soon compiling games for x86/AMD64 CPUs. The only issue would be testing those builds.</p>
<p>If you are thinking about buying a new Apple computer with a Silicon chip for gaming, maybe it's still not a good option. Investing in a dedicated console or a budget PC with a decent graphics card might be a better option right now.</p>
<p>There is an ongoing transition that will probably take some years to become more matured and supported by the app and game developers of both ARM-based macOS and Windows.</p>
<div class="hn-embed-widget" id="coffee"></div>]]></content:encoded></item><item><title><![CDATA[GameMaker Studio 2, Unity 2020 and Godot Engine 3 Comparison for 2D Game Development]]></title><description><![CDATA[This is a guide for programmers and for beginners. Which engine should I choose? Here is my experience with all of them when trying to recreate a familiar retro game that we all know.
If you want to start game development it’s not always easy to deci...]]></description><link>https://blog.itsjavi.com/gamemaker-studio-2-unity-2020-and-godot-engine-3-comparison-for-2d-game-development</link><guid isPermaLink="true">https://blog.itsjavi.com/gamemaker-studio-2-unity-2020-and-godot-engine-3-comparison-for-2d-game-development</guid><category><![CDATA[unity]]></category><category><![CDATA[Game Development]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Wed, 18 Nov 2020 21:15:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1616176374899/JRVyvVNfI.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is a guide for programmers and for beginners. Which engine should I choose? Here is my experience with all of them when trying to recreate a familiar retro game that we all know.</p>
<p>If you want to start game development it’s not always easy to decide which engine fits best your needs.</p>
<p>That’s a process that has taken me almost 4 years of basic experience with engines like Melon JS, Unity, LÖVE, Game Maker Studio and now Godot. I can say I have touched all of them for a while, not very deep, but deep enough to realize which one was the best fit for me and the kind of games I want to do: 2D, sprite-based, grid-based movement (like a classic RPG).</p>
<p>What's the best engine? nothing in the internet will provide you the right answer: it depends on the kind of game you want to make, your experience as a programmer and what engine you feel more comfortable with.</p>
<p>In this article, I am always talking from my experience and probably many of the mentioned engines here may fit better for your games than others, but it doesn’t necessarily have to match my preferences. This article comes from a game dev beginner's perspective who is also a full-time Senior Software Engineer with more than 10 years of experience.</p>
<p>Said that, let’s begin talking about the game I was trying to develop and about the pros/cons I have found in every engine I tried to develop it with.</p>
<h1 id="my-project">My project</h1>
<p>I always loved Pokémon since I was a child. In fact, my nickname is based on the franchise.</p>
<p>I wanted to start game development making something that I already know well and that I’d love making: that’s right, I wanted to remake a Pokémon game, in my case Gameboy Color’s classic Gold and Silver.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616175542073/A4zk0Dmpw.png" alt="Screenshot 2020-06-28 at 17.34.55.png" /></p>
<blockquote>
<p>New Bark engine in Unity 2020</p>
</blockquote>
<p>I started in 2D to avoid having to learn all about 3D which seems more complex to me than using sprites in 2 dimensions. When I master 2D I might consider learning 3D later.</p>
<p>My idea is to create an engine that I can reuse later on to make my own monster-collecting games (not tied to Pokémon).</p>
<p>The first thing was obviously to choose the game engine. It was not an easy task (even less a few years ago): it involved a lot of googling things like “what’s the best engine for 2D game development”.</p>
<h2 id="initial-project-scope">Initial project scope</h2>
<p>My initial scope of the game was always simple: instead of thinking about all the aspects of the game I wanted to introduce or all that I need to do and frustrate myself, I always tried to create and fully cover in detail the first town of the game in every engine. That would cover these aspects:</p>
<ul>
<li>The tile-based map, including indoors (houses).</li>
<li>The player animation and grid-based movement + running</li>
<li>Collisions with tiles and other objects.</li>
<li>Interacting with objects: dialog boxes, printing text char by char and auto-advancing to the next line.</li>
<li>Teleport to another part of the scene with a fade-in/out transition: going inside and outside houses.</li>
<li>Basic game save/loading (player position)</li>
<li>Changing the background music depending on the area the player is in.</li>
<li>Sound effects (interacting with dialogs, collisions)</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616175544072/w37bvHV4K.gif" alt="Jun-28-2020 19-11-54-2.gif" /></p>
<blockquote>
<p>Example in Unity (frame-rate looks jumpy because of the GIF)</p>
</blockquote>
<h1 id="the-tested-engines">The tested engines</h1>
<h2 id="melonjs-50">MelonJS (5.0)</h2>
<p>MelonJS is a good engine to play with if you have a Web / JavaScript developer background. It provides you the basic blocks to build very simple games but it’s not aimed for making big complex games.</p>
<p>PROS</p>
<ul>
<li>Familiar languages. Quick to start with if you come from a Web / JavaScript developer background.</li>
<li>Compatible with browsers. You can run your game in the browsers or package it inside an Electron app for desktop.</li>
<li>Ok for simple games like Flappy Bird</li>
<li>Open source and free, community maintained.</li>
</ul>
<p>CONS</p>
<ul>
<li>It doesn’t have a dedicated IDE to work visually with the engine.</li>
<li>You have to write almost everything from scratch since the engine provides the very basic building blocks.</li>
<li>Not recommended for complex professional games.</li>
</ul>
<h2 id="love-110">LÖVE (11.0)</h2>
<p>With LÖVE I had a similar feeling as with MelonJS. There are not many differences apart from the language (Lua) and the way it packages and executes the games: In Android you have to install a separate app in order to execute LÖVE games. That’s something I didn’t like.</p>
<p>Maybe LÖVE has a more mature API than MelonJS that lets you build a bit more complex games, but still: no IDE, a lot of code required for getting started with a simple game.</p>
<p>So it has basically similar PROS/CONS to MelonJS.</p>
<h2 id="unity-v2017v2020">Unity (v2017–v2020)</h2>
<p>I tried to use Unity before any other, but the complexity of the IDE scared me a bit in the beginning and I opted for more simple engines.</p>
<p>I came back to Unity after discovering that I was not going to go any further with the previously mentioned engines. So I gave it another try starting from the 2017 version until v2020.</p>
<p>My first impression after learning the basic concepts of game development with the other engines was: wow, this feels very powerful and I have a good language like C#.</p>
<p>Starting a 2D game of my characteristics in Unity is not an easy task. Back then in 2017, there were no 2D pixel-perfect tools or tilemap editor, so everything looked a bit glitchy.</p>
<p>I had to watch lots of tutorials for a year in order to have the first town of the game working with dialogs and grid-based movement but nothing more.</p>
<p>I needed code for almost anything, I had to write my own physics engine because the built-in one is not so flexible, so I could not use it for grid-based movement and collisions because I always had problems (e.g. bounciness, stuck pixels, etc.).</p>
<p>PROS</p>
<ul>
<li>Industry-standard for many kinds of games (mostly mobile and PC / console casual games). If you master this engine you probably can apply for a job in lots of game dev companies.</li>
<li>Robust OOP Language which is used in many other areas not only game development: C#</li>
<li>The engine evolves very quickly. The jump from 2018 to 2020 was huge. Lots of things have changed.</li>
<li>Future looks promising for 2D game development, but still uncertain.</li>
<li>You can use the engine for free, even commercially up to a certain amount of sales. That’s great for learning the engine.</li>
</ul>
<p>CONS</p>
<ul>
<li>Still feels incomplete for 2D development after all these years. I feel that 2D features are not a priority for Unity, they still seem more focused on 3D: 3D games, CAD (for automotive, construction etc) and VR/AR right now. It’s not clear nor transparent the direction they are taking for 2D game development.</li>
<li>Learning curve is high, even more for 2D game development, since Unity was initially intended only for 3D. This has improved a lot in the last years but there are still many lacks that are covered in other engines very well.</li>
<li>Lack of information and tutorials for classic 2D games without modern physics. This has been a major handicap and time-consuming for my case. Something so basic like transitioning from one room/scene to another with a transition, there are not good examples for that.</li>
<li>The Animator frame function callbacks are not reliable like in other engines.</li>
<li>Convoluted event system. They are complex to set up and you don’t have a way to have a clear overview of what happens when.</li>
<li>The built-in components are very generic, they allow you to make any game you want but at the cost of also having to write a lot of code. The package system has been a good addition though.</li>
<li>Migrating your game to a new version may break it. The amount of changes introduced from 2018 to 2020 is huge (and they are still in progress like the DOTS engine). It makes you think if it’s a good moment to learn this engine or wait.</li>
<li>Many 2D-related bugs that you don’t really know if they will ever fix them.</li>
<li>Not having a dedicated language for game development makes the usage of C# very convoluted in many cases like the mentioned game event handling.</li>
</ul>
<p>… and I probably found more obstacles that made me give up with Unity… after trying GameMaker Studio 2.</p>
<h2 id="gamemaker-studio-22">GameMaker Studio 2.2</h2>
<p>I won’t extend so much with this engine because I only have used it for less than 6 months, but here are my impressions:</p>
<p>PROS</p>
<ul>
<li>The engine, at first sight, seems a good choice for 2D game development. Many basic aspects of 2D development are covered here while they are lacking in other engines like Unity. Lots of aspects seem very convenient.</li>
<li>Learning curve is low: I wrote the same basic town in 1 month instead of 1 year that took me doing the same in Unity.</li>
<li>Good for quickly prototyping games and for learning the basics concepts of game development.</li>
<li>You can make your games without writing a single line of code: using Drag-and-Drop components. That’s good for non-developers to write casual games.</li>
<li>If there is any error in your whole code or some reference missing, the editor complains before running your game. That’s good in case you changed script names or refactored code.</li>
<li>Undertale and Swords of Ditto were made with this engine, so it’s possible to create full complex games that can be commercialized if you don’t care about the cons.</li>
</ul>
<p>CONS</p>
<ul>
<li>If you are not a developer, the engine teaches you bad practices that you will probably drag for years in your developer career. So, if you never worked with an object-oriented programming language I recommend you to avoid starting with GameMaker but start simple with an engine that has OOP like LÖVE (it uses Lua) or even MelonJS (now that Javascript supports proper classes). Later on you can try GameMaker if you want, then you will be able to notice the difference.</li>
<li>GML has no OOP (Object-Oriented-Programming). Every data structure has to be in integer-indexed arrays. Managing your variables using enums and arrays is a no-go for big projects. Although OOP will be partially introduced in v2.3 and will feel similar to Javascript objects and functions, it still needs a long way to go to be mature.</li>
<li>Porting code from Unity / C# to GML was not easy due to the huge differences in the way GameMaker is doing things.</li>
<li>Some built-in components are opinionated (not flexible enough), meaning that they will somehow dictate how your game has to work.</li>
<li>There is no built-in 2D lighting system. You have to write it from scratch or use assets from the marketplace or the community. That might be ok if you don’t need this feature for your game or you make your shadows/lights with translucent layers.</li>
<li>As soon as your project gets big it becomes unmaintainable: lots of windows here and there, lots of scripts, lots of data structures as arrays and enums</li>
<li>Hard to refactor code: you have to do it everywhere manually, the IDE doesn’t detect the usages of your scripts, variables, etc. that you are renaming.</li>
<li>It has a trial, but after that you have to pay for a license. Not nice if you just want to learn this engine before deciding to use it commercially.</li>
<li>You need to log in with your account in the IDE in order to use it, so you cannot use it offline. If your network is slow, the IDE can take a lot of time to start.</li>
</ul>
<p>Then I started following <a target="_blank" href="https://www.youtube.com/user/uheartbeast/">HeartBeast</a> tutorials and videos on YouTube and decided to give Godot Engine a try.</p>
<h2 id="godot-engine-32">Godot Engine 3.2</h2>
<p>I have heard about Godot years ago but I thought it was like another indie game development engine and I was afraid that It wasn’t going to be enough for what I wanted to achieve.</p>
<p>Well… I am discovering that I was wrong.</p>
<p>In May 2020 I started watching <a target="_blank" href="https://www.youtube.com/user/uheartbeast/">HeartBeast</a>’s Godot tutorials on YouTube and, after trying all the other engines I have to say it has been very easy to learn, also because HeartBeast is a very good teacher.</p>
<p>Let’s say that Godot has the good stuff that I found in GameMaker and Unity combined together, plus it has a dedicated OOP gaming language that it may not be as powerful as C# but it does what it should do and it’s improving very fast.</p>
<p>My first impression of this engine is: wow, they got things right like I expected them to work, everything is so intuitive and works so conveniently together.</p>
<p>In less than one month I achieved half of what I did in GameMaker, but the quality of my code and the scenes feels much much better.</p>
<p>It also takes me more time because I am writing the game in a modularised component-based way: similar concept as React JS where each component can be reusable and can potentially work on its own. That combined with signals/events is very powerful.</p>
<p>So here is my (preliminary) opinion on Godot:</p>
<p>PROS</p>
<ul>
<li>Free and open source. Community driven. You clearly see the direction this project is taking, you can tell by the Github Issues/PRs/Milestones. So there are no surprises.</li>
<li>Multi-platform without the need for extra licenses: Desktop, Browser or Mobile.</li>
<li>Transparent founding system. With all the donations they hire people to take the engine to the next level. That’s something I like and the support of the community is impressive.</li>
<li>Intuitive IDE. If you tried Unity and GameMaker, you will love Godot. In the beginning, you will be a bit lost to know what’s everything, but with some tutorials, you get it quickly.</li>
<li>Faster than the competitors. Running my simple town is much much faster than with Unity or GameMaker.</li>
<li>It also has live code editing like Unity.</li>
<li>Huge set of reusable components, which are highly flexible and customizable compared to the other engines. This saves you lots and lots of code.</li>
<li>I didn’t try animations much deeper than just sprites, but they seem more powerful than in Unity or GameMaker. Function callbacks in the Animation timeline are reliable and called when expected if you don’t have important frame drops.</li>
<li>A great and friendly community with tutorials that still work even after minor version updates. I have found some outdated tutorials, but not so many compared to the other engines and the things I had to change to make them work were not hard to find.</li>
<li>I love the node/scene system and concept. You can build perfectly decoupled and reusable scenes, helping you write better games more than with any other game engine. You can build much cleaner games by having each level (composited by multiple scenes) working as a standalone mini-game. That’s perfect for testing and learning how coupled are the different parts of your game.</li>
<li>Another thing that I really love, that in other engines is more convoluted: The signals system (events). They are so visually intuitive that you feel encouraged to use them from day 1. That also helps writing better &amp; decoupled code.</li>
<li>It has a dedicated OOP language, written specifically for game development: GDScript. Although the engine also supports VisualScript (like GM Drag and Drop), NativeScript (for more low-level code) and C# !! Even If I like C# a lot, I stay with GDScript because it feels much easier and convenient for the engine, plus it seems to get new features before C#.</li>
<li>Documentation of the Godot engine API is just great, extensive and well explained. You don’t have to leave the IDE to check the docs or wait for a webpage to load inside a frame.</li>
<li>Shaders are very easy to integrate and learn to write in this engine. It has a visual diagram tool to build them if you don’t want to write their code.</li>
</ul>
<p>CONS</p>
<ul>
<li>I wish I knew this engine before. Unity and GameMaker are better known because the most part is the hype and marketing behind them. Godot community doesn’t invest much in that, but rather focuses on the quality of the engine and spends the most part of the budget on that. I little more promotion and marketing for Godot is needed I would say.</li>
<li>GDScript feels great but it there is some stuff that I would like to see improved (and actually it is being in the works): Ability to export any data structure in the inspector, variable groups and hints in the inspector, type hinting for any class.</li>
<li>The IDE has serious performance issues when playing animated textures in the 2D view. It’s being investigated but I have to hide the layer so my laptop doesn’t burn.</li>
<li>The TileSet editor seems very powerful but it has UX/usability problems, same for the 2D view TileMap editor. <a target="_blank" href="https://github.com/godotengine/godot-proposals/issues/896">Various proposals are being considered</a>.</li>
<li>There is no built-in sprite editor but that’s ok for me since I can also work with Aseprite. Using Aseprite and GameMaker sprite editor at the same time was tedious because of the different keyboard shortcuts.</li>
<li>The engine it’s not compatible with any console <a target="_blank" href="https://docs.godotengine.org/en/3.0/tutorials/platform/consoles.html">and it probably won’t</a> because it’s open-source, so it is meant for developers that intend to release their games for Desktop, Browser or Mobile only. By the time your game becomes popular, probably you will have enough budget to hire people to port it to consoles using another engine.</li>
</ul>
<h1 id="conclusion">Conclusion</h1>
<p>I know, this is a long post to read, but thank you for taking your time.</p>
<p>I wanted to provide you all what I experienced using these engines (or a summary of what I can remember) so with all that information you will have a better understanding of what can you expect and the struggles you will find if you want to do similar 2D games as I do.</p>
<p>Of course, choosing the best game engine that suits your needs it’s always up to you.</p>
<p><strong>In my opinion the clear winner here is Godot, at least for now</strong>. It seems to have everything I need, It has a quick learning curve, good tutorials, encourages good practices, … and more that I have to discover.</p>
<p>I will keep posting Godot tips and tutorials here as well as some of the progress of my games, mostly the parts that I think you might find interesting or that were the most challenging for me.</p>
<p>I end this article with this thought: if you have a game idea, don’t try to do everything the first day because you’ll get frustrated. Set yourself small scopes and goals for your game. Keep trying, do little by little every day or weekend, at your own pace and the most important thing: Never give up!</p>
<div class="hn-embed-widget" id="coffee"></div>]]></content:encoded></item><item><title><![CDATA[How to change CollisionShape color tint properly in Godot]]></title><description><![CDATA[In this video tutorial I'll show you a trick to give proper colors to the collision shapes in Godot because, by default, the tint color gets mixed with the default one which unfortunately is not white.
https://www.youtube.com/watch?v=5TUeWl_O0kE?star...]]></description><link>https://blog.itsjavi.com/how-to-change-collisionshape-color-tint-properly-in-godot</link><guid isPermaLink="true">https://blog.itsjavi.com/how-to-change-collisionshape-color-tint-properly-in-godot</guid><category><![CDATA[Game Development]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Tue, 04 Aug 2020 21:42:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1616279747266/7qP4hBYLF.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this video tutorial I'll show you a trick to give proper colors to the collision shapes in Godot because, by default, the tint color gets mixed with the default one which unfortunately is not white.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=5TUeWl_O0kE?start=7">https://www.youtube.com/watch?v=5TUeWl_O0kE?start=7</a></div>
<div class="hn-embed-widget" id="coffee"></div>]]></content:encoded></item><item><title><![CDATA[How to use tiles for your dialog box borders in Godot: The NinePatchRect component]]></title><description><![CDATA[The other day I was looking for the counterpart of the Unity Panel’s tiled image mode but it didn’t seem an easy thing to find. Lots of tutorials cover how to make your own themes, but it was hard to find how to use tiles for the borders in Godot.
Wh...]]></description><link>https://blog.itsjavi.com/how-to-use-tiles-for-your-dialog-box-borders-in-godot-the-ninepatchrect-component</link><guid isPermaLink="true">https://blog.itsjavi.com/how-to-use-tiles-for-your-dialog-box-borders-in-godot-the-ninepatchrect-component</guid><category><![CDATA[Game Development]]></category><dc:creator><![CDATA[Javier Aguilar]]></dc:creator><pubDate>Sun, 28 Jun 2020 19:46:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1616176295759/VEeaFKUcl.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The other day I was looking for the counterpart of the Unity Panel’s tiled image mode but it didn’t seem an easy thing to find. Lots of tutorials cover how to make your own themes, but it was hard to find how to use tiles for the borders in Godot.</p>
<p>When you build a tile-based game it’s what you usually want for your UI: too look pixel-perfect with that retro look.</p>
<p>Here is the example in Unity:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616175549654/o3CaDDfkH.png" alt="Screenshot 2020-06-28 at 16.18.53.png" /></p>
<blockquote>
<p>In the Panel component in Unity, you have the option of using a “Tiled” image type easily. As you can see, it detects the 9 tiles automatically.</p>
</blockquote>
<p>After some more digging, it turns out that in Godot Engine you have a very powerful and customisable component (even more than in Unity) called NinePatchRect. With it, you can use any texture and slice the region you are interested in to use it as the borders of your panels / dialog boxes.</p>
<p>The important inspector settings are:</p>
<ul>
<li>Region Rect: Defines the area of the texture to use</li>
<li>Patch Margin: Defines the margins of the borders, so they keep always the same size/ratio even if your panel is resized.</li>
<li>Axis Stretch: Defines how to stretch the tiles when resized. Here usually you will want it as “Tiled” in both horizontal and vertical. This way the tiles are not stretched, but auto-tiled one next another when you resize the panel.</li>
</ul>
<p>Here is an example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616175551225/qOL6cdhsL.png" alt="Screenshot 2020-06-28 at 16.21.28.png" /></p>
<blockquote>
<p>Basic NinePatchRect configuration in Godot for 16x16 px tiles</p>
</blockquote>
<div class="hn-embed-widget" id="coffee"></div>]]></content:encoded></item></channel></rss>