<?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>DEV Community: Michael Essiet</title>
    <description>The latest articles on DEV Community by Michael Essiet (@devshogun).</description>
    <link>https://dev.to/devshogun</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%2F919912%2F683069d1-de5b-4c08-b933-811533cfabae.JPG</url>
      <title>DEV Community: Michael Essiet</title>
      <link>https://dev.to/devshogun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devshogun"/>
    <language>en</language>
    <item>
      <title>Embracing Rust-Style Error Handling in JavaScript with try.rs</title>
      <dc:creator>Michael Essiet</dc:creator>
      <pubDate>Sat, 12 Apr 2025 09:45:44 +0000</pubDate>
      <link>https://dev.to/devshogun/embracing-rust-style-error-handling-in-javascript-with-tryrs-22m8</link>
      <guid>https://dev.to/devshogun/embracing-rust-style-error-handling-in-javascript-with-tryrs-22m8</guid>
      <description>&lt;p&gt;JavaScript's error handling has long been a source of frustration for JS devs. The traditional &lt;code&gt;try/catch&lt;/code&gt; mechanism often leads to verbose spaghetti code, making it challenging to manage errors effectively. Enter &lt;code&gt;try.rs&lt;/code&gt;, a TypeScript library that I've been using for my personal projects that brings Rust-like error handling to JavaScript and TypeScript, offering a more structured and readable approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Problem with JavaScript's Error Handling
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;try...catch&lt;/code&gt; syntax has served us for years, but it often leads to certain challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verbosity and Nesting: Handling multiple potential failure points often requires nested &lt;code&gt;try...catch&lt;/code&gt; blocks or multiple separate blocks, which can make code harder to read and follow ("try...catch hell").
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;someFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;anotherFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error in anotherFunction:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error in someFunction:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Flow Interruption: try...catch can break the chain of functional method calls or make the "happy path" logic harder to distinguish from the error handling logic.&lt;/li&gt;
&lt;li&gt;Implicit Errors: It's easy to forget to wrap potentially failing code in a try...catch. In environments like Node.js, an uncaught exception can crash the entire process. Even in the browser, it often times leads to broken user experiences.&lt;/li&gt;
&lt;li&gt;Overly Broad Catching: A single catch block might catch different types of errors from the try block, requiring complex conditional logic within the catch to handle them appropriately. Sometimes, we might accidentally catch bugs instead of expected failures (like network issues), masking underlying problems.&lt;/li&gt;
&lt;li&gt;Performance Considerations: While often negligible, exception handling mechanisms can introduce performance overhead compared to returning values, especially in older JavaScript engines or performance-critical loops.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Possible Solutions to Improve Error Handling
&lt;/h2&gt;

&lt;p&gt;Over the years, us developers have explored various approaches to improve error handling in JavaScript:&lt;/p&gt;

&lt;h3&gt;
  
  
  Promise .catch()
&lt;/h3&gt;

&lt;p&gt;For asynchronous operations, Promises provide a &lt;code&gt;.catch()&lt;/code&gt; method to handle errors. This is cleaner than nested try...catch blocks but still requires careful chaining to avoid missing errors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;processData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Callback Pattern
&lt;/h3&gt;

&lt;p&gt;In older Node.js code, the callback pattern was widely used, where functions explicitly passed an error as the first argument. While this avoids throwing exceptions, it can lead to "callback hell" and is less common in modern JavaScript code now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file.txt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error reading file:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;File data:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Go-style Error Returns
&lt;/h3&gt;

&lt;p&gt;Inspired by Go, some of us use a pattern where functions return a tuple (or array) containing an error and a result. This makes errors explicit but requires manual checking after every call. (e.g the try-catch package)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mightFail&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Result:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Functional Error Handling
&lt;/h3&gt;

