<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Breno Lira</title>
    <description>The latest articles on Forem by Breno Lira (@brenoliradev).</description>
    <link>https://forem.com/brenoliradev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1927949%2Fcf85ab36-6b66-482c-8372-b85e3fd44211.png</url>
      <title>Forem: Breno Lira</title>
      <link>https://forem.com/brenoliradev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/brenoliradev"/>
    <language>en</language>
    <item>
      <title>Creating Standalone Widgets with Svelte: My Journey and Solutions</title>
      <dc:creator>Breno Lira</dc:creator>
      <pubDate>Wed, 14 Aug 2024 12:14:18 +0000</pubDate>
      <link>https://forem.com/brenoliradev/how-to-create-widgets-using-svelte-1gep</link>
      <guid>https://forem.com/brenoliradev/how-to-create-widgets-using-svelte-1gep</guid>
      <description>&lt;p&gt;On the past months In the past few months, I was tasked with determining how to write and manage standalone widgets for my full-time job. While it was relatively straightforward to ensure they were functional, I quickly realized that maintaining them was a different challenge altogether&lt;/p&gt;

&lt;p&gt;With this in mind, I began a side project during my spare time and made it open-source. This allowed me to share my insights and the strategies that helped me ensure the quality of my widgets.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I did them originally?
&lt;/h3&gt;

&lt;p&gt;Since my widgets required a high level of reactivity, I relied heavily on the &lt;a href="https://svelte.dev/docs/client-side-component-api#creating-a-component" rel="noopener noreferrer"&gt;Svelte component API&lt;/a&gt; and used &lt;a href="https://rollupjs.org/" rel="noopener noreferrer"&gt;Rollup&lt;/a&gt; for bundling. "It was simple and direct until I got the following problems: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;My unused CSS increasing overtime and I was also unsure if only the CSS of the desired component was being bundled on. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hard time handling JavaScript through widgets without strict typing. It rapidly became a mess since I had to share some utils like jwt decoding and authentication.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How I changed it?
&lt;/h3&gt;

&lt;p&gt;I began to consider how I could establish some defaults and, more importantly, integrate a type system. This led to the creation of my side project, &lt;a href="https://github.com/brenoliradev/svelte-standalone" rel="noopener noreferrer"&gt;svelte-standalone&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The goal of svelte-standalone was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure a well minified CSS and remove unused CSS when bundling. &lt;/li&gt;
&lt;li&gt;Ensure a type system of choice well supported and reused on all my app.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: the type system of choice was TypeScript.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Ensure unit and integration testing.&lt;/li&gt;
&lt;li&gt;Ensure that I could check my widgets visually before and after rollup parsing them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How I achieved all of that?
&lt;/h3&gt;

&lt;p&gt;After ensuring TypeScript compatibility with Rollup plugins and the Svelte preprocessor, I took a step back and broke down my project into key steps. Basically I had:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;&amp;lt;component&amp;gt;.svelte&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;embed.js&lt;/code&gt; file responsible for starting the instance of &lt;code&gt;&amp;lt;component&amp;gt;.svelte&lt;/code&gt; file and adding it to body.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From that I noticed that my embed file so was basically a default replicated on all my widgets and started generating them. So I was able to use codegen tools to generate 3 files based on my svelte files and my desire of handling the types throughout the app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;declaration.d.ts - enabled that I could directly import my svelte component and wrap it using &lt;a href="https://svelte.dev/docs/typescript#types-sveltecomponent" rel="noopener noreferrer"&gt;SvelteComponent&lt;/a&gt; type so I turned my svelte components strong typed by default.&lt;/li&gt;
&lt;li&gt;types.ts - enabled that I could write a &lt;code&gt;defaultConfig&lt;/code&gt; based on the props declared from &lt;code&gt;declaration.d.ts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;embed.ts - enabled start/stop of my component in a standard way for all my widgets!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And voilà! This approach resolved my issues with the type system and improved the maintainability of my widgets.&lt;/p&gt;

&lt;h4&gt;
  
  
  How I Addressed CSS Challenges:
&lt;/h4&gt;

&lt;p&gt;The main CSS-related challenges I faced were: How can I purge and minify my CSS without the hassle? How can I write CSS that is both easy to collaborate on and integrate into different environments?&lt;/p&gt;

&lt;p&gt;The solution was pretty straightforward: just use Tailwind CSS.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnl34og6svh4m5ivfls6r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnl34og6svh4m5ivfls6r.png" alt="bell curve meme: just use tailwind" width="490" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this approach, I identified the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No More Conflicting Styles&lt;/strong&gt;: Using Tailwind allowed me to stop worrying about conflicting styles. For example, when dealing with a legacy app heavily reliant on Bootstrap, I simply applied a prefix and an important flag to my widget, and the conflicts were resolved.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Seamless Integration&lt;/strong&gt;: When importing my widget into another Tailwind app, I could easily omit certain Tailwind directives to reduce my bundle size.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Effortless Purging and Minification&lt;/strong&gt;: Minifying became straightforward, and with Tailwind’s built-in PurgeCSS, I just needed to configure the content flag properly for each widget. This ensured that only the necessary styles were included in the final bundle.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  How I Addressed The Testing Issues?
&lt;/h4&gt;

&lt;p&gt;I faced a challenge in ensuring comprehensive testing for my widgets, covering unit testing, integration testing, and visual testing.&lt;/p&gt;

&lt;p&gt;My primary goal was to visualize my components both before and after processing them with Rollup. To achieve this, I took the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Strictly-Typed Storybook&lt;/strong&gt;: I implemented a strictly-typed Storybook based on my &lt;code&gt;declaration.d.ts&lt;/code&gt; and &lt;code&gt;types.ts&lt;/code&gt; files. This made it convenient to generate a default story for each of my widgets automatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vite Integration&lt;/strong&gt;: I used Vite to load the bundled component on a Svelte route. It was also convenient to generate a default route component based on my TypeScript files.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That was all! I would wholeheartedly appreciate some feedback! Also, check out &lt;a href="https://github.com/brenoliradev/svelte-standalone/" rel="noopener noreferrer"&gt;svelte-standalone&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Whether you have questions, suggestions, or concerns, feel free to contact me!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