&lt;p&gt;Libraries like &lt;code&gt;fp-ts&lt;/code&gt; and &lt;code&gt;neverthrow&lt;/code&gt; introduce functional programming concepts such as Either or Result types. These types explicitly represent success or failure as values, making error handling more predictable and composable.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Introducing try.rs: A Rust-Inspired Solution
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;try.rs&lt;/code&gt; is a TypeScript library that emulates Rust's &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;/code&gt; type, providing a structured way to handle operations that may fail. It encourages the explicit handling of errors, leading to more predictable and maintainable code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Result Type: Encapsulates success (&lt;code&gt;Ok&amp;lt;T&amp;gt;&lt;/code&gt;) and failure (&lt;code&gt;Err&amp;lt;E&amp;gt;&lt;/code&gt;) outcomes.&lt;/li&gt;
&lt;li&gt;Chainable Methods: Functions like &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;andThen&lt;/code&gt;, and &lt;code&gt;mapErr&lt;/code&gt; allow for fluent transformations.&lt;/li&gt;
&lt;li&gt;Pattern Matching: The match method enables clear and concise handling of different result states.&lt;/li&gt;
&lt;li&gt;Async Support: &lt;code&gt;tryAsync&lt;/code&gt; wraps asynchronous functions, integrating seamlessly with &lt;code&gt;async/await&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Type Safety: Leverages TypeScript's type system to enforce error handling at compile time.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Practical Examples of try.rs in Action
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Handling Synchronous Operations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;try.rs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Division by zero&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Result: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wrapping Functions That May Throw
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;tryFn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;try.rs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parseJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;tryFn&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"name": "Alice"}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Parsed data: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Parsing error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Managing Asynchronous Operations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;tryAsync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;try.rs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;tryAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`HTTP error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Data:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;try.rs&lt;/code&gt; offers a compelling alternative to traditional JavaScript error handling by introducing a Rust-inspired Result type. It promotes explicit and consistent error management, leading to cleaner and more reliable code. By integrating try.rs into your JavaScript or TypeScript projects, you can enhance your application's robustness, readability, and maintainability. I've been using it internally for some time now so I thought I'd share it with all of you.&lt;/p&gt;

&lt;p&gt;For more information and to get started, visit the &lt;a href="https://www.npmjs.com/package/try.rs" rel="noopener noreferrer"&gt;try.rs npm package page&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Creating a Browser Extension using SolidJS + WXT II</title>
      <dc:creator>Michael Essiet</dc:creator>
      <pubDate>Fri, 22 Mar 2024 17:10:28 +0000</pubDate>
      <link>https://dev.to/devshogun/creating-a-browser-extension-using-solidjs-wxt-ii-4lf5</link>
      <guid>https://dev.to/devshogun/creating-a-browser-extension-using-solidjs-wxt-ii-4lf5</guid>
      <description>&lt;p&gt;It's no secret that browser extensions are a powerful tool for enhancing the browsing experience. They can be used to add new features, modify existing ones, or even create entirely new applications. In this article, we'll be talking about the process of creating a browser extension and things you should keep in mind using SolidJS and WXT.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons learnt
&lt;/h2&gt;

&lt;p&gt;The first time I tried to create a browser extension I was under the impression that it required some kind of special programming language, compilation method or something. Turns out they're just web apps bundled to run in the browser runtime. This means that you can use most of the same technologies that you use to build web apps to build browser extensions. You can use HTML, CSS, and JavaScript to build the user interface, and you can use JavaScript to interact with the browser's APIs.&lt;/p&gt;

&lt;p&gt;WXT takes it to the next level though. It's a tool that allows you to scaffold a browser extension project with a single command. It also provides a way to manage your manifest file, pages, scripts and service workers. Did I forget to mention that it also offers framework support? Yup you can use WXT with React, Vue, Svelte, and SolidJS. It really helped in managing and creating the manifest file, background scripts, content scripts, browser actions, page actions, and permissions. Which are all important parts of a browser extension.&lt;/p&gt;

&lt;p&gt;In my &lt;a href="https://essiet.dev/posts/creating-a-browser-extension-using-solidjs"&gt;previous&lt;/a&gt; article about creating a browser extension using SolidJS, I had initially thought that all you needed was Javascript, HTML, CSS, and a manifest file and you were good to go. Oh, how wrong I was. I had to learn about the limitations of browser extensions, the importance of messaging, and the different APIs that are available to browser extensions. I also had to learn about the different parts of the manifest file and how to manage them. For instance, the permissions, the background scripts, the content scripts, the browser actions, the page actions, and the storage. And did you know that the window size is limited to 800x600? I didn't. This is why I decided to write this article. To share what I've learnt and to help others who might be interested in creating a browser extension.&lt;/p&gt;

&lt;h3&gt;
  
  
  Difference between browser extensions and web apps
&lt;/h3&gt;

&lt;p&gt;Here's a table of the differences between browser extensions and web apps:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Browser Extensions&lt;/th&gt;
&lt;th&gt;Web Apps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;can be used to add new features, modify existing ones, or even create entirely new applications&lt;/td&gt;
&lt;td&gt;is a client-server software application in which the client (or user interface) runs in a web browser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;can be used to modify the behavior of the browser itself&lt;/td&gt;
&lt;td&gt;are accessed through the internet and are designed to be used on a web browser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;can be used to interact with the browser runtime's APIs and it's window APIs&lt;/td&gt;
&lt;td&gt;can be used to interact with the server's APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;can be used to interact with the browser's tabs, windows, and bookmarks&lt;/td&gt;
&lt;td&gt;can only interact with their tab and the server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;advised to use the browser's storage APIs e.g chrome.storage&lt;/td&gt;
&lt;td&gt;web storage APIs a pretty much all you need e.g localStorage and sessionStorage&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Concerning the last point, the browser's storage APIs are advised to be used in browser extensions because they can be used in service workers. Service workers are a type of web worker that runs in the background and can be used to intercept and handle network requests, cache resources, carry out messaging, and handle push notifications. They are also used to manage the browser's storage APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  API limitations
&lt;/h3&gt;

&lt;p&gt;There are some limitations to the APIs that are available to browser extensions. For instance, the &lt;code&gt;window&lt;/code&gt; object is not available to background scripts. This is because background scripts are compiled ahead of time to a single file and can't use the &lt;code&gt;window&lt;/code&gt; or &lt;code&gt;document&lt;/code&gt; object. They can only use the &lt;code&gt;chrome&lt;/code&gt; object and the &lt;code&gt;chrome.runtime&lt;/code&gt; object. The &lt;code&gt;chrome&lt;/code&gt; object is used to interact with the browser's APIs and the &lt;code&gt;chrome.runtime&lt;/code&gt; object is used to interact with the browser's runtime. The &lt;code&gt;chrome.runtime&lt;/code&gt; object is used to manage the extension's lifecycle, to manage the extension's manifest file, to manage the extension's storage, to manage the extension's messaging, and to manage the extension's permissions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Storage
&lt;/h4&gt;

&lt;p&gt;There are two types of storage that are available to browser extensions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Storage APIs (can't be used in service worker)&lt;/li&gt;
&lt;li&gt;Browser storage APIs e.g chrome.storage (can be used in service worker)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The web storage APIs are a set of APIs that are used to store web app user data in the browser. The most common example of a web storage API is &lt;code&gt;localStorage&lt;/code&gt;, which offers a storage limit up to 5MB and is semi persistent. The browser storage APIs are a set of APIs that are used to store extension and service worker user data, with the &lt;code&gt;unlimitedStorage&lt;/code&gt; permission they can even store data large than 5MB. The most common example is &lt;code&gt;chrome.storage.local&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One major thing to keep in mind though is the difference in the way the two storage APIs are used. The web storage APIs are used to store data in the browser's window object and can only be used in the window object. The browser storage APIs are used to store data in the browser's storage object and can be used in the window object and the service worker object. Browser storage APIs are asynchronous as opposed to web storage APIs which are synchronous.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// web storage APIs&lt;/span&gt;
&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// browser storage APIs&lt;/span&gt;
&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Value is set to &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Value currently is &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WXT provides a wrapper for the different browser storage APIs. As you may have noticed &lt;code&gt;chrome.storage.local&lt;/code&gt; is only usable on chromium browsers. The wrapper allows you to use single code to interact with different browsers. Making your extension compatible on Chrome, Safari, and Firefox.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;local:key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;local:key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Permissions
&lt;/h4&gt;

&lt;p&gt;Permissions are something that you should get very acquainted with if you plan to build an extension that functions more than just some simple todo app. This part my be a bit tricky because you have to be very specific about the permissions you request. You can't just request all permissions and hope for the best, because, when submitting your extension to the web store, the permissions you request are reviewed by the Chrome Web Store team. They will only approve the permissions that are necessary for your extension to function. If you request permissions that are not necessary for your extension to function, your extension will be rejected and asked to resubmit with the unnecessary permissions removed.&lt;/p&gt;

&lt;p&gt;Here's a comprehensive list of the permissions that are available to browser extensions using Manifest V3 as of the time of writing this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/develop/concepts/activeTab"&gt;activeTab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/alarms"&gt;alarms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/bookmarks"&gt;bookmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/browsingData"&gt;browsingData&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/contentSettings"&gt;contentSettings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/contextMenus"&gt;contextMenus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/cookies"&gt;cookies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/debugger"&gt;debugger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/declarativeContent"&gt;declarativeContent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/declarativeNetRequest"&gt;declarativeNetRequest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/declarativeNetRequest"&gt;declarativeNetRequestFeedback&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/desktopCapture"&gt;desktopCapture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/dns"&gt;dns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/documentScan"&gt;documentScan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/downloads"&gt;downloads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/enterprise/deviceAttributes"&gt;enterprise.deviceAttributes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/enterprise/platformKeys"&gt;enterprise.platformKeys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/fileBrowserHandler"&gt;fileBrowserHandler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/fileSystemProvider"&gt;fileSystemProvider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/fontSettings"&gt;fontSettings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/gcm"&gt;gcm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/how-to/web-platform/geolocation"&gt;geolocation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/history"&gt;history&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/identity"&gt;identity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/idle"&gt;idle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/management"&gt;management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/notifications"&gt;notifications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/pageCapture"&gt;pageCapture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/platformKeys"&gt;platformKeys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/power"&gt;power&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/printerProvider"&gt;printerProvider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/processes"&gt;processes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/proxy"&gt;proxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/scripting"&gt;scripting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/sessions"&gt;sessions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/storage"&gt;storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/system/cpu"&gt;system.cpu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/system/display"&gt;system.display&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/system/memory"&gt;system.memory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/system/storage"&gt;system.storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/tabCapture"&gt;tabCapture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/tabs"&gt;tabs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/topSites"&gt;topSites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/tts"&gt;tts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/ttsEngine"&gt;ttsEngine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/permissions-list"&gt;unlimitedStorage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/vpnProvider"&gt;vpnProvider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/webNavigation"&gt;webNavigation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/api/webRequest"&gt;webRequest&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Why Messaging is Important
&lt;/h4&gt;

&lt;p&gt;Chrome extensions are sandboxed and can't access the DOM a page is running on. So in order to manipulate or identify things in the DOM there needs to be a messaging bridge created between the &lt;code&gt;contentScript&lt;/code&gt;, &lt;code&gt;backgroundScript&lt;/code&gt;, and &lt;code&gt;popup&lt;/code&gt;. Anything from strings to booleans can be sent over this bridge, however, I recommend serializing objects as complex objects with methods and classes will not be able to be sent over the bridge.&lt;/p&gt;

&lt;p&gt;Here's a quick example of how to create a messaging bridge between the &lt;code&gt;contentScript&lt;/code&gt;, &lt;code&gt;backgroundScript&lt;/code&gt;, and &lt;code&gt;popup&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// contentScript.js&lt;/span&gt;
&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello from the content script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;background&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// backgroundScript.js&lt;/span&gt;
&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sendResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;background&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;sendResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello content, this is from the background script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;background&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;popup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello popup, this is from the background script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// popup.js&lt;/span&gt;
&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello from the popup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;background&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;popup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're using the &lt;code&gt;chrome.runtime&lt;/code&gt; API to send and receive messages between the &lt;code&gt;contentScript&lt;/code&gt;, &lt;code&gt;backgroundScript&lt;/code&gt;, and &lt;code&gt;popup&lt;/code&gt;. The &lt;code&gt;chrome.runtime.onMessage&lt;/code&gt; method is used to listen for messages and the &lt;code&gt;chrome.runtime.sendMessage&lt;/code&gt; method is used to send messages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Covering all basis in the manifest file
&lt;/h3&gt;

&lt;p&gt;An extensions manifest file is a JSON file that contains metadata about the extension. It's used to configure the extension and to specify the extension's properties. Here's a quick example of a manifest file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"manifest_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My Extension"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is my first extension"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"storage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"activeTab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scripting"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default_popup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"popup.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default_icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"16"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"images/icon16.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"48"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"images/icon48.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"128"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"images/icon128.png"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"background"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"service_worker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"background.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"content_scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;all_urls&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"js"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"content.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"web_accessible_resources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"images/*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"options_ui"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"options.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"open_in_tab"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"icons"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"16"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"images/icon16.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"48"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"images/icon48.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"128"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"images/icon128.png"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As of the time of writing this article manifest V3 is the latest version of the manifest file. Let's do a quick rundown of the properties in the snippet above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;manifest_version&lt;/code&gt;: The version of the manifest file. As of the time of writing this article, the latest version is 3.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;: The name of the extension.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;version&lt;/code&gt;: The version of the extension.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt;: A description of the extension.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;permissions&lt;/code&gt;: An array of permissions the extension requires. For example, the &lt;code&gt;storage&lt;/code&gt; permission is required to use the &lt;code&gt;chrome.storage&lt;/code&gt; API.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;action&lt;/code&gt;: The action property is used to define the browser action. The &lt;code&gt;default_popup&lt;/code&gt; property is used to specify the HTML file that will be used as the popup. The &lt;code&gt;default_icon&lt;/code&gt; property is used to specify the icon that will be used for the extension.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;background&lt;/code&gt;: The background property is used to define the background script. The &lt;code&gt;service_worker&lt;/code&gt; property is used to specify the service worker that will be used as the background script.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;content_scripts&lt;/code&gt;: The content_scripts property is used to define the content scripts. The &lt;code&gt;matches&lt;/code&gt; property is used to specify the URLs the content script will run on. The &lt;code&gt;js&lt;/code&gt; property is used to specify the JavaScript files that will be used as the content script.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;web_accessible_resources&lt;/code&gt;: An array of resources that are accessible to the web. For example, the &lt;code&gt;images/*&lt;/code&gt; resource is accessible to the web.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;options_ui&lt;/code&gt;: The options_ui property is used to define the options page. The &lt;code&gt;page&lt;/code&gt; property is used to specify the HTML file that will be used as the options page. The &lt;code&gt;open_in_tab&lt;/code&gt; property is used to specify whether the options page will open in a tab.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;icons&lt;/code&gt;: An object that contains the icons that will be used for the extension.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Content Security Policy
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;content_security_policy&lt;/code&gt; property is used to define the content security policy for the extension. The content security policy is used to specify the rules for the resources the extension can load. For example, the &lt;code&gt;script-src 'self'; object-src 'self'&lt;/code&gt; content security policy specifies that the extension can only load scripts and objects from the extension itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"content_security_policy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"extension_pages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"script-src 'self'; object-src 'self'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"content_scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"script-src 'self'; object-src 'self'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"web_accessible_resources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"script-src 'self'; object-src 'self'"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: If you intend to use WASM in your extension, you'll need to add &lt;code&gt;wasm-eval&lt;/code&gt; or &lt;code&gt;wasm-unsafe-eval&lt;/code&gt; to the &lt;code&gt;script-src&lt;/code&gt; directive in the &lt;code&gt;content_security_policy&lt;/code&gt; property. Like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"content_security_policy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"extension_pages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"script-src 'self' 'wasm-eval'; object-src 'self'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"content_scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"script-src 'self' 'wasm-eval'; object-src 'self'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"web_accessible_resources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"script-src 'self' 'wasm-eval'; object-src 'self'"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Content scripts
&lt;/h4&gt;

&lt;p&gt;Content scripts are JavaScript files that run in the context of web pages. They can read and modify the DOM of web pages and interact with the web page's JavaScript. Content scripts are used to modify the appearance and behavior of web pages.&lt;/p&gt;

&lt;p&gt;To add a content script to your extension, you'll first need to add it to the manifest file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"content_scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;all_urls&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"js"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"content.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once it's added you can then use the &lt;code&gt;chrome.tabs.executeScript&lt;/code&gt; method to inject the content script into the web page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in-page script&lt;/span&gt;
&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// content.js&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I'm the content script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, if you plan on using WXT you won't need to do the above as WXT offers a method that can do this for you, eliminating the need for the &lt;code&gt;chrome.tabs.executeScript&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineContentScript&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;all_urls&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I'm the content script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Background scripts
&lt;/h4&gt;

&lt;p&gt;These scrips can also be referred to as service workers. You might think that they are similar to the content script with the only differing feature being that they run in the background, but you couldn't be further from the truth. Background scripts are fundamentally different in a sense that they can not be used like normal JavaScript scripts that run on the web, because they don't have access to the DOM, web page or anything related to it(like localStorage, the document and window objects).&lt;/p&gt;

&lt;p&gt;Now you might be wondering since they're so limited what can they even be used for? Well as their name implies they can be used to run background tasks such as notifications, tracking, analytics, event-handling and messaging. I hope you understand why they're also referred to as service workers now.&lt;/p&gt;

&lt;p&gt;Setting up a background script is similar to setting up a content script in normal extension workflows, however, when using WXT it can be done even easier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineBackground&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I'm the background script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Something that you'll have to keep in mind is that the callback can not be made async as background scripts are synchronous. So if you're a fine of the &lt;code&gt;async/await&lt;/code&gt; syntax you're out of luck, you'll have to use the good old &lt;code&gt;then/finally/catch&lt;/code&gt; method chain.&lt;/p&gt;

&lt;h4&gt;
  
  
  Browser actions
&lt;/h4&gt;

&lt;p&gt;Web extension browser actions are buttons that extensions add to the browser's toolbar, typically with an icon and optional popup functionality. These buttons allow users to interact with the extension directly from the browser interface. When a user clicks on a browser action button, it can trigger specific actions defined by the extension, such as opening a popup with HTML, CSS, and JavaScript content, or executing certain functions within the extension.&lt;/p&gt;

&lt;p&gt;As of the time of writing this article I haven't been able to get these to work using WXT. It might be something with my implementation or WXT doesn't support it yet, however, &lt;a href="https://chat.openai.com/share/0e0f5875-6bf3-48c5-a663-abf503820148"&gt;here's&lt;/a&gt; a ChatGPT thread explaining how you can go about trying it out yourself using a none WXT managed code base.&lt;/p&gt;

&lt;h4&gt;
  
  
  Page actions
&lt;/h4&gt;

&lt;p&gt;Page actions in Chrome extensions are specific actions that are relevant to particular pages rather than the browser as a whole. They are represented by icons added inside the browser's URL bar and can be associated with specific web pages. Page actions can be used for features that make sense for only a few pages, and they are hidden by default but can be shown for a particular tab using the &lt;code&gt;pageAction.show()&lt;/code&gt; method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using WXT for Scaffolding
&lt;/h2&gt;

&lt;p&gt;Now that we're past the basics, let's actually create a project. Run the following command to create a WXT project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bunx wxt@latest init sample-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command will prompt you to choose a framework you would like to use. I recommend SolidJS, but go with whichever you're proficient in.&lt;/p&gt;

&lt;p&gt;Once that's done your project's file structure will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── README.md
├── assets
│   └── solid.svg
├── entrypoints
│   ├── background.ts
│   ├── content.ts
│   └── popup
│       ├── App.css
│       ├── App.tsx
│       ├── index.html
│       ├── main.tsx
│       └── style.css
├── package.json
├── public
│   ├── icon
│   │   ├── 128.png
│   │   ├── 16.png
│   │   ├── 32.png
│   │   ├── 48.png
│   │   └── 96.png
│   └── wxt.svg
├── tsconfig.json
└── wxt.config.ts

6 directories, 18 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;sup&gt;I used tree to print this. If you're using &lt;a href="https://pkgx.sh"&gt;pkgx&lt;/a&gt;, just run &lt;code&gt;pkgx tree&lt;/code&gt; to print the dirctory tree&lt;/sup&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Directory structure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;assets&lt;/code&gt;: This houses your images, svgs, and any other asset formats you'll be using.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;entrypoints&lt;/code&gt;: This houses your background scripts, content scripts, and popup.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wxt.config.ts&lt;/code&gt;: This manages WXTs behavior and your manifest file settings.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;public&lt;/code&gt;, &lt;code&gt;tsconfig.json&lt;/code&gt;: Same old, same old.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Running the extension
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building the extension
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Using SolidJS for the popup
&lt;/h3&gt;

&lt;p&gt;The popup directory is the UI of your extension. It's where you'll be using SolidJS to create the UI of your extension. The &lt;code&gt;index.html&lt;/code&gt; file is the entry point of the popup, and the &lt;code&gt;main.tsx&lt;/code&gt; file is the entry point of the SolidJS app. While the extension is running and open you can modify the &lt;code&gt;App.tsx&lt;/code&gt; file and see it update in real time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSignal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;solid-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;solidLogo&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/assets/solid.svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;wxtLogo&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/wxt.svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://wxt.dev"&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;wxtLogo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"logo"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"WXT logo"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://solidjs.com"&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;solidLogo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"logo solid"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Solid logo"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;WXT + Solid&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          count is &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Edit &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;popup/App.tsx&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; and save to test HMR
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"read-the-docs"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Click on the WXT and Solid logos to learn more
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: WXT uses the &lt;code&gt;@&lt;/code&gt; symbol to refer to the root directory of your project. This is a feature of WXT and not SolidJS. You can get rid of it by changing the &lt;code&gt;baseUrl&lt;/code&gt; in your &lt;code&gt;tsconfig.json&lt;/code&gt; file and modifying the paths in your &lt;code&gt;wxt.config.ts&lt;/code&gt; file. I recommend leaving it as is, because if you're not well versed in configs you might end up breaking the project.&lt;/p&gt;

&lt;h4&gt;
  
  
  Routing
&lt;/h4&gt;

&lt;p&gt;You can add routing to your popup the exact same way you would any other SolidJS app. Here's an example of how you can do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRoutes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@solidjs/router&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRoutes&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Home&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/about&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;About&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Routes&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Home.tsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// About.tsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;About&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;About&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Managing your manifest properties with WXT
&lt;/h3&gt;

&lt;p&gt;WXT uses a &lt;code&gt;wxt.config.ts&lt;/code&gt; file to manage your manifest properties. Manifest properties can be assigned through the manifest object in the &lt;code&gt;defineConfig&lt;/code&gt; function. Here's an example of how you can do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wxt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Solid&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vite-plugin-solid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// See https://wxt.dev/api/config.html&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;vite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;esnext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Solid&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;manifest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WXT + Solid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A WXT extension with SolidJS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;popup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/icon/16.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/icon/48.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/icon/128.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Compile and build
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This builds and zips your extension into a &lt;code&gt;.zip&lt;/code&gt; file. You can then upload this file to the Chrome Web Store or drag and drop it into the &lt;code&gt;chrome://extensions&lt;/code&gt; page to install it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That's pretty much all the info you'll need on how to build and package your first extension using WXT + SolidJS. As you may have noticed this article leans heavily towards building for the Chrome Web Store. The same principles apply to building for Firefox, Edge, and Opera. The only difference is the manifest properties and the way you package your extension. I recommend giving the Chrome browser extension api doc a read (&lt;a href="https://developer.chrome.com/docs/extensions/reference"&gt;https://developer.chrome.com/docs/extensions/reference&lt;/a&gt;) to get a better understanding of how to use the Chrome extension api, and the differences between the different browsers.&lt;/p&gt;

&lt;p&gt;If you would like to learn more about how to publish and distribute your extension, let me know and I might write an article on that. If you have any questions or need help with anything, feel free to reach out to me on &lt;a href="https://twitter.com/devshogun"&gt;Twitter&lt;/a&gt;. I'm always happy to help.&lt;/p&gt;

</description>
      <category>solidjs</category>
      <category>browserextension</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>5 Developer CLI Essentials</title>
      <dc:creator>Michael Essiet</dc:creator>
      <pubDate>Tue, 02 Jan 2024 18:00:00 +0000</pubDate>
      <link>https://dev.to/devshogun/5-developer-cli-essentials-23c0</link>
      <guid>https://dev.to/devshogun/5-developer-cli-essentials-23c0</guid>
      <description>&lt;p&gt;Happy New Year everyone! I want to start this year right with an article showcasing some of the CLI tools that I couldn’t do without in 2023. With this article I’ll be adopting a new writing style, keeping things short and sweet while giving all you need to get started and productively use some of the things I will write about in 2024.&lt;/p&gt;

&lt;p&gt;Without further a do, let’s jump into the tools that I just couldn’t do without.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;a href="https://pkgx.sh"&gt;pkgx&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;If you follow me on &lt;a href="https://twitter.com/devshogun"&gt;X&lt;/a&gt;, you’ve probably seen me mention this a couple of times. pkgx is the package manager to rule them all. No, I’m not exaggerating.&lt;/p&gt;

&lt;p&gt;Pkgx allows you to run anything, anywhere and on almost any computer. Heck, one of our community members even got it to run on a powkiddy device.&lt;/p&gt;

&lt;p&gt;You can run any command that pkgx has in its registry directly without having to explicitly install it on your machine. Here’s an example of what that looks like&lt;/p&gt;



&lt;p&gt;Once you have pkgx installed, by simply prefixing any command that you want to run with &lt;code&gt;pkgx&lt;/code&gt;, it will search its registry for the command and install it if it finds it. Then it will run the command for you immediately after.&lt;/p&gt;

&lt;p&gt;Pkgx also has a dev environment tool built in. Using the &lt;code&gt;dev&lt;/code&gt; command pkgx creates a dev environment in that directory and automatically installs any packages and tools needed for said environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;a href="https://git-scm.com/"&gt;git&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As a developer, you must have some sort of version control tool like git. Git is a version control system that allows you to track changes in your code and easily revert to previous versions if needed. It's an essential tool for managing and organizing your codebase and workflow, and it integrates seamlessly with popular code hosting platforms like GitHub and GitLab.&lt;/p&gt;

&lt;p&gt;Git makes things like debugging and collaboration easier since it allows you to revert to previous versions of things using commit history and merge and compare code from collaborators.&lt;/p&gt;

&lt;p&gt;I can’t count how many times I’ve either created a separate branch to messily debug an issue clean it up and merge it into the main branch or how many times I’ve rollback commits because I broke something in some way or another.&lt;/p&gt;

&lt;p&gt;Here’s a quick example of how to commit, branch, and merge code using git.&lt;/p&gt;



&lt;h2&gt;
  
  
  3. &lt;a href="https://github.com/jesseduffield/lazygit"&gt;lazygit&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Lazygit is a terminal UI that helps you visualize your git commit history and changes. With Lazygit you’re able to better understand the changes you’ve made to your project without having to keep running &lt;code&gt;git status&lt;/code&gt; and &lt;code&gt;git diff&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QZ7Uh227--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://yvellwnvywwynkrgnsvr.supabase.co/storage/v1/object/public/blog/5-developer-cli-essentials/Screenshot%25202023-12-26%2520at%252018.06.36.png%3Ft%3D2024-01-02T16%253A46%253A40.518Z" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QZ7Uh227--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://yvellwnvywwynkrgnsvr.supabase.co/storage/v1/object/public/blog/5-developer-cli-essentials/Screenshot%25202023-12-26%2520at%252018.06.36.png%3Ft%3D2024-01-02T16%253A46%253A40.518Z" alt="Image of the lazygit terminal UI" width="800" height="818"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s an amazing tool for whenever you’ve made too many changes to a project or just have too many git operations going on. Now, I can’t say that I use it weekly but I can say that it has saved me some time and stress when working in large codebases and whenever I want to unscrew myself 😅.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;a href="https://github.com/sharkdp/bat"&gt;bat&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You can think of bat as a cat clone except with syntax highlighting. Bat has things like syntax highlighting, git diffs and more. I often use bat to peek into files while I code or try to understand a codebase that I was just introduced to.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VHyfJsUu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://yvellwnvywwynkrgnsvr.supabase.co/storage/v1/object/public/blog/5-developer-cli-essentials/Screenshot%25202024-01-02%2520at%252017.06.45.png%3Ft%3D2024-01-02T16%253A47%253A41.322Z" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VHyfJsUu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://yvellwnvywwynkrgnsvr.supabase.co/storage/v1/object/public/blog/5-developer-cli-essentials/Screenshot%25202024-01-02%2520at%252017.06.45.png%3Ft%3D2024-01-02T16%253A47%253A41.322Z" alt="Image of the bat CLI tool in action" width="800" height="682"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see it offers syntax highlighting for the &lt;code&gt;package.yml&lt;/code&gt; file being viewed. I highly recommend it over &lt;code&gt;cat&lt;/code&gt; especially if you’re a dev.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;a href="https://httpie.io/cli"&gt;httpie&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Httpie is an API test client in your terminal that offers JSON highlighting, header parsing, body parsing, session parsing, and more. It’s lightweight, open-source, and intuitive, everything that devs love. Here’s an example of it querying the Coingecko API &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9atZ334h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://yvellwnvywwynkrgnsvr.supabase.co/storage/v1/object/public/blog/5-developer-cli-essentials/Screenshot%25202024-01-02%2520at%252017.20.14.png%3Ft%3D2024-01-02T16%253A48%253A28.992Z" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9atZ334h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://yvellwnvywwynkrgnsvr.supabase.co/storage/v1/object/public/blog/5-developer-cli-essentials/Screenshot%25202024-01-02%2520at%252017.20.14.png%3Ft%3D2024-01-02T16%253A48%253A28.992Z" alt="Image of the httpie CLI tool in action" width="800" height="686"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, these CLI tools have been instrumental in my productivity as a developer. From the convenience of pkgx, which allows me to run any command without explicitly installing it, to the power of git for version control and collaboration. Lazygit helps me visualize my git history, while bat provides syntax highlighting for file viewing. Lastly, httpie simplifies API testing in the terminal. I highly recommend incorporating these tools into your workflow to enhance your development experience.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>cli</category>
      <category>devtools</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Creating a basic browser extension using SolidJS</title>
      <dc:creator>Michael Essiet</dc:creator>
      <pubDate>Sat, 05 Aug 2023 22:27:23 +0000</pubDate>
      <link>https://dev.to/devshogun/creating-a-basic-browser-extension-using-solidjs-5e3e</link>
      <guid>https://dev.to/devshogun/creating-a-basic-browser-extension-using-solidjs-5e3e</guid>
      <description>&lt;p&gt;I always thought that browser extensions were a complicated technology that required some kind of special programming language or compilation method. Turns out they're just web apps.&lt;/p&gt;

&lt;p&gt;In this article we'll be building a very simple browser extension for generating QR codes. The technologies we'll be using in this article are listed below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en"&gt;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.solidjs.com/"&gt;SolidJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.google.com/chrome"&gt;A Chromium based browser&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Make sure that you have these installed and ready to go. In order to create a SolidJS project and install the required dependencies you can run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx degit solidjs/templates/ts-tailwindcss qrcode-extension
&lt;span class="nb"&gt;cd &lt;/span&gt;qrcode-extension &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Now that you have everything that you need installed open up the SolidJS project in your code editor. Your project should look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MciVgTPO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://yvellwnvywwynkrgnsvr.supabase.co/storage/v1/object/public/blog/solid-ts-template-structure" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MciVgTPO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://yvellwnvywwynkrgnsvr.supabase.co/storage/v1/object/public/blog/solid-ts-template-structure" alt="An example of how the basic SolidJS project structure looks" width="602" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Head over to the &lt;code&gt;App.tsx&lt;/code&gt; file inside the &lt;code&gt;src/&lt;/code&gt; where you'll see a basic app component.&lt;/p&gt;

&lt;p&gt;You can run the app using the &lt;code&gt;npm run dev -- --open&lt;/code&gt; terminal command. Feel free to make edits to the component and see your changes reflect in realtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the extension
&lt;/h2&gt;

&lt;p&gt;The first and only thing that you'll need to install is the qrcode npm package, run this command to do so &lt;code&gt;npm install qrcode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; When using Typescript you'll run into an error about the &lt;code&gt;qrcode&lt;/code&gt; package type definitions. In order to fix that error you will need to run &lt;code&gt;npm install -D @types/qrcode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Head over to the &lt;code&gt;App.tsx&lt;/code&gt; file and modify the code like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSignal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;solid-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;QRcode&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;qrcode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;qrDataUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setQRDataUrl&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;canvasRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTMLCanvasElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;QRcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toCanvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canvasRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setQRDataUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;QRcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDataURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex h-[400px] min-w-[300px] flex-col items-center justify-center"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-3xl font-bold"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;QR Code Generator&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
        &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"rounded p-2 outline outline-black"&lt;/span&gt;
        &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Input text to encode..."&lt;/span&gt;
        &lt;span class="na"&gt;onkeyup&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setter&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;canvas&lt;/span&gt;
        &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"m-4 h-0 w-0 rounded outline outline-black"&lt;/span&gt;
        &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;canvasRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;qrDataUrl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;download&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"qrcode.png"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Download
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code snippet we're importing the &lt;code&gt;createSignal&lt;/code&gt; primitive from SolidJS, as well as the &lt;code&gt;QRcode&lt;/code&gt; package. We're also creating an input field that takes in the text that you would like to encode then calls a function called &lt;code&gt;setter&lt;/code&gt;, which takes that text and converts it to a QR code using the &lt;code&gt;QRcode&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;A download button is also provided which uses the generated data URL we set in the &lt;code&gt;qrDataUrl&lt;/code&gt; signal.&lt;/p&gt;

&lt;p&gt;That's all the code we need. Next just build the project by running the &lt;code&gt;npm run build&lt;/code&gt; command. Once that's done, a &lt;code&gt;dist&lt;/code&gt; folder will be created in the current working directory. &lt;code&gt;cd&lt;/code&gt; into that folder and create a &lt;code&gt;manifest.json&lt;/code&gt; file with this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"QR Code Generator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A generic QR code generator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"activeTab"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"browser_action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default_popup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.html"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"manifest_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing the extension
&lt;/h2&gt;

&lt;p&gt;Open up a Chromium based browser and head over to this url &lt;code&gt;BROWSER://extensions&lt;/code&gt;, "BROWSER" being the name of your browser. e.g &lt;code&gt;chrome://extensions&lt;/code&gt;, &lt;code&gt;arc://extensions&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once there you should see a button at the top right corner titled "Load unpacked". Click on that button and navigate to and select the &lt;code&gt;dist&lt;/code&gt; folder that was created earlier. That's it! The extension should appear and be loaded into your browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v_9N7FnT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://yvellwnvywwynkrgnsvr.supabase.co/storage/v1/object/public/blog/chrome-extension-screenshot" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v_9N7FnT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://yvellwnvywwynkrgnsvr.supabase.co/storage/v1/object/public/blog/chrome-extension-screenshot" alt="The loaded browser extension in the chrome extensions screen" width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check your list of extensions and the QR Code Generator extension should be among them.&lt;/p&gt;

&lt;p&gt;That's it! Your extension should be ready to go. If you would like to learn how to publish your extension to the Chrome web store I recommend following &lt;a href="https://developer.chrome.com/docs/webstore/publish/"&gt;this guide&lt;/a&gt; from the Chrome Developers documentation.&lt;/p&gt;

&lt;p&gt;If you enjoyed this article please don't forget to share, check out my &lt;a href="https://dev.to/devshogun"&gt;other work&lt;/a&gt; and &lt;a href="https://twitter.com/devshogun"&gt;follow me&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>solidjs</category>
      <category>typescript</category>
      <category>extensions</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to build an iOS Expo App without using EAS Build</title>
      <dc:creator>Michael Essiet</dc:creator>
      <pubDate>Sun, 19 Mar 2023 14:21:56 +0000</pubDate>
      <link>https://dev.to/devshogun/how-to-build-an-ios-expo-app-without-using-eas-build-5d77</link>
      <guid>https://dev.to/devshogun/how-to-build-an-ios-expo-app-without-using-eas-build-5d77</guid>
      <description>&lt;p&gt;As a software developer with a fair amount of experience with Expo and React Native, I know how annoying it can get to just simply build an app from an Expo project.&lt;/p&gt;

&lt;p&gt;Just the other day I found myself blankly staring at my screen wondering why my local Expo builds were failing, just to find out a few hours later that there is nothing that I can do about it because it was not my fault but a weird glitch with React Native and Expo. Thankfully I found a way to get the app to build and get it published. This is an article about how I went about doing that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don’t use the Expo commands
&lt;/h3&gt;

&lt;p&gt;After several trial and errors I found out that there is no need to use the Expo/EAS build commands because you can just archive your app directly through Xcode. Yes, it works. To my surprise all the build phases are already setup in Xcode, so all you need to do is run Archive and your project will be completely built and archived for any platform you have selected, and yes the Javascript React Native code will be compiled.&lt;/p&gt;

&lt;p&gt;Another reason why I recommend against using the Expo/EAS commands is that it asks for a file that is automatically present in Xcode if you’re logged into a company profile. I believe that file is some sort of certificate/signing file. Having all devs working on the project to manually provide this file can add a level of unnecessary complexity.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to archive your project
&lt;/h3&gt;

&lt;p&gt;Before talking about how you can go about archiving your project first let’s talk about what archiving even is in iOS app development.&lt;/p&gt;

&lt;p&gt;Simply put archiving is the overall packaging of your application. This package includes .ipa files that are similar to .apk files in android. The wording can be a bit deceiving with calling it Archive and having Build directly under, but trust me if you’re looking to get a distributable file or start the distribution process via Xcode, Archive is what you’re looking for.&lt;/p&gt;

&lt;p&gt;Now let’s get started on how we can go about archiving our app.&lt;/p&gt;

&lt;p&gt;Firstly you’ll need to run npx expo prebuild if you have an Expo managed project.&lt;/p&gt;

&lt;p&gt;After running the prebuild command you’ll need to run npx pod-install or cd into the ios directory and run pod install whichever you choose is totally up to your preference.&lt;/p&gt;

&lt;p&gt;Once that’s done you’ll need to open the ios directory using Xcode. You can do that via right clicking in VSCode and selecting “open in xcode”. If you don’t make use of VSCode you can open the ios directory in finder from your terminal using the open . command, once that’s open you should see a file with the .xcworkspace file extension, double click it and it should open in Xcode.&lt;/p&gt;

&lt;p&gt;Now that Xcode is open we’ll need to verify our Signing and Capabilities settings. For those not well versed in certificate management with MacOS and Xcode I suggest ticking the “Automatically manage signing” setting to leave signing to Xcode and the certificates associated with the logged in Apple developer account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F2vdogSy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AQgt4vw5QuHXgBkTL93JEIA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F2vdogSy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AQgt4vw5QuHXgBkTL93JEIA.png" alt="View of the signing and capabilities settings" width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we’re done with all the settings it’s time to Archive. To start archiving your project go to the “Product” drop down in the menu bar and select “Archive”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FA5BxR31--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AKLO37wHdpM4zr9KsjtWjYw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FA5BxR31--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AKLO37wHdpM4zr9KsjtWjYw.png" alt="View of what the Product dropdown in XCode looks like" width="800" height="734"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it, your project will start archiving.&lt;/p&gt;

&lt;p&gt;Note that you will see a lot of warnings but that is normal as most of them are just null safety checks.&lt;/p&gt;

&lt;p&gt;Once archiving is done a screen will popup where you can choose to export your app or just distribute it to App Store directly from Xcode.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In conclusion this method saved me a lot of time and painstaking hours of debugging. I highly recommend this over building locally using the EAS commands.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devshogun.medium.com/flutter-vs-react-native-a-cross-platform-framework-vs-react-ported-for-mobile-5f1f256f7306"&gt;Flutter vs. React Native: A Cross-Platform Framework vs. React Ported For Mobile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devshogun.medium.com/migrating-a-react-project-to-react-native-best-practices-and-things-to-keep-in-mind-70caccea516a"&gt;Migrating a React project to React Native — Best Practices and Things to Keep in Mind&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>xcode</category>
      <category>mobileappdevelopment</category>
      <category>expo</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Migrating a React project to React Native — Best Practices and Things to Keep in Mind</title>
      <dc:creator>Michael Essiet</dc:creator>
      <pubDate>Sun, 19 Feb 2023 09:17:30 +0000</pubDate>
      <link>https://dev.to/devshogun/migrating-a-react-project-to-react-native-best-practices-and-things-to-keep-in-mind-gd0</link>
      <guid>https://dev.to/devshogun/migrating-a-react-project-to-react-native-best-practices-and-things-to-keep-in-mind-gd0</guid>
      <description>&lt;h3&gt;
  
  
  Migrating a React project to React Native — Best Practices and Things to Keep in Mind
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NiqUndip--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AwbtO-jGDOeJgZqxLflqKCg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NiqUndip--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AwbtO-jGDOeJgZqxLflqKCg.png" alt="Migrating React to React Native" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;React Native is a popular open source framework created by Facebook that allows developers to create cross-platform mobile applications with JavaScript. If you have an existing React project and are looking to migrate it to React Native, this blog post will provide best practices and tips on how to streamline your workflow.&lt;/p&gt;

&lt;p&gt;This article will contain information on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up your project environment&lt;/li&gt;
&lt;li&gt;Structuring your React project for migration&lt;/li&gt;
&lt;li&gt;Polyfilling Node functions in React Native&lt;/li&gt;
&lt;li&gt;Managing components&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Set up your environment
&lt;/h3&gt;

&lt;p&gt;The first step when migrating to React Native is to set up your environment. This includes installing the React Native command line interface (CLI), configuring your mobile device or simulator, and setting up any third-party libraries or plugins. Setting up your environment properly will help ensure a smoother transition to React Native. This is especially important when you are trying to migrate a cryptocurrency related project from react to react native as react native does not support some of the crypto classes, functions and plugins out of the box.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structure your project
&lt;/h3&gt;

&lt;p&gt;When migrating to React Native, it is important to structure your project in a way that is easy to manage. This means organizing your project into separate folders for components, styles, images, hooks, and any other necessary files. Keeping your project organized will help you to find files quickly and reduce the amount of time spent looking for them.&lt;/p&gt;

&lt;p&gt;An easy way to ensure that your project is properly structured for migration is to ensure that a lot of your non-jsx functions, classes and files are modular and semi-framework agnostic and can be ripped out and placed into any project whether it be react or not. In the case of react native I would advise that you create custom hooks and service classes on the react side to make things easier for you to move and manage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Polyfilling Node functions and classes
&lt;/h3&gt;

&lt;p&gt;In some cases, React Native does not have the same Node.js functions and classes that are available in React. To make up for this, developers can use polyfills to make the same functions and classes available in React Native. Polyfills are JavaScript functions that are designed to mimic the behavior of the Node.js functions and classes, allowing developers to use the same code when migrating to React Native. This can help streamline the process of migrating a project, since developers don’t have to rewrite code to account for the differences between React and React Native. However, not all Node.js functions and classes can be polyfilled, so it is important to research which functions need to be replaced during the migration process. These polyfills are often times called shims. For more information on polyfilling the right functions and classes check out this &lt;a href="https://github.com/tradle/rn-nodeify"&gt;github repo&lt;/a&gt; called rn-nodeify that helps in adding polyfills for most Node functions to your react native project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Manage components
&lt;/h3&gt;

&lt;p&gt;When migrating to React Native, it is important to keep track of all your components and how they interact with each other. This can be done by creating a component library that is organized according to the type of component. This will make it easier to find components when you need to make changes or add new features. Even though react components cannot be transferred to react native it is still advisable to manage and keep track of how your components interact with one another so that implementation in react native won’t feel like you’re reinventing the wheel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Migrating a React project to React Native can be a time-consuming process, but with the right tools and techniques, it can be made easier. By setting up your environment, structuring your project, and managing your components, you can streamline your workflow and make your transition to React Native smoother.&lt;/p&gt;

&lt;p&gt;Thanks for reading, that’s all for now. If you would like a much more in-depth guide on migrating a React application to React Native I would be happy to publish a more in-depth guide or post a YouTube video based on demand.&lt;/p&gt;

&lt;p&gt;Check out some of my other work&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/devshogun/how-to-build-an-ios-expo-app-without-using-eas-build-5d77"&gt;What I’ve Learned Working On Open Source And Why I Think Everyone Else Should Too&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mobileappdevelopment</category>
      <category>react</category>
      <category>reactnative</category>
      <category>projectmanagement</category>
    </item>
    <item>
      <title>What I’ve Learned Working On Open Source And Why I Think Everyone Else Should Too</title>
      <dc:creator>Michael Essiet</dc:creator>
      <pubDate>Sat, 10 Dec 2022 19:12:13 +0000</pubDate>
      <link>https://dev.to/devshogun/what-ive-learned-working-on-open-source-and-why-i-think-everyone-else-should-too-2636</link>
      <guid>https://dev.to/devshogun/what-ive-learned-working-on-open-source-and-why-i-think-everyone-else-should-too-2636</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eyqST1fI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Ai7RJoSt2RqzBjShOaCKvTQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eyqST1fI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Ai7RJoSt2RqzBjShOaCKvTQ.jpeg" alt="" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over the past 3 months I’ve taken a break from writing an article a week to contribute to open source. In this article I will be talking about what I’ve learnt, experienced and worked on, and how that has changed the way I interact with the community and code.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I’ve worked on
&lt;/h3&gt;

&lt;p&gt;Over these 3 months I’ve found myself working on everything from web3 SDKs to Solid.js documentation. I initially started my open source journey last year with VelocityX a Flutter UI framework. I started out by contributing to their documentation little by little and correcting any mistakes that there might be.&lt;/p&gt;

&lt;p&gt;Over the past few months however, I’ve been working in the Solid.js community which I’ve been very passionate about for some time now. I’ve been writing documentation for the new Solid.js docs and I’m really excited for the community to see what we’ve been building when it’s ready.&lt;/p&gt;

&lt;p&gt;I started working on the Supabase Auth UI kit recently, through expanding their Auth UI kit to support Solid.js. I also have plans on writing documentation for them as well in regards to Solid.js and how Solid.js developers can get started with Supabase.&lt;/p&gt;

&lt;p&gt;From time to time I also dabble in web3 SDKs here and there. My most recent work was with the &lt;a href="https://www.npmjs.com/package/quickswap-sdk-lite"&gt;quickswap-sdk-lite&lt;/a&gt; package, this is mostly a fork of the &lt;a href="https://github.com/Sushi-integration/simple-sushiswap-sdk"&gt;simple-sushiswap-sdk&lt;/a&gt; package built by &lt;a href="https://twitter.com/devjoshstevens"&gt;Josh Stevens&lt;/a&gt;, just with a few key things changed, such as the chainId, abi.json files and a little more. I also planned on expanding the Orcaswap typescript sdk but I haven’t found the time to yet.&lt;/p&gt;

&lt;p&gt;I’ve also released a few packages on NPM and &lt;a href="http://pub.dev"&gt;pub.dev&lt;/a&gt; but those solve very very specific problems so they won’t be of much use to many devs, but feel free to take a look at either of my profiles.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I’ve learnt
&lt;/h3&gt;

&lt;p&gt;As a software developer with a couple years of experience, finding a job hasn’t been easy. After applying for hundreds of roles and not even making it to the interview stage of most of them I had decided that I will carve my own path and work on open source in the meantime or even full-time, whether that be writing documentation, building software or just helping out community members.&lt;/p&gt;

&lt;p&gt;I decided to start writing documentation for the Solid.js community. I found this as a way to help beginner and experienced developers get started with Solid.js. Another community I started contributing to is the Supabase community, as I am helping them expand their Auth UI library and plan on writing documentation which pertains to Solid.js.&lt;/p&gt;

&lt;p&gt;While working in these communities over the past months I’ve realized that software development shouldn’t be solely based around making money, building cool stuff all the time, and creating SAASs or startups. It should also be about community building, software management and documentation, and knowledge sharing. After all, none of us as software developers would be where we are today if someone decided not to share their knowledge and just kept on building new things without explaining how he or she did it. This is one thing that a majority of software developers are missing, the ability to teach, write, and convey ideas at different levels of understanding.&lt;/p&gt;

&lt;p&gt;Nobody is an island. As software developers we need to learn how to share our knowledge before moving forward and leaving everyone else behind.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Experience Gained / Conclusion
&lt;/h3&gt;

&lt;p&gt;In summary I’ve really gained a lot while working on open source. From developing web3 SDKs to writing documentation for Solid.js, open source is something that I have come to fall in love with. In just the few months that I’ve been doing this I’ve had the opportunity to connect with so many cool people, one of which being Ryan Carniato.&lt;/p&gt;

&lt;p&gt;As a developer I highly recommend getting involved in open source at least once in your career, and when I say open source I mean contribute to a well known open source library, package, SDK or whatever it might be, I guarantee you that you’ll learn a lot from the experience.&lt;/p&gt;

&lt;p&gt;This was just a quick update article to let you guys know what I’ve been doing over the past month and what I will be doing for the time being. If you would like to reach out don’t be afraid to DM me on Twitter or if you’ve already left twitter then feel free to add me on Discord. Bye for now 👋.&lt;/p&gt;

</description>
      <category>web3development</category>
      <category>web3</category>
      <category>webdev</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>What I’ve Learnt While Working on My Second Flutter App: Numb</title>
      <dc:creator>Michael Essiet</dc:creator>
      <pubDate>Sat, 24 Sep 2022 17:02:21 +0000</pubDate>
      <link>https://dev.to/devshogun/what-ive-learnt-while-working-on-my-second-flutter-app-numb-g2i</link>
      <guid>https://dev.to/devshogun/what-ive-learnt-while-working-on-my-second-flutter-app-numb-g2i</guid>
      <description>&lt;h4&gt;
  
  
  The Skills and Experience I Gained While Working On My Second App
&lt;/h4&gt;

&lt;p&gt;Hi, it’s Michael. Over the past couple weeks starting from the beginning of September and today being the 23rd of September, I’ve been working on an app called Numb. You could say that this app is a sort of Numi clone for mobile. For those of you who don’t know what Numi is, it’s a calculator app on MacOS. You might be saying to yourself “Ok… what’s so special about a calculator app?” well Numi is more than just a normal calculator app. It allows you to do conversion, assign variables and many other things. Here’s a quick photo of what it looks like&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HVoJcgL7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AbEYfwBVHRoBDGXJjxLqXDA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HVoJcgL7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AbEYfwBVHRoBDGXJjxLqXDA.png" alt="" width="800" height="649"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks pretty cool huh? I found out about this from a fellow developer named &lt;a href="https://twitter.com/inkdrop_app"&gt;Takuya Matsuyama&lt;/a&gt;, for some of you that name might ring a bell.&lt;/p&gt;

&lt;p&gt;Numb is going to be a mobile version of this, developing a calculator in this way will be taking the mundane beginner developer project of the calculator and turn it into a broader spanning project that challenges both beginner to experienced developers.&lt;/p&gt;

&lt;h4&gt;
  
  
  TL;DR
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;I chose to make &lt;strong&gt;Numb&lt;/strong&gt; in order to &lt;strong&gt;challenge&lt;/strong&gt; myself and &lt;strong&gt;develop&lt;/strong&gt; my &lt;strong&gt;skills&lt;/strong&gt;  &lt;strong&gt;in mobile&lt;/strong&gt;  &lt;strong&gt;app development&lt;/strong&gt; , especially since I’m able to develop for iOS and Android now.&lt;/li&gt;
&lt;li&gt;I chose &lt;strong&gt;Flutter&lt;/strong&gt; to build this since it makes development &lt;strong&gt;quicker&lt;/strong&gt; , &lt;strong&gt;easier&lt;/strong&gt; and is more &lt;strong&gt;performant&lt;/strong&gt; than other cross platform frameworks.&lt;/li&gt;
&lt;li&gt;I gained a better understanding of &lt;strong&gt;Regex&lt;/strong&gt; , it’s &lt;strong&gt;use cases&lt;/strong&gt; and how &lt;strong&gt;important&lt;/strong&gt; it is in a lot of software we take for granted&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Numb&lt;/strong&gt; will be &lt;strong&gt;open-source&lt;/strong&gt; until I come to a conclusion on &lt;strong&gt;whether to monetize&lt;/strong&gt; (subscription model), &lt;strong&gt;sell&lt;/strong&gt; or &lt;strong&gt;make it free&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why Make A Calculator App Of All Things?
&lt;/h3&gt;

&lt;p&gt;I chose to make Numb because I saw it as a way to challenge my skills, experience and perception on some concepts.&lt;/p&gt;

&lt;p&gt;Earlier in my developer journey I skipped the basic calculator app that a lot of us developers make as our first, second or third project. And now it’s coming back to bite me in the ass 😂.&lt;/p&gt;

&lt;p&gt;One afternoon while thinking about a project that would look good in my resume I started thinking about apps I use everyday or at least once every 2 days, and it came to me that I’ve been using Numi quite often lately. So I did some digging and I realized that there was no app like this on mobile, I was only able to find one similar in concept but nothing else really. It wasn’t all that different from a basic calculator. That is when I decided to make one that I can carry around in my pocket.&lt;/p&gt;

&lt;p&gt;I saw it as an opportunity to build not just for myself but for a lot of people out there who are looking for a quick calculator app without all the headaches of having to tilt and look for operands and hope that the syntax is right.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I Chose Flutter Over React Native
&lt;/h3&gt;

&lt;p&gt;Over the past 2 years I’ve been dabbling in Flutter and React Native off and on. With my first app(&lt;a href="https://play.google.com/store/apps/details?id=com.essiet.twitwall"&gt;Twitwall&lt;/a&gt;) being released in February 2021, I gained experience from a plethora of challenges and situations that I needed to figure out myself. My first app &lt;a href="https://play.google.com/store/apps/details?id=com.essiet.twitwall"&gt;Twitwall&lt;/a&gt; was built using Flutter, I started developing it in December of 2020 after coming across Flutter for the first time. This would serve to be the driving factor that made me switch from React Native to Flutter.&lt;/p&gt;

&lt;p&gt;While using React Native for the past few years I noticed that the community never seemed to be in consensus for anything. When googling for quick guides on how to do something or on how to implement a particular library/feature, the things I came across were either outdated, completely wrong or meant for a specific version of Expo/React Native. For instance, I remember looking for a quick way to implement a dismissible list item in react native since it was removed from React Native in a previous update. Luckily I came across a lot of guides, tutorials and articles on how to do so but they all went about it in a roundabout way — I mentioned this in one of my &lt;a href="https://devshogun.medium.com/flutter-vs-react-native-a-cross-platform-framework-vs-react-ported-for-mobile-5f1f256f7306"&gt;previous articles&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I initially started Numb with React Native, I had reached the point of developing the calculation and conversion engine. However, something at the back of my head said that I should develop the frontend a bit first, so I did and it didn’t go as planned. I had to make use of a lot of libraries that interact with the storage, databases and allow theming respectively. And these are the packages I chose: &lt;a href="https://github.com/mrousavy/react-native-mmkv"&gt;MMKV&lt;/a&gt; for storage; &lt;a href="https://www.npmjs.com/package/react-native-sqlite-storage"&gt;React Native SQLite Storage&lt;/a&gt; for the database; &lt;a href="https://docs.nativebase.io/?utm_source=HomePage&amp;amp;utm_medium=Hero_Fold&amp;amp;utm_campaign=NativeBase_3"&gt;NativeBase&lt;/a&gt; for theming.&lt;/p&gt;

&lt;p&gt;Installing these alone was a pain especially the database 🤦‍♂️, I had to install third-party libraries just to get it working. After all the installing and time wasted I still chose to stick with React Native, the last straw came after I had implemented some of the designs I had for the UI and they just didn’t look right at all — NativeBase was anything but Native looking, especially with their bottom modal sheet.&lt;/p&gt;

&lt;p&gt;That’s when I decided that I’ll go with Flutter in the long run. With the performance gains, native feel and widget catalog I soon realized that I made the right choice. Installing the database(&lt;a href="https://pub.dev/packages/sqflite"&gt;SQFlite&lt;/a&gt;) and the storage package(&lt;a href="https://pub.dev/packages/get_storage"&gt;Get_Storage&lt;/a&gt;) literally took me less than 2 mins. You might be wondering “What about a theming library?” well with Flutter and in fact Dart you can make use of the ChangeNotifier class and implement theming yourself fairly easily. I wrote an article on this as well recently:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.devgenius.io/quick-and-simple-way-to-add-theming-to-any-flutter-app-826c16a53e19"&gt;Quick and Simple Way To Add Theming To Any Flutter App&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With all of that sorted I decided to deal with the engines before moving to the frontend aspect. Now I admit implementing the Regex, logic and structures was quite difficult especially since I took such a long break from Dart as a whole but I got rid of that ring rust fairly quickly roughly within a week. After running several tests on the engine I was shocked at how fast it was. From decomposing, filtering, compiling and calculating, the results were instant.&lt;/p&gt;

&lt;p&gt;Moving on to the frontend implementing the designs I had come up with were fairly easy, no need for any external libraries when it came to the frontend.&lt;/p&gt;

&lt;p&gt;All in all I chose Flutter because it was faster, easier and has little overhead in terms of widgets.&lt;/p&gt;

&lt;h3&gt;
  
  
  How My Perspective On Regex Changed
&lt;/h3&gt;

&lt;p&gt;Earlier in my developer journey I saw regex as a tool that frontend devs will hardly ever use on the job, boy was I wrong 😂.&lt;/p&gt;

&lt;p&gt;Over the past few weeks just working on this project alone, I’ve found myself on &lt;a href="https://leetcode.com/problemset/algorithms/"&gt;leetcode&lt;/a&gt; more times than not. In order to make sure that I’m implementing properly optimized algorithms for the engine I practiced a few &lt;a href="https://leetcode.com/problemset/algorithms/"&gt;leetcode&lt;/a&gt; algorithmic questions here and there, about 2 a day. But, I find myself using a more declarative approach while programming, I try not to reinvent the wheel unless absolutely necessary. However, in this project while making the engines, I had to do a lot of imperative programming especially since I had to deal with a lot of edge cases.&lt;/p&gt;

&lt;p&gt;Regex is the backbone of the engines, you might think that it is some trained AI model that works with word and number recognition, but nope, it’s just good old regex. Arguably regex is one of the most powerful tools backend developers have at their disposal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TSUEhQND--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AEfVNq9Iby7RLBJyWmtR5Zg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TSUEhQND--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AEfVNq9Iby7RLBJyWmtR5Zg.png" alt="" width="800" height="534"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A look at the basic parsing algorithm&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Regex saved me a lot of time while working on the engines, especially since I don’t have to go over every character in the input.&lt;/p&gt;

&lt;h3&gt;
  
  
  To Open-Source, To Sell or To Monetize? That Is The Question
&lt;/h3&gt;

&lt;p&gt;As a developer still striving to get into the market and get a decent job, I don’t think that I’m in a position where I can make something that has taken so much of my time open-source and free in the long run. I’ve been deliberating over this issue for the past few days now, as I am an advocate for open-source software.&lt;/p&gt;

&lt;p&gt;I have considered going with Numi’s monetization model and limiting the free version of the app to only having half the functionality and no cloud synchronization.&lt;/p&gt;

&lt;p&gt;I have also considered selling this app to any company or individual willing to buy it for a good enough price as it is something that can be easily built upon to have high utility.&lt;/p&gt;

&lt;p&gt;At the end of the day money keeps the lights on, and food on the table, not advocacy or how much you contribute to the community.&lt;/p&gt;

&lt;p&gt;However, I later came to a decision to leave it open-source until I am either able to find a buyer or implement the monetization model.&lt;/p&gt;

&lt;p&gt;If you are interested in buying the app, supporting its development or helping out with marketing in order for it to be a success, you can reach out to me on &lt;a href="https://twitter.com/devshogun"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.reddit.com/user/Shogun-2077"&gt;Reddit&lt;/a&gt; or email me on my public email (&lt;a href="mailto:emsaa2002@gmail.com"&gt;emsaa2002@gmail.com&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick Look At The Screens So Far
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hZVqFgFa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/828/1%2Av_vmxNG8WtGlpoZarAWxPw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hZVqFgFa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/828/1%2Av_vmxNG8WtGlpoZarAWxPw.jpeg" alt="" width="800" height="1731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6cLDc7AO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/828/1%2AtBRpDWS3hUIvRjpxIUUiqg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6cLDc7AO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/828/1%2AtBRpDWS3hUIvRjpxIUUiqg.jpeg" alt="" width="800" height="1731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--98JPtbD8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/390/1%2Adspy3N7FJPOF59ltdsXP7Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--98JPtbD8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/390/1%2Adspy3N7FJPOF59ltdsXP7Q.png" alt="" width="390" height="844"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;From left to right: main screen, theming and nav modal, and help/instructions screen&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this article and I hoped that it helped you in at least one way. For the next few weeks I will not be releasing any articles since I will be focusing on helping out with the new Solidjs documentation and trying to make it into the fellows program, but I will be coming back towards the end of October with an update.&lt;/p&gt;

&lt;p&gt;I hope you had a great time reading this article and I hope you have an even greater day, bye for now.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Follow me online for more frequent updates&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/devshogun"&gt;Michael.E (@devshogun) / Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Reddit: &lt;a href="https://www.reddit.com/user/Shogun-2077"&gt;Devshogun (u/Shogun-2077) — Reddit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Medium: &lt;a href="https://devshogun.medium.com/"&gt;Michael Essiet — Medium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dev.to: &lt;a href="https://dev.to/devshogun"&gt;Michael Essiet — DEV Community 👩‍💻👨‍💻&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>beginnercoding</category>
      <category>flutter</category>
      <category>reactnative</category>
      <category>appdevelopment</category>
    </item>
    <item>
      <title>Quick and Simple Way To Add Theming To Any Flutter App</title>
      <dc:creator>Michael Essiet</dc:creator>
      <pubDate>Sat, 17 Sep 2022 17:02:11 +0000</pubDate>
      <link>https://dev.to/devshogun/quick-and-simple-way-to-add-theming-to-any-flutter-app-m45</link>
      <guid>https://dev.to/devshogun/quick-and-simple-way-to-add-theming-to-any-flutter-app-m45</guid>
      <description>&lt;h4&gt;
  
  
  Theming Made Easy Using The ChangeNotifier Class
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UIywD76Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AyFHi6RgnvG6-5bhoEvyvyA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UIywD76Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AyFHi6RgnvG6-5bhoEvyvyA.png" alt="" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a Frontend, Fullstack or even Backend developer I’m sure you must have googled “how to theme…” at least once. With app theming being so common nowadays but still being a bit complicated on most frameworks it’s not a surprise that “how to theme a * app” is commonly searched on google by Frontend to Backend developers alike.&lt;/p&gt;

&lt;p&gt;In this article I will be sharing how I go about theming my Flutter apps, whether that be a side project or otherwise, using the ChangeNotifier class.&lt;/p&gt;

&lt;p&gt;Prerequisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic Flutter and Dart knowledge&lt;/li&gt;
&lt;li&gt;Flutter SDK fully installed on your development machine&lt;/li&gt;
&lt;li&gt;A device or emulator to test your app&lt;/li&gt;
&lt;li&gt;Basic knowledge on the ChangeNotifier class (&lt;a href="https://docs.flutter.dev/development/data-and-backend/state-mgmt/simple"&gt;Simple app state management | Flutter&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Let’s Begin
&lt;/h3&gt;

&lt;p&gt;I will be starting out by creating the theme.dart file. It can be kept in any directory depending on your file structure. I keep it in its own separate folder that contains files like colors.dart and any other theming/styling variables.&lt;/p&gt;

&lt;h4&gt;
  
  
  Initial Setup
&lt;/h4&gt;

&lt;p&gt;First things first, let’s change the root of our app into a stateful widget. We need to do this in order for the widget tree to re-render when the theme is changed. Some of you might think that is going to be very tasking process for the app especially if it’s a huge app like Instagram for instance, well you will be surprised to know that Flutter handles this quite well and if you do run into any bottlenecks or janky frames you can always make use of the AnimatedBuilder widget which takes in a Listenable as an argument and changes the children widgets or the widget tree that it wraps based on changes happening within the Listenable .&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As I usually do in articles like this I explain the code within the code snippet. Take note of the comments.&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating Theme.dart
&lt;/h4&gt;

&lt;p&gt;We can leave the main.dart file as is for now and move on to creating the Theme.dart file.&lt;/p&gt;

&lt;p&gt;In this file we will be declaring our themes whether that be light, dark, sunrise, noon, or whatever you want to call them. We do this by making use of the ThemeData class in Flutter&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You can change the colors, text styles and more to whatever your app theme might be. Be careful while using some parameters though, for some reason some won’t work when combined with other parameters. For instance, the bodyMedium and bodyText1 parameters in the TextTheme class can not be used at the same time, this will cause an error that will break the app and show the below error&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vemhmhB8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AEl1iTrmdNu1649nz9mPGJQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vemhmhB8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AEl1iTrmdNu1649nz9mPGJQ.png" alt="" width="800" height="1731"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;I don’t know why this is allowed to happen 🤷‍♂️. They should just deprecate the 2018 terms&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Creating The AppTheme Class
&lt;/h4&gt;

&lt;p&gt;We will be making a class called AppTheme that makes use of the ChangeNotifier class. This will house our theme state and the callback that will handle toggling of the theme.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the above code snippet I added the AppTheme class into the theme.dart file. I did this because the class is only a few lines of code. Notice that I created an instance of it on the 30th line, I did this because it would be easier to understand if another person were to take a look at your code and look for the root instance of AppTheme.&lt;/p&gt;

&lt;p&gt;I made themeMode a getter since it is ill advised to mutate state directly, since mutating state directly leads to unexpected bugs some times.&lt;/p&gt;

&lt;h4&gt;
  
  
  Implementing appTheme
&lt;/h4&gt;

&lt;p&gt;Once you’ve created all that you can go back to your main.dart file and implement it in the MaterialApp widget at the root of your application, like so:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And with this you’re done. In order to make use of the themed values all you need to do is use Theme.of(context).* with (*) being the parameters you set in the ThemeData variables earlier e.g(Theme.of(context).textTheme.headlineMedium)&lt;/p&gt;

&lt;p&gt;Let me show you the PlaceholderWidget code as an example&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Let me show you what your app might look like if you followed this article to the letter:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h5hnRxvh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/600/1%2ArLY1a_0VNUFvKG8u8-nkqQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h5hnRxvh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/600/1%2ArLY1a_0VNUFvKG8u8-nkqQ.gif" alt="" width="600" height="1298"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Yup! It does that fading animation on it own, no extra code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And voila! You’re all done theming your Flutter app. With less than 30 lines of code and a few changes to already existing code you’ve added theming to your Flutter app.&lt;/p&gt;

&lt;p&gt;If this article helped you in any way, please feel free to share, leave a comment or applause 👏. If you think that I could improve the article in any way, please leave a comment, I would be happy to chat and rub minds.&lt;/p&gt;

&lt;p&gt;If you really liked this article feel free to check out my other posts on similar topics. And don’t forget to tune in next week for an inside look into a little side project I’m working on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://devshogun.medium.com/pull-to-refresh-or-search-using-flutter-e06e57b3b5e2"&gt;Pull To Refresh Or Search Using Flutter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>flutterappdevelopmen</category>
      <category>flutterwidget</category>
      <category>flutterui</category>
    </item>
    <item>
      <title>Flutter vs. React Native: A Cross-Platform Framework vs. React Ported For Mobile</title>
      <dc:creator>Michael Essiet</dc:creator>
      <pubDate>Sat, 10 Sep 2022 13:44:21 +0000</pubDate>
      <link>https://dev.to/devshogun/flutter-vs-react-native-a-cross-platform-framework-vs-react-ported-for-mobile-1pj2</link>
      <guid>https://dev.to/devshogun/flutter-vs-react-native-a-cross-platform-framework-vs-react-ported-for-mobile-1pj2</guid>
      <description>&lt;h4&gt;
  
  
  Why React Native Makes Me Want To Pull My Hair Out
&lt;/h4&gt;

&lt;p&gt;This is going to be a short article of me mostly venting about my struggles with both React Native and Flutter. Yes, I know it sounds weird but there are some things in React Native that I just don’t understand why they do and don’t exist, the same also goes for Flutter, but it’s much more manageable than React Native.&lt;/p&gt;

&lt;p&gt;A few things to note before reading: the views in this article are my own and they should not be taken as advice in any way, shape or form; the scenarios in this article do not apply to all projects and might or might not apply to yours; and I won’t be going into too much detail in regards to the differences in syntax or sharing code snippets like I normally do. Since they are built off of 2 completely different programming languages the huge difference in syntax shouldn’t come as a shock to you.&lt;/p&gt;

&lt;p&gt;Now let’s talk about the major differences between the 2:&lt;/p&gt;

&lt;h3&gt;
  
  
  Ease Of Use
&lt;/h3&gt;

&lt;p&gt;Ease of use is very subjective, depending on the framework and dev stack you are coming from. If you’re coming from a web development stack that makes use of Javascript frameworks such as React or Vue, React Native will seem very familiar to you as opposed to Flutter. However, if you’re coming from a more traditional programming stack such as Java, C# or Kotlin, Flutter won’t exactly feel familiar but most of the basic concepts of OOP you know will apply.&lt;/p&gt;

&lt;p&gt;If you’re a beginner just starting out your programming journey then I would say that Flutter is easier to use since it has a large library of built in widgets that just make the app development process seamless, but that can also work against you. With Flutter you can build a fully functioning app with cool animations and components without having to install any third party packages or libraries. Meanwhile for something as simple as a swipeable list view in React Native you will need to jump through so many hoops it’s ridiculous, from installing animation and gesture handling libraries such as react-native-gesture-handler and react-native-reanimated like why do I have to do all this for a component that should be built into the framework 🤦‍♂️&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JnyYV1nc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/480/1%2AM7A5N__FHtL4naTMbcKVNw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JnyYV1nc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/480/1%2AM7A5N__FHtL4naTMbcKVNw.gif" alt="" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation and Features
&lt;/h3&gt;

&lt;p&gt;In terms of documentation Flutter beats out React Native in this one. I know a lot of React Native fan boys are going to hate on me for saying this, but hear me out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lz3lPDxu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/480/1%2A1Zsk2pyAQrsIjAFdw9pr5g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lz3lPDxu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/480/1%2A1Zsk2pyAQrsIjAFdw9pr5g.gif" alt="" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Through out my journey as a developer I have never come across an official way to do something in React Native especially since the React Native team has close to 0 involvement in the community and in putting out beginner friendly and advanced content, either on Youtube or through blog posts. To be honest the React Native community and the fact that big tech companies are using it is the only reason why it’s still alive.&lt;/p&gt;

&lt;p&gt;While on the other hand, the Flutter team puts out so much content on their Youtube channel and blog posts that it’s hard to believe that they even have enough time to work on their framework. From full blown app tutorials, to widget by widget tutorials, to basic tutorials and explanations about advanced concepts such as multithreading and the likes, it’s hard to believe that there are still people out there that would still disagree with me on this topic, but I guess everyone is free to believe what they want 🤷‍♂.&lt;/p&gt;

&lt;p&gt;Now I know that React Native is very flexible as opposed to Flutter that can feel quite rigid at times, especially when using stuff like SVGs(till this day I’m still confused on why it’s so difficult to make use of SVGs in Flutter, but I guess you can’t have everything you want 😪).&lt;/p&gt;

&lt;p&gt;Anyways all in all Flutter has better documentation and better built in components/widgets. But I’m not going to lie the community support that Javascript has works in React Natives favor 🙄.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;Performance, performance the thing that everybody at all points of the development lifecycle cares most about. Let me save you some time and give you the answers first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flutter is faster in creating projects&lt;/li&gt;
&lt;li&gt;Flutter is faster in hot reloading and restarting&lt;/li&gt;
&lt;li&gt;Flutter is faster and smoother when carrying out complex animations since it has it’s own rendering engine&lt;/li&gt;
&lt;li&gt;Flutter uses less CPU power on your development machine during development&lt;/li&gt;
&lt;li&gt;React Native has smaller app bundles&lt;/li&gt;
&lt;li&gt;Flutter has faster read and write speeds when interacting with device storage&lt;/li&gt;
&lt;li&gt;Flutter build times are quicker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see Flutter is faster…way faster. The speed doesn’t just apply to the things listed above it applies to a lot of other things as well, such as encryption and decryption. In an experiment I carried out recently I noticed that packages like ethers.js and web3.js were ported for dart so as a developer I became curious and decided to put ethers on dart up against ethers.js (the package it was ported from), and the results shocked me. Ethers on dart was 10 times faster on both iOS and Android. In the development space speed is very important and having something be 10 times faster is honestly ridiculous.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hCc3OuG0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/500/1%2AGABY5mtVhaSKLVVHRipqZA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hCc3OuG0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/500/1%2AGABY5mtVhaSKLVVHRipqZA.gif" alt="" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Developer Experience
&lt;/h3&gt;

&lt;p&gt;Ya, I’m not even going to bother writing much about this. React Native makes me want to pull out my hair and Flutter is manageable as long as you don’t bury yourself in nesting hell 😂.&lt;/p&gt;

&lt;p&gt;Oh, and did I forget to mention that if you’re really considering building complex applications using React Native that you will need to know a bit about how to code Natively since React Native doesn’t even come close to 80% integration with the Native code bases… but thank goodness for third party libraries am I right? 😅&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JNcqqub8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/480/1%2AUXD_ptwGJBO5yw5Df9GUkA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JNcqqub8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/480/1%2AUXD_ptwGJBO5yw5Df9GUkA.gif" alt="" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Flutter over React Native any day for &lt;strong&gt;MOBILE APP DEVELOPMENT&lt;/strong&gt; but never use Flutter or React Native for web development. &lt;strong&gt;Please!!!&lt;/strong&gt; I don’t know why these 2 teams decided to do this… well I guess I understand Flutter’s case to an extent, since they want to be the one stop shop for all your development framework needs but why does React Native for web even exist. React Native’s whole existence is based off of it being React.js for mobile development, it’s kinda implied in the name “React” + “Native”. Personally I think using React Native for web development is an abomination and the fact that it exists is probably because someone on the React Native team brought it up during some meeting and the team leads said why not 🤷‍♂️.&lt;/p&gt;

&lt;p&gt;I know a lot of people will have a lot of things to say regarding this article but these are all my views and you arguing with me over them won’t change a thing. Some things that we can all do that will make a change is contribute to the community by writing documentation, making videos, building well rounded packages and libraries, and making PRs to these projects with our own little additions (hopefully they get merged 🙏). Anyways big ups to the React Native community members for building for and keeping that framework alive and big ups to the Flutter team too for making such a well rounded framework 💪.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--npcgmsk8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/480/1%2Az-h_1fbl93DvI0Ub1FOnpQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--npcgmsk8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/480/1%2Az-h_1fbl93DvI0Ub1FOnpQ.gif" alt="" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ll be writing again next week about a personal app I’m currently working on. If any of you know Numi for Mac, you could say I’m working on something similar.&lt;/p&gt;

&lt;p&gt;If you enjoyed the article leave an applause and check out some of my other articles&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.devgenius.io/react-js-vs-solid-js-as-a-beginner-which-should-you-learn-fcb34653defe"&gt;React.js VS Solid.js, As A Beginner Which Should You Learn?&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnativedevelopme</category>
      <category>flutterappdevelopmen</category>
      <category>flutter</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>React.js VS Solid.js, As A Beginner Which Should You Learn?</title>
      <dc:creator>Michael Essiet</dc:creator>
      <pubDate>Sat, 03 Sep 2022 11:03:17 +0000</pubDate>
      <link>https://dev.to/devshogun/reactjs-vs-solidjs-as-a-beginner-which-should-you-learn-33lm</link>
      <guid>https://dev.to/devshogun/reactjs-vs-solidjs-as-a-beginner-which-should-you-learn-33lm</guid>
      <description>&lt;h4&gt;
  
  
  As A Beginner Which Framework Would Help You The Most On Your Developer Journey?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TJci0tNU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2ACc8wPgY3iVvj-cunecFyjg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TJci0tNU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2ACc8wPgY3iVvj-cunecFyjg.png" alt="React.js vs Solid.js" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a beginner getting into javascript Frontend frameworks for the first time you’re probably wondering about a few things like, which one is the fastest, which one is most used, which one is easier to learn or which one earns more. Well, if you are wondering about things like that, good thing you stumbled upon this article because we will be discussing which framework, Solid.js or React.js, would be the best fit for beginners, as well as answer a few questions you might have.&lt;/p&gt;

&lt;p&gt;Since this is a beginner focused article I will be providing short explanations to some of the terminologies used while talking about frontend frameworks. Do keep in mind that we will not be discussing anything advanced such as hydration methods, server side rendering, diffing algorithms, granularity, etc.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DOM&lt;/strong&gt; : Otherwise known as Document Object Model is an API for HTML documents that defines the logical structure of documents and the way documents can be accessed and manipulated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSX/TSX&lt;/strong&gt; : This is a syntax extension to javascript and typescript respectively. You will see them very often especially in codebases containing React.js or Solid.js code. Files that have the .jsx or .tsx file extension will contain JSX or TSX code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Virtual DOM(VDOM)&lt;/strong&gt;: This is a representation of the DOM stored in memory created by libraries like React.js, and it is synced with the real DOM by using a diffing algorithm.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diffing&lt;/strong&gt; : This is an algorithm that takes in 2 inputs and finds the difference between these inputs. As it is an algorithm different frameworks and libraries implement it in different ways and React.js is one of those libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Components&lt;/strong&gt; : React and Solid have things called components which can be different bits of reusable code such as navigation menus, drop downs, buttons, forms, helpers etc. The kinds of components you have, depends on you. The 2 types of components are function and class components. This is just a light summary,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rendering&lt;/strong&gt; : This is the process when your framework transforms your code into DOM(Document Object Model) nodes that are understandable by the browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok now that we’ve gotten some of the confusing lingo out of the way let’s talk about what you’re most curious about — which one is more popular or widely used?&lt;/p&gt;

&lt;h3&gt;
  
  
  Popularity
&lt;/h3&gt;

&lt;p&gt;Without a doubt React.js is more popular than Solid.js since it is older and it was made by a more well known company/team(i.e Meta). With React.js being released in 2013 it should not be much of a surprise that it’s more popular than Solid.js which was first open-sourced in 2018 and officially had version 1.0 released in 2021, making it roughly 5 years younger than React.js. With companies like Meta, Netflix, Airbnb, Dropbox and many more using React.js. Having React.js be the first framework you learn is not a bad idea at all.&lt;/p&gt;

&lt;p&gt;If you’re considering a framework because of it’s popularity, I would suggest that you go with React.js over Solid.js since it offers more job opportunities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;N.B&lt;/strong&gt; : From here on out React.js will be referred to as React or react and Solid.js will be referred to as solidjs or Solid&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning Curve &amp;amp; Development Experience
&lt;/h3&gt;

&lt;p&gt;Both React and Solid have fairly low learning curves. They’re the ideal frontend frameworks to learn for a beginner coming straight out of the HTML, CSS and Vanilla JavaScript bootcamp, with a basic understanding of these 3 it shouldn’t take longer than 3 months to grasp React or Solid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But&lt;/strong&gt; there are some things that you need to keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React has hooks which are functions that you use in function components, that offer you features that are only available in class components. They can not be used outside of function components since they are mainly built to be used inside them. If you try to make use of them outside of function components you will run into errors.&lt;/li&gt;
&lt;li&gt;On the other hand Solid has primitives that you can use both inside and outside your components. Solid only has function components so there is no need for you to worry about running into class components and wondering “what the heck is this?”.&lt;/li&gt;
&lt;li&gt;In React to store state within a component you have to make use of the useState hook. While in Solid you have to make use of the createSignal primitive or the createStore primitive. CreateStore is more used in arrays and objects, while createSignal is used more in storing numbers, strings and booleans. I’m sure you’re wondering why have 2 things that do the same thing, well Solid does this because they make createStore in such a way that using it for nested things like objects and arrays overall, make it faster, lighter and more reactive. I’m not going to go into too much detail into this but if you would like to know the details about it you can find it &lt;a href="https://www.solidjs.com/tutorial/stores_createstore"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With all this said, I’m sure you’re still wondering which is easier to learn, well I will have to say that Solid takes the cake in this one. With less specific things to worry about and components/helpers that make a lot of things easier, Solid just makes React look like it’s still in beta and I’m sure that as a beginner you wouldn’t want to deal with the complications of working with beta software.&lt;/p&gt;

&lt;p&gt;For instance Solid has a neat built in component called For, it helps in simplifying the complexity of dealing with arrays or data within them, within your JSX code. For example:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now here’s that same code in React&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Notice the slight differences and absence of the For component? Depending on the kind of person you are you might prefer React in this particular case, but with the built in components that Solid has, it’s going to be hard to say that the development experience isn’t better.&lt;/p&gt;

&lt;p&gt;Later on once you start making use of more complex libraries and writing much more complex and taxing code you will hit the React re-render hurdle that till this day vexes developers around the world. By the time you reinitialize something an infinite amount of times just to find out that it was just React doing it’s shananigans you will understand 🙃.&lt;/p&gt;

&lt;p&gt;There are a lot more things that you will come to learn and understand when you decide to learn either Solid or React. At the end of this article I will be providing links to both their documentations, so once you’re done feel free to read through which ever framework you choose.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;Now let’s get to the most important part, the part that companies or startups should consider before deciding on their tech stack, Perfomance. In this category there is no competition, Solid blows React out of the water. Here are a few photos to give you a little bit of context&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9_-wpuWW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2A1cczcmqnshyHSVVefK5SgQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9_-wpuWW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2A1cczcmqnshyHSVVefK5SgQ.png" alt="" width="800" height="752"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Aqn51mdu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AmN7jpXkMd7g1AauTH0ZGDw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Aqn51mdu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AmN7jpXkMd7g1AauTH0ZGDw.png" alt="" width="800" height="855"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JUBw-Cs7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/888/1%2Ati24ISkD_pRhZ_3V-DuOrA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JUBw-Cs7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/888/1%2Ati24ISkD_pRhZ_3V-DuOrA.png" alt="" width="800" height="1241"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;In all these comparisons lower is better&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I know these might seem like gibberish to some of you, but the tables analyze the time and memory it takes each of the frameworks to carry out the tasks in the first column. And in the first image you will notice that Solid is 5% slower than vanilla javascript as opposed to React that is about 93% slower. That is a huge margin. Here is the link to view the full table &lt;a href="https://krausest.github.io/js-framework-benchmark/current.html"&gt;Interactive Results (krausest.github.io)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Solid being almost as fast as vanilla JS there are not many frameworks that can beat its speed. Meanwhile React on the other hand bloats itself up with techniques like the VDOM, entire component re-render on even the smallest of changes, keeping long disposed of components still in memory, etc. Solid does things very differently with only updating things that have changed and doing its best to only render and load things that are needed in realtime through lazy prop evaluation and then getting rid of them when they’re not needed anymore. This in other words is called the Vanishing Components approach. I can write on this and other advanced concepts in another article if need be.&lt;/p&gt;

&lt;p&gt;I’m sure you might still be asking “Michael, what makes Solid.js so blazingly quick?”, well I’m glad you asked, luckily for you I’ve got the answer from Ryan Carniato the creator of Solid.js himself. He replied:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While Solid has a component model for authoring, it has very little impact on how it executes. By escaping the component model at runtime Solid is able to do even more efficient updates than other libraries that use compilation or a VDOM to diff.  &lt;strong&gt;— Ryan Carniato&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;you can find out more on this in the article Ryan posted(&lt;a href="https://dev.to/ryansolid/thinking-granular-how-is-solidjs-so-performant-4g37"&gt;Thinking Granular: How is SolidJS so Performant? — DEV Community 👩‍💻👨‍💻&lt;/a&gt;) in which he explains this in more detail.&lt;/p&gt;

&lt;p&gt;We can go on and on about how Solid blows React out of the water in regards to performance, but let’s move on to something that most, if not all of you are thinking about, and most likely came to this article to find out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Job Opportunities
&lt;/h3&gt;

&lt;p&gt;The job opportunities. One of the end goals of becoming a developer in the first place. Over the years many companies have integrated React into their sites, apps and some even their company infrastructure as a whole. Till this day React remains the most popular and well used framework in the world, it doesn’t matter where you live or work, no matter where you are you will come across a company, individual, government agency or even coffee shop looking to hire a React developer. With React there are countless job opportunities, but do keep in mind that with countless job opportunities also comes countless individuals looking to take those jobs.&lt;/p&gt;

&lt;p&gt;On the other hand, I haven’t run into any companies recruiting specifically Solid.js developers &lt;strong&gt;YET.&lt;/strong&gt; You might make the first startup that creates the first Solid.js developer job listing, who knows 🤷‍♂️. With all this said, I’m very certain that this will change in the future, especially with the level of frustration that React developers express on a daily basis (I’m one of them 🤣).&lt;/p&gt;

&lt;h3&gt;
  
  
  Community Support &amp;amp; Documentation
&lt;/h3&gt;

&lt;p&gt;The React community is one of the largest communities in the developer space. That shouldn’t be a surprise with React being about 9 years old as of the day of writing this article. On the other hand with Solid just being more than 4 years old its community is significantly smaller but that won’t stay true forever.&lt;/p&gt;

&lt;p&gt;In terms of documentation and coverage React has much more documentation both in the official docs and outside the docs with developers writing, recording and screenshotting about their apps, hurdles, issues, milestones or frustrations while using it. SolidJS has a few articles and videos posted online and the team and creator are active parts of the community. but it can’t be compared to React’s at the moment.&lt;/p&gt;

&lt;p&gt;With all this said do keep in mind that Solid and React are very similar and very different as well so if you run into a SolidJS specific problem you can always feel free to ask the whole community since everyone is here to learn and grow. To your surprise a senior React developer that has never touched SolidJS might be the one to help you solve your problem.&lt;/p&gt;

&lt;p&gt;React Documentation: &lt;a href="https://reactjs.org/docs/getting-started.html"&gt;Getting Started — React (reactjs.org)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Solid Documentation: &lt;a href="https://www.solidjs.com/guides/getting-started"&gt;SolidJS · Reactive Javascript Library&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In conclusion, if I were to make a recommendation, I would say to start with React &lt;strong&gt;right now.&lt;/strong&gt; I’m not sure where or when you will have come across this article, maybe SolidJS has taken the crown from ReactJS already. But as of September 1st, 2022, React is the framework/library to use as a beginner progressing from Vanilla javascript. Only once you’re done learning React and have honed your skills in it, would I &lt;strong&gt;strongly&lt;/strong&gt; recommend learning Solid, as it is more performant, has a better dev experience and is much more closer to the community.&lt;/p&gt;

&lt;p&gt;If this article was helpful please leave an applause 👏 , share and leave a comment of your thoughts on it. If I missed anything or made any mistakes, feel free to let me know. I’m always looking for ways to improve .&lt;/p&gt;

&lt;p&gt;Happy coding and have a great day ✌️.&lt;/p&gt;

&lt;p&gt;Check out some of my other articles:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.devgenius.io/add-parallax-animation-to-your-flutter-app-using-velocityx-and-sensor-plus-c0a832e4e12f"&gt;Add Parallax Animation To Your Flutter App Using VelocityX and Sensor Plus&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactvssolid</category>
      <category>solidjs</category>
    </item>
    <item>
      <title>Add Parallax Animation To Your Flutter App Using VelocityX and Sensor Plus</title>
      <dc:creator>Michael Essiet</dc:creator>
      <pubDate>Sat, 27 Aug 2022 14:36:18 +0000</pubDate>
      <link>https://dev.to/devshogun/add-parallax-animation-to-your-flutter-app-using-velocityx-and-sensor-plus-4j6d</link>
      <guid>https://dev.to/devshogun/add-parallax-animation-to-your-flutter-app-using-velocityx-and-sensor-plus-4j6d</guid>
      <description>&lt;h4&gt;
  
  
  Learn A New Way To Use Tween Animations In Flutter
&lt;/h4&gt;

&lt;p&gt;Everyone knows that parallax animations look cool and are really fun, but not everyone knows how difficult it is to actually apply it to apps. In this article I will be showing you a quick and easier way to add it to your Flutter apps using the TweenAnimationBuilder widget, transform widget and 2 handy packages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtube.com/shorts/jOK9zFSLhzU?feature=share"&gt;Parallax effect made using Flutter, VelocityX and Sensor_Plus&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  First things first, what will we be needing in order to carry this out:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Flutter (of course)&lt;/li&gt;
&lt;li&gt;VelocityX Flutter Package (not compulsory but helps a lot)&lt;/li&gt;
&lt;li&gt;Sensor_Plus Flutter Package (very important)&lt;/li&gt;
&lt;li&gt;And last but not least a little bit of knowledge using builder widgets in Flutter&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://api.flutter.dev/flutter/widgets/TweenAnimationBuilder-class.html"&gt;TweenAnimationBuilder class - widgets library - Dart API&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s Get Started
&lt;/h3&gt;

&lt;p&gt;Ok! Now that you’ve skimmed through the TweenAnimationBuilder documentation you should have a basic understanding of it. I encourage you to do a quick read of the Sensor_Plus package documentation and the VelocityX documentation as well, as they will help you in the future.&lt;/p&gt;

&lt;p&gt;In order to get started with this make sure that you already have a Flutter app that you want to add this to or simply run flutter create app-name in your terminal.&lt;/p&gt;

&lt;p&gt;First you’ll need to head over to the pubspec.yaml file and install the packages that I mentioned earlier (velocityx and sensor_plus).&lt;/p&gt;

&lt;p&gt;Once that’s done the second thing that you’ll do is go into your app-name/lib directory and open up main.dart. In here you’ll see a lot of generated code, you can leave it for now and just create another .dart file in app-name/lib that will house the Parallax animation widget. You can name this file whatever you’d like.&lt;/p&gt;

&lt;h3&gt;
  
  
  Now Let’s Get Into Coding
&lt;/h3&gt;

&lt;p&gt;Once you open this file in your code editor you can go ahead and create stateful widget or use the stfl — stateful widget generator code snippet that comes with the Flutter VSCode extension. You should have something like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/0f463b832533235c9246a6036f943b33/href"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/0f463b832533235c9246a6036f943b33/href"&gt;https://medium.com/media/0f463b832533235c9246a6036f943b33/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alright now that you’ve generated a basic stateful widget it’s time to modify a few things. Firstly let’s add the TickerProviderStateMixin to the _MyWidgetState class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href"&gt;https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this you will be ready to produce as many 60 frames per second animations as you’d like. And do endeavor to read the comments in the code as the code will be explained in the comments much more than in the article.&lt;/p&gt;

&lt;h4&gt;
  
  
  Getting the values out of the way
&lt;/h4&gt;

&lt;p&gt;Here, we’ll be defining variables to hold the angular values that we will receive from the Sensor_Plus package.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href"&gt;https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, so as the comments have already explained the values that have angle in them are used to store the data that we will receive from the accelerometerEvents.listen method. The streamsub value on the other hand will be used as an array of stream subscriptions. The StreamSubscription class here is used to properly type the array letting flutter know that this is an array of StreamSubscription objects. Whenever you use the .listen method on a stream the object returned is a StreamSubscription object. More on StreamSubscription below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://api.flutter.dev/flutter/dart-async/StreamSubscription-class.html"&gt;StreamSubscription class - dart:async library - Dart API&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We made the build function return a Column widget because of the error that will appear if there is nothing returned.&lt;/p&gt;

&lt;p&gt;Now let’s call void initState and void dispose so that we can initialize our accelerometerEvents.listen. We will also be changing the state of the xAngle, prevXAngle, yAngle, prevYAngle, zAngle, and prevZAngle variables in the .listen() callback function. Let’s go 👇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href"&gt;https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We make use of the initState and dispose functions in order to, respectively, subscribe and cancel subscriptions to the stream.&lt;/p&gt;

&lt;p&gt;Notice that in the streamsub.add method we’re adding accelerometerEvents.listen() to our array of stream subscriptions. Inside the listen method we have a function that gives us the realtime value of the accelerometer events. The event object has 3 values: x, y and z. Make sure that you set the state of what the previous Angle values will be before setting the new state of the Angle values, this will be very important for what comes next.&lt;/p&gt;

&lt;h4&gt;
  
  
  Time To Animate
&lt;/h4&gt;

&lt;p&gt;Now that the values are updating in realtime we can start making use of them using the flutter widget called *&lt;em&gt;TweenAnimationBuilder *&lt;/em&gt;. We will be making use of the Column widget that we added earlier, of course you can make use of any container like widget you want but I’m making use of Column in case I would like to add anything after the widget. Alright, let’s get into it&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href"&gt;https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the code snippet above, we make use of 2 TweenAnimationBuilder widgets. This is because we will be animating the values of 2 axes, first the X, then the Y. The way that we will be doing this is through the Transform widget. You might be wondering why we are using the zAngle value if we’re going to be animating the Y axis. Well this is because of the way you move your device in 3D space, making use of the zAngle for this produces the best results. As you will see later, the values being parsed to the rotateX and rotateY Matrix4.indentity() methods, will seem a bit mismatched. Ok, now let’s see the values being used in action&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href"&gt;https://medium.com/media/3582a3d93a14657f47b526a5ac5220a8/href&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;*1. Here we passed in the negative of the animated zValue provided by the TweenAnimationBuilder . You will probably be asking why is it negative, like I said earlier it is because of the way you move your device in 3D space. In translates in a much more desired way as if we were to use the positive zValue or make a yValue.&lt;/li&gt;
&lt;li&gt;*2. Here we passed in xValue. Yes, not the negative just the positive xValue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m sure you’re interested in knowing why these values are divided by 10. It’s because if they are not divided by 10 the parallax motion would be too much event if the device is turned slightly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;*3. We made use of the xValue and zValue here and multiplied them by 8 in order to get a better shadow effect for the parallax card.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this we are done with the Parallax animation and we can now see it in acton in our app. All we need to do is add this widget to our main.dart file as a widget. Like so&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/4448338978a34173350d85c041f4de50/href"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/4448338978a34173350d85c041f4de50/href"&gt;https://medium.com/media/4448338978a34173350d85c041f4de50/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get your main.dart file looking like this just make sure to get rid of all the boilerplate that is comes along with it when you generated the app earlier. Replace NameOfParallaxWidget() with whatever you named the parallax widget you made.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Now you should have something like this when you run your flutter app&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v5mP5uMK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/600/1%2AU3nZzK385WfOhUZkFzlutw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v5mP5uMK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/600/1%2AU3nZzK385WfOhUZkFzlutw.gif" alt="" width="600" height="1299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there you go you have a parallax animation. You can apply this method to any widget that you would like to animate by just changing the VxBox widget to another widget you would like to animate. You can even use it on text but it would be best to use it on the texts container instead 😅.&lt;/p&gt;

&lt;p&gt;Here’s the link to my repo&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/michaelessiet/flutter-test/blob/master/lib/widgets/parallaxnft_widget.dart"&gt;flutter-test/parallaxnft_widget.dart at master · michaelessiet/flutter-test&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope this article helped you out. If it did why not leave a clap 👏 and share 😁.&lt;/p&gt;

&lt;p&gt;If you would like to add to the repo feel free to leave a PR or fork and experiment with it . If I got anything wrong don’t be shy to let me know in the comments. I’m always looking for a way to improve.&lt;/p&gt;

&lt;p&gt;Thanks for reading ❤️ have a great time playing around with Flutter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://devshogun.medium.com/pull-to-refresh-or-search-using-flutter-e06e57b3b5e2"&gt;Pull To Refresh Or Search Using Flutter&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Check out some of my other articles 👆
&lt;/h4&gt;




</description>
      <category>mobileapps</category>
      <category>flutterapp</category>
      <category>flutter</category>
      <category>mobiledevelopment</category>
    </item>
  </channel>
</rss>
