<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: The Jared Wilcurt</title>
    <description>The latest articles on Forem by The Jared Wilcurt (@thejaredwilcurt).</description>
    <link>https://forem.com/thejaredwilcurt</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%2F27675%2F9eed086f-834e-4e50-9a05-c026403c33f1.jpeg</url>
      <title>Forem: The Jared Wilcurt</title>
      <link>https://forem.com/thejaredwilcurt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/thejaredwilcurt"/>
    <language>en</language>
    <item>
      <title>Trigger a child component method from parent (Vue)</title>
      <dc:creator>The Jared Wilcurt</dc:creator>
      <pubDate>Wed, 01 Oct 2025 19:10:54 +0000</pubDate>
      <link>https://forem.com/thejaredwilcurt/trigger-a-child-component-method-from-parent-vue-1amn</link>
      <guid>https://forem.com/thejaredwilcurt/trigger-a-child-component-method-from-parent-vue-1amn</guid>
      <description>&lt;h2&gt;
  
  
  Vue 3 Approaches:
&lt;/h2&gt;

&lt;p&gt;I've attempted to make this list as comprehensive as possible with code examples.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A.&lt;/strong&gt; Use &lt;code&gt;ref&lt;/code&gt;s
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;B.&lt;/strong&gt; Prop trigger
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C.&lt;/strong&gt; Module file instantiation
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;D.&lt;/strong&gt; Composable
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E.&lt;/strong&gt; Pinia
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;F.&lt;/strong&gt; Emit Callback
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;G.&lt;/strong&gt; Event Bus
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Approach A: Ref
&lt;/h3&gt;

&lt;p&gt;Add a Ref to the child and access its internals from the parent.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ref - Options API
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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="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="s1"&gt;MyChild&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &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="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="s1"&gt;Hello&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;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&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;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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 vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;MyChild&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"myChild"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"$refs.myChild.setText"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Set text&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MyChild&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;./MyChild.vue&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="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="s1"&gt;MyParent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MyChild&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Ref - Script Setup
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;MyChild&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"myChild"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"setChildText"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Set text&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&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;useTemplateRef&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;vue&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;MyChild&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;./MyChild.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;defineOptions&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="s1"&gt;MyParent&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;useChildDoThing&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;MyChildRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTemplateRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myChild&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;setChildText&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;MyChildRef&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;setText&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="nx"&gt;setChildText&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;setChildText&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useChildDoThing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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 vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&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;ref&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;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;defineOptions&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="s1"&gt;MyChild&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;useText&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&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;setText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&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="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="nx"&gt;setText&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;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nf"&gt;defineExpose&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;setText&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Approach B: Prop Trigger
&lt;/h3&gt;

&lt;p&gt;Flip a boolean prop on the child from the parent. The child watches the prop and runs the method. This requires deeper coupling of a boolean prop tied to a method, and a watcher connecting them. Becase of this, it is not advised. Also unit testing components that use watchers is always harder.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trigger - Options API
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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="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="s1"&gt;MyChild&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;triggerSetText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Boolean&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &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="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="s1"&gt;Hello&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;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&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="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;triggerSetText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setText&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;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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 vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;MyChild&lt;/span&gt; &lt;span class="na"&gt;:triggerSetText=&lt;/span&gt;&lt;span class="s"&gt;"setTextSwitch"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"setChildText"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Set text&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MyChild&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;./MyChild.vue&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="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="s1"&gt;MyParent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MyChild&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &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="na"&gt;setTextSwitch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;setChildText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setTextSwitch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setTextSwitch&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;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Trigger - Script Setup
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&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;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;watch&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;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;defineOptions&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="s1"&gt;MyChild&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;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineProps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;triggerSetText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Boolean&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;useText&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&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;setText&lt;/span&gt; &lt;span class="p"&gt;()&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="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&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;watch&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;triggerSetText&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;setText&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;return&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="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;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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 vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;MyChild&lt;/span&gt; &lt;span class="na"&gt;:triggerSetText=&lt;/span&gt;&lt;span class="s"&gt;"childTextTrigger"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"setChildText"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Set text&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&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;ref&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;vue&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;MyChild&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;./MyChild.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;defineOptions&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="s1"&gt;MyParent&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;useSetChildText&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;childTextTrigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;setChildText&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;childTextTrigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;childTextTrigger&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="nx"&gt;childTextTrigger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;setChildText&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;childTextTrigger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;setChildText&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSetChildText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Approach C: Module Helper File
&lt;/h3&gt;

&lt;p&gt;Initialize your shared reactive state in a module, export the state and logic as needed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Helper - Options API
&lt;/h4&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;ref&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;vue&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&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;text&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;./helper.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;export&lt;/span&gt; &lt;span class="k"&gt;default&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="s1"&gt;MyChild&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&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="nf"&gt;function &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;text&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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 vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;MyChild&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"setText"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Set text&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MyChild&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;./MyChild.vue&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setText&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;./helper.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;export&lt;/span&gt; &lt;span class="k"&gt;default&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="s1"&gt;MyParent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MyChild&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Helper - Script Setup
&lt;/h4&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;ref&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;vue&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&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;text&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;./text.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;defineOptions&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="s1"&gt;MyChild&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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 vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;MyChild&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"setText"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Set text&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MyChild&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;./MyChild.vue&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setText&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;./text.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;defineOptions&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="s1"&gt;MyParent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Approach D - Composable
&lt;/h3&gt;

&lt;p&gt;Similar to the above, but instead of instantiating in the helper module, your wrap the logic in a function call as a composable. This allows shared instantiation, like above, but also for seperate instances of state.&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ref&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;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// For new context&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&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;setText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&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="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="nx"&gt;setText&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// For shared context&lt;/span&gt;
&lt;span class="k"&gt;export&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;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Approach E - Pinia
&lt;/h3&gt;

&lt;p&gt;Move the shared component state to a Pinia store. Move the shared logic to a Pinia action. Import them as needed from the store in each component.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pinia - Options
&lt;/h4&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;defineStore&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;pinia&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&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;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &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="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="s1"&gt;Hello&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;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&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;mapState&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;pinia&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;textStore&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;../stores/text.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;export&lt;/span&gt; &lt;span class="k"&gt;default&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="s1"&gt;MyChild&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;computed&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;mapState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;textStore&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="s1"&gt;text&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="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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 vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;MyChild&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"setText"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Set text&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&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;mapActions&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;pinia&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;MyChild&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;./MyChild.vue&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;textStore&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;../stores/text.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;export&lt;/span&gt; &lt;span class="k"&gt;default&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="s1"&gt;MyParent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MyChild&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;methods&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;mapActions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;textStore&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="s1"&gt;setText&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="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Pinia - Script Setup
&lt;/h4&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;defineStore&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;pinia&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ref&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;vue&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&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;setText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setText&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="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 vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&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;computed&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;vue&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;textStore&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;../stores/text.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;defineOptions&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="s1"&gt;MyChild&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&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;return&lt;/span&gt; &lt;span class="nf"&gt;textStore&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="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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 vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;MyChild&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"setText"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Set text&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MyChild&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;./MyChild.vue&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;textStore&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;../stores/text.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;defineOptions&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="s1"&gt;MyParent&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;textStore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Approach F - Emit a callback
&lt;/h3&gt;

&lt;p&gt;The child component could emit an object with a reference to a function in the child, that can then be called by the parent. Gonna be honest, I've been doing Vue for 8 years and never once seen anyone do this. I did test it and shockingly it works. Probably has some performance downsides though. &lt;strong&gt;If you use this approach you're probably doing something very wrong.&lt;/strong&gt; I don't see any advantage to using this over just using a &lt;code&gt;ref&lt;/code&gt; which is officially recommended and simpler.&lt;/p&gt;

&lt;h4&gt;
  
  
  Emit Callback - Options API
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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="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="s1"&gt;MyChild&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &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="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="s1"&gt;Hello&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;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&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="na"&gt;created&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;innerMethods&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;setText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setText&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="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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 vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;MyChild&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;innerMethods=&lt;/span&gt;&lt;span class="s"&gt;"childMethods = $event"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"childMethods.setText()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Set text&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MyChild&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;./MyChild.vue&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="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="s1"&gt;MyParent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;MyChild&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &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="na"&gt;childMethods&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;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Emit Callback - Script Setup
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&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;onMounted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ref&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;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;defineOptions&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="s1"&gt;MyChild&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;emit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineEmits&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;innerMethods&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;useText&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&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;setText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&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;onMounted&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="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;innerMethods&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;setText&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="nx"&gt;text&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;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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 vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;MyChild&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;innerMethods=&lt;/span&gt;&lt;span class="s"&gt;"childMethods = $event"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"childMethods.setText()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Set text&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&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;ref&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;vue&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;MyChild&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;./MyChild.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;defineOptions&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="s1"&gt;MyParent&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;childMethods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Approach G: Event Bus
&lt;/h3&gt;

&lt;p&gt;Vue 2 had an event bus pattern. It sucked, and you should not have ever used it. They told people not to, but they did anyway. In Vue 3, the entire concept was abandoned and removed. But just because it's not possible, and was always a bad idea, doesn't mean you can't still do it. It would require pulling in an additional dependency (&lt;code&gt;npm i --save mitt&lt;/code&gt;). But I'm not gonna put a code example for this one because it's a dumb idea. Don't do it. Even dumber than the callback example above, because it involves maintaining another dependency.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Editor's Note: This was originally on Stack Overflow, but I deleted it from there after the 9th time the mods tried to edit it. Now it lives here. Where it will still be used for AI training data, without my permission, but at least StackOverflow won't profit off of it, and the psycho mods over there can't fuck with it to make it inaccurate.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>vue</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Using Vue's Single File Components (.vue) in the browser directly, no build step</title>
      <dc:creator>The Jared Wilcurt</dc:creator>
      <pubDate>Tue, 08 Jul 2025 13:14:28 +0000</pubDate>
      <link>https://forem.com/thejaredwilcurt/using-vues-single-file-components-vue-in-the-browser-directly-no-build-step-50j3</link>
      <guid>https://forem.com/thejaredwilcurt/using-vues-single-file-components-vue-in-the-browser-directly-no-build-step-50j3</guid>
      <description>&lt;p&gt;"The web is so complex now"&lt;/p&gt;

&lt;p&gt;"Ugh, I wish I didn't need all these different tools and build steps just to make a website"&lt;/p&gt;

&lt;p&gt;"But I don't want to give up all the convenience I'm used to"&lt;/p&gt;

&lt;p&gt;Sure, that's enough strawmen to pretend to justify this sillyness.&lt;/p&gt;

&lt;p&gt;Vue invented this phenomenal idea of a "Single file component". Where you break up your app into UI component chunks (separation of features), and within each component, there are 3 dedicated places for the 3 languages of the web. Each with their own focus (separation of concerns).&lt;/p&gt;

&lt;p&gt;Technically you can use Vue via a CDN and it works, but out of the box, they don't have a way to support these wonderful &lt;code&gt;.vue&lt;/code&gt; files in the browser. So we need to pull in a library that can dynamically download &lt;code&gt;.vue&lt;/code&gt; files on the fly, and also process them to regular JS render functions that the Vue runtime can handle. Fortunately this library does exist, however there are some caveats to working with this approach.&lt;/p&gt;

&lt;p&gt;Below I've outlined a basic "Hello World" setup, with comments pointing out things that work differently when you run everything directly in the browser without a build step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- index.html --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"IE=edge"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1, shrink-to-fit=no"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Hello, World&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/styles/main.css"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- FROM: cdn.jsdelivr.net/npm/vue@3.5.17/dist/vue.global.prod.js --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/vendors/vue.global.prod.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-cloak&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!--
        All HTML tags must be lowercase.
        Component names must be two words and hyphenated so the browser can
        differentiate them from real HTML tags, which are always one word.
        All components must have ending tags.
        BAD: &amp;lt;Logo /&amp;gt;
        BAD: &amp;lt;SiteLogo /&amp;gt;
        BAD: &amp;lt;site-logo /&amp;gt;
        BAD: &amp;lt;logo&amp;gt;&amp;lt;/logo&amp;gt;
        GOOD: &amp;lt;site-logo&amp;gt;&amp;lt;/site-logo&amp;gt;
      --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;site-logo&amp;gt;&amp;lt;/site-logo&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Hello, World&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- FROM: cdn.jsdelivr.net/npm/axios@1.10.0/dist/axios.min.js --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/vendors/axios.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- FROM: cdn.jsdelivr.net/npm/vue3-sfc-loader@0.9.5/dist/vue3-sfc-loader.js --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/vendors/vue3-sfc-loader.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/scripts/helpers.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/scripts/app.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/styles/fonts.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;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 javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* /scripts/helpers.js */&lt;/span&gt;
&lt;span class="c1"&gt;// Abstract away the component import process to simplify it&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpVueLoader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;componentPath&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;sfcLoaderOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;moduleCache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;vue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;getFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;function &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="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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;),&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="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&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;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;addStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;textContent&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;style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;style&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;textContent&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;reference&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;style&lt;/span&gt;&lt;span class="dl"&gt;'&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="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertBefore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reference&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;return&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineAsyncComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue3-sfc-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;loadModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;componentPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sfcLoaderOptions&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* /scripts/app.js */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Importing child components is a little different&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;site-logo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;httpVueLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/components/site-logo.vue&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;// But the rest of the component is normal&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &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;},&lt;/span&gt;
  &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="na"&gt;created&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- /components/site-logo.vue --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/index.html"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
        &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/imgs/logo.png"&lt;/span&gt;
        &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Hello World logo"&lt;/span&gt;
        &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"wordmark"&lt;/span&gt;
      &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!--
  All the code you write in your components needs to be browser-safe.
  Meaning you must use only HTML, CSS, and JavaScript (no meta-languages).
  Also you can only use language features supported in the browser, there
  are no build tools to polyfill, vendor-prefix, or transpile the syntactic sugar for you.
--&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;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="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="s1"&gt;site-logo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style &lt;/span&gt;&lt;span class="na"&gt;scoped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;.wordmark&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above example doesn't show Vue-Router or Pinia, but they both have a CDN approach officially documented and can be pulled in normally.&lt;/p&gt;

&lt;p&gt;Also, in the same spirit, you could pull in a library like &lt;code&gt;marked.js&lt;/code&gt; to convert markdown files on the fly to HTML in the browser.&lt;/p&gt;

&lt;p&gt;This means your entire project has no build step, but you can still break up your code into modular chunks and dynamically load them in, processing them at runtime to generate the page content on the fly.&lt;/p&gt;

&lt;p&gt;The upsides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can statically host these files and they just work&lt;/li&gt;
&lt;li&gt;You can edit the files on the server and they are live instantly, no build step or processing required.

&lt;ul&gt;
&lt;li&gt;Though if you are hosting your static site on GitHub Pages, it lets you create a GitHub Action to do the build step on every commit anyways, which would result in a much better user and dev experience. But we aren't here for those practical solutions.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;No CLI tooling or dependency management&lt;/li&gt;

&lt;li&gt;No build config files to deal with&lt;/li&gt;

&lt;li&gt;Working with the real languages right in the browser, like the good ol' days&lt;/li&gt;

&lt;li&gt;When it comes time to update dependencies, you just change the version number in the URL (if you are pointing to the CDN directly. My examples show them as downloaded to a vendors folder which is better for performance, but lol, nothing else about this is, so who cares)&lt;/li&gt;

&lt;li&gt;Converting this over to a system with build tools is pretty straight-forward. Really it's just changing the imports in each file, and the basic setup. Component logic doesn't change at all.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The downsides to this is are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You send much more data than if you used a build step.&lt;/li&gt;
&lt;li&gt;The page has to "build" at runtime&lt;/li&gt;
&lt;li&gt;Content loads dynamically in chunks rather than in optimized bundles&lt;/li&gt;
&lt;li&gt;SEO is much harder&lt;/li&gt;
&lt;li&gt;If you make a mistake you have no tools to catch you.&lt;/li&gt;
&lt;li&gt;If you do use tools, like a linter, you'll need to adjust linter settings to work within the limitations of this approach.&lt;/li&gt;
&lt;li&gt;The projects this works best on are Websites (not webapps), that are mostly static anyways. And could probably just be written in plain HTML and CSS without any JS at all.&lt;/li&gt;
&lt;li&gt;and &lt;em&gt;surrrrrre&lt;/em&gt; we could use a Static Site Generator (SSG) like VitePress, but that involves a build step! what are you crazy? this convoluted, inefficient approach is so much more con-veeeeen-yent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;lol don't actually do this, but also do it, I don't care, I'm not your dad&lt;/p&gt;

</description>
      <category>vue</category>
      <category>donttrythisathome</category>
      <category>lolwhythough</category>
      <category>okayiguess</category>
    </item>
    <item>
      <title>Why trying to be clever is the fastest way to writing bad code</title>
      <dc:creator>The Jared Wilcurt</dc:creator>
      <pubDate>Wed, 11 Jun 2025 01:42:23 +0000</pubDate>
      <link>https://forem.com/thejaredwilcurt/why-trying-to-be-clever-is-the-fastest-way-to-writing-bad-code-4nhc</link>
      <guid>https://forem.com/thejaredwilcurt/why-trying-to-be-clever-is-the-fastest-way-to-writing-bad-code-4nhc</guid>
      <description>&lt;h1&gt;
  
  
  The 3 types of developers
&lt;/h1&gt;

&lt;p&gt;In my experience, there are 3 types of people drawn to programming; “The Tourist”, “The Puzzle Master”, and “The Builder”.&lt;/p&gt;

&lt;p&gt;The tourist is someone that has no real interest in programming itself, or what you can do with it. They are more interested in how it can allow them to change their lifestyle. They may care about the higher pay, allowing for a better living space, or to get away from the work culture they are used to in a different industry, or the aspect of being able to work remotely. You’ll often hear people from this group say something like “I just want to be able to travel and work from anywhere”. Hence the name “tourist”. Though this group often doesn’t last long, either leaving the industry, or changing position to management or something else that may be near programmers,  but without having to primarily be a programmer. There are some that stick it out, and they tend to be pretty fun.&lt;/p&gt;

&lt;p&gt;The puzzle masters are people that love the challenge, and feeling of solving a complex puzzle. These are your more stereotypical programmers. They find the levels of abstraction involved with programming exciting. They love logic, and keeping track of many things at once in their giant puzzle master brains. They can be insanely brilliant at being able to solve the most complex of problems. They are also most susceptible to the siren song of trying to be clever, but no group is completely free from its entrancing melody. This group can also be prone to over-engineering.&lt;/p&gt;

&lt;p&gt;The last group is the builder, my favorite group, the best group! I put myself in this group, so I’m only slightly biased. Builders are passionate about making stuff. The code lets them create things they otherwise would not be able to. They tend to not be interested in puzzles, preferring to avoid them and spend as much time as they can creating. Builders are less likely to read a book on how to do something, and more likely to just hop in and try to figure it out. This can be good sometimes, but can also lead to more naive solutions that could have been avoided if more time was spent studying. Successful builders tend to be more process oriented, knowing everything they need to complete in order to finish what they’re building. They try to focus just on those things.&lt;/p&gt;

&lt;p&gt;In reality very few people fall entirely into just one of these camps, instead being a mix of them, that may change over time. But you should know which of these you most lean towards, and if you don’t, the honest people around you will let you know if you ask.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why trying to be clever is the fastest way to writing bad code
&lt;/h1&gt;

&lt;p&gt;Why is it that trying to be clever tends to be such a bad thing? There are many adages about simplicity from other industries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1960’s US Navy - &lt;strong&gt;KISS: Keep It Simple Stupid&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;UX Expert Luke Wrobleski - &lt;strong&gt;Obvious always wins&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The most popular UX Book - &lt;strong&gt;Don’t make me think&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It comes down to communication. Ultimately most jobs in our little world are about conveying context. As a developer your job is to communicate abstract ideas into concrete logic and systems that a computer can understand. But your job is also in writing that code in a way that it also communicates to other developers what your intent is, and why the code exists and does what it does.&lt;/p&gt;

&lt;p&gt;If others need to be as clever as you were to solve the problem just to be able to understand the implemented solution, they simply may not be able to. It forces everyone to be the great puzzle solver you had to be in order to find the original solution. So good developers take the time to refactor the solution so that it is broken down to its simplest and most obvious form.&lt;/p&gt;

&lt;p&gt;Of the 3 groups mentioned above, the puzzle masters tend to be very clever, and I mean that as a compliment. And if you are one, that means you’ll need to ensure you give yourself ample additional time after solving one of your coding challenges to evaluate your solution. See if there are cleaner, simpler, more readable alternative ways to convey that solution. Or, once you understand one approach to solving it, see if other approaches could work as well. I find talking to other developers about my complex approach yields ideas of “Would X work here?”. Sometimes X is something I hadn’t even considered, and it would drastically simplify my solution. Other times it spawns a discussion as to why X wouldn’t work here, and the other developer challenges assumptions I had made about that approach.&lt;/p&gt;

&lt;p&gt;One time I was working with a developer who was trying to add a new concept to an existing very generalized system. This system had many many layers of abstraction built in, as it was the primary architecture for how most of this large application worked. As he talked about his approach, and I tried to offer alternative solutions, we both felt like perhaps we were over complicating things. Maybe there were other approaches we could take that wouldn’t have as many drawbacks. So we invited 3 more software engineers into the room. We explained the problem and the current approach, and ideas we had and their downsides. Then the 5 of us sat in that room for 90 minutes talking about the problem, throwing out new ideas, and shooting holes in them. From creating wrapper parent components, to making generic global state functions to be passed around between a top level configuration and a low level input field. It got pretty complex. But ultimately we found a beautifully simple solution that only required passing in a single 3 line callback function. Three seniors, one tech lead, and one quiet junior sitting in the corner listening and trying to keep up. It took this group an hour and a half to write 3 lines of code. But it saved us months of future turmoil from dealing with complex interconnected systems passing data around in &lt;strong&gt;&lt;em&gt;clever&lt;/em&gt;&lt;/strong&gt; ways.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>softwaredevelopment</category>
      <category>cleancode</category>
      <category>tips</category>
    </item>
    <item>
      <title>The Job Pipeline</title>
      <dc:creator>The Jared Wilcurt</dc:creator>
      <pubDate>Sat, 24 May 2025 18:52:40 +0000</pubDate>
      <link>https://forem.com/thejaredwilcurt/the-job-pipeline-2jgc</link>
      <guid>https://forem.com/thejaredwilcurt/the-job-pipeline-2jgc</guid>
      <description>&lt;p&gt;It seems most people I talk to are unaware of the job pipeline. There is a process jobs go through in the journey of trying to find and hire a qualified candidate.&lt;/p&gt;

&lt;p&gt;Let's walk through this process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: The Rockstar
&lt;/h2&gt;

&lt;p&gt;Sometimes a job is created &lt;em&gt;exclusively&lt;/em&gt; for one specific person. Maybe the company is using a technology that person invented. Maybe someone is starting up a new business and doesn't want to invest the time and money to get it off the ground if it's just going to fail, so they &lt;em&gt;only trust&lt;/em&gt; this specific person to be the CTO. Maybe a specific person isn't very useful to have at your company, but it's worth paying them NOT to work for your competition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you apply for this job?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No, you can't "apply". This job is "offered" to you. In most cases, if the person does not accept the role, the job never gets created.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you get these jobs?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Be so good, they can't ignore you" - Steve Martin&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Work on your connections, your public facing "personal brand". Be well known in the industry. Give talks at conferences. Produce important content, be that a book, an open source library, a startup or product, etc.&lt;/p&gt;

&lt;p&gt;I personally convinced the company I work at to create an entirely new role to solve problems I'd identified, and recommended a friend for the position. They did a preliminary interview with my friend to make sure, if no one else applied, that they'd be happy hiring them. Because they didn't want to create this job role if we didn't have a good candidate lined up. After a hiring process with 60+ candidates applying, my friend made it to the final round and was hired. This role was made for them, and now, a year later, it's worked out really well. They are excelling in the role, and everyone is happy to have them solving those problems I'd originally pointed out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Internal Hires
&lt;/h2&gt;

&lt;p&gt;Whenever possible, you want to hire from within.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reasons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If someone is moving laterally from the same role on a different team, it often means they were bored with their work, or unhappy with the project, team, or management. Moving them to this other team in the same role is basically preventing them from leaving the company to do the same job somewhere else.&lt;/li&gt;
&lt;li&gt;Retaining talent is generally a big win for companies. Onboarding new people and getting them used to your company specific processes, verbiage, etc takes time.&lt;/li&gt;
&lt;li&gt;Hiring new people is a risk, what if they don't work out? What if they're a bad influence on the rest of the team?&lt;/li&gt;
&lt;li&gt;Promoting from within is good too. Let's say a Senior developer leaves the company and we need to back-fill that role. I've got a mid-level dev that is ready to be promoted that could be moved to this new team to take on the role of a senior. Great! I saved money and now only have to replace a mid level developer, rather than hire for a more expensive senior dev. But looking around I find a junior dev that is ready to be promoted to mid, let's move them over to fill in for the mid that was promoted. Now I only have to hire a much cheaper Junior dev. But the team the junior came from is actually fine, and doesn't need a replacement junior. TaDa! Win/Win/Win!

&lt;ul&gt;
&lt;li&gt;The mid and junior are both happy, they have been promoted.&lt;/li&gt;
&lt;li&gt;The company retains their existing talent.&lt;/li&gt;
&lt;li&gt;The company skips an external hiring process entirely, which is expensive and takes a lot of time.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Whenever possible, shuffling of internal assets is the best option for everyone involved. It is the most efficient use of employees.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you apply for this job?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nope, internal employees only. Unless you work at the company, you will never even know about this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you get these jobs?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make your manager aware that you are interested in something new, and why. Either a new team, project, or role. Explain the root cause of why you want something new. They will start asking around and trying to find opportunities for you, it may not happen soon, but when one comes up, they'll be thinking of you. And in the mean time, they'll try to improve the underlying issues that you pointed out as the reason you want this change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Nepotism
&lt;/h2&gt;

&lt;p&gt;Okay, so a new role opened up at the company and no one internal is interested or a good fit. So it's time to hire externally. But just because they're going external, doesn't mean they're doing it publicly. First, the company will ask employees for recommendations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reasons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As someone that works at the company, you know what the company is like, the culture, the expectations, and what this role would roughly look like. So you'll be able to filter out people you know that aren't a good fit, and if you know anyone that is, you can do a good job of recruiting them.&lt;/li&gt;
&lt;li&gt;If you recommend someone who was a bad hire, that reflects poorly on you, so you are likely to only recommend people you really trust to work out. Lowering the risk for the company.&lt;/li&gt;
&lt;li&gt;Companies generally reward employees when someone they recommended gets hired (referral bonus). This can be a couple hundred or thousand dollars depending on how important the role is, or how hard it is to find good candidates for that role.&lt;/li&gt;
&lt;li&gt;If your friend works at the same place as you, you are more likely to work there longer before leaving the company. Employee retention is a big win for any company.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Can you apply for this job?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Probably not. Sometimes, for legal reasons, these jobs will be posted publicly, but usually quietly to the company's careers page and taken down relatively quickly. Even if you snuck an application in, they are most likely going to go with the recommended candidate over you, unless you are dramatically better, and not hiring you would make other people look bad.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you get these jobs?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Networking. You have to have a strong network. You have to know people in the same industry as you, or doing the same job role at different companies. That is the easiest way to be informed of jobs before they are public. Being in the right group chat can increase your salary dramatically over the course of your career. Or when layoffs happen, they can be the difference between getting hired somewhere else instantly, or spending a year looking and applying, or changing careers entirely.&lt;/p&gt;

&lt;p&gt;I run a few Meetup groups. From this, and attending many other tech meetups, I know most of the people in the tech community in Indianapolis. So anytime a job opens up where I work, I have at least 2 or 3 good, qualified, candidates to recommend. As a result, I've helped a lot of people I know get hired. Also as a meetup organizer, I have companies coming TO ME to ask if I know any good candidates. And I always do. In person meetups took a huge hit during covid and have really only just started coming back in ~2024-2025. More and more jobs are remote now. But finding these communities is still key to getting alerted to opportunities when they come up. You can try going to meetups and announcing that you are looking for work, and maybe someone who is hiring will talk to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Recruiters
&lt;/h2&gt;

&lt;p&gt;Okay, so no one internally is a good fit, or knows anyone that is. Time for a recruiter. Some companies have recruiters on staff, others will pay external recruiters.&lt;/p&gt;

&lt;p&gt;A good recruiter is a master networker, they know hundreds of people that could be the right fit, and are constantly messaging and connecting with people. They're job is to know what the company is looking for, and what the people in their network are looking for and to match them up.&lt;/p&gt;

&lt;p&gt;Recruiters also have access to qualified candidates that are already working at other companies and wouldn't be looking for a job. Candidates that otherwise would never have applied.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you apply for this job?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nope, you have to be privately recruited.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you get these jobs?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use your network to find out who the best recruiters are &lt;em&gt;right now&lt;/em&gt;. Unfortunately, the best recruiters, don't stay recruiters for long. Usually only lasting a year or two. When you get really good at connecting people to higher paying jobs, it doesn't take long to figure out you can connect yourself to those jobs too.&lt;/p&gt;

&lt;p&gt;But you don't need &lt;em&gt;the best&lt;/em&gt; recruiter, as long as you can very clearly communicate exactly what you want, and what you &lt;em&gt;don't&lt;/em&gt; want, then that's all they really need to know.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: The careers page
&lt;/h2&gt;

&lt;p&gt;We finally made it to the point where the job requirements (job req) are posted publicly. But still quietly, on the company's website. Usually &lt;code&gt;careers.company.com&lt;/code&gt; or &lt;code&gt;company.com/careers&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reasons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This limits the applicants just to those that are already interested in working for the company.&lt;/li&gt;
&lt;li&gt;This means they are more likely to stay at the company longer if hired. And may already be familiar with the industry the company operates in.&lt;/li&gt;
&lt;li&gt;This also reduces the overall amount of applicants, important for competitive roles that may get dozens, hundreds, or even thousands of candidates. That's a lot to filter through.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Can you apply for this job?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes! But you have to be proactive and looking around at specific companies, and routinely coming back to see what's new.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you get these jobs?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Have a really polished resume that is optimized to quickly communicate your skills and experience, so as they skim across 15 resumes a minute, yours doesn't get filtered out.&lt;/p&gt;

&lt;p&gt;Practice your phone, and video call, interview skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Desperation sets in
&lt;/h2&gt;

&lt;p&gt;If a company isn't getting enough good candidates, they may try targeted job boards. Here in Indianapolis, we have a local tech community job board, which only those in our community know about. So you're more likely to find passionate, enthusiastic candidates through it. For programmers, Stack Overflow used to have the best job board, but then they killed it in order to take money from Indeed, to embed their shitty search. I mean, do what you gotta do to stay afloat as a company, StackOverflow, but sucks that the best tool for the industry died off. Now-a-days, I see people using LinkedIn's targeted marketing of job roles as a replacement.&lt;/p&gt;

&lt;p&gt;So yeah, basically more targeted posting of the job to the community, since not everyone checks your company's specific careers page every day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you apply for this job?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sure&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you get these jobs?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Same as above. Good resume, good interview, good luck.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: The sewage
&lt;/h2&gt;

&lt;p&gt;At this point, the job posting has been turned down by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All internal employees&lt;/li&gt;
&lt;li&gt;No one is willing to recommend anyone&lt;/li&gt;
&lt;li&gt;All the experience people contacted by recruiters&lt;/li&gt;
&lt;li&gt;No one good is applying to the website&lt;/li&gt;
&lt;li&gt;No one good is applying to the targeted job boards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why is &lt;em&gt;everyone&lt;/em&gt; passing on this job? Is it the bad pay? Bad benefits? The toxic company culture? The horrible tech stack (looking at &lt;em&gt;you&lt;/em&gt; React)? A combination of these things?&lt;/p&gt;

&lt;p&gt;Whatever it is, this job is probably pretty shitty. So it has made its way to the end of the pipeline, a sewer pipe, public job boards. I'm talking Indeed, Monster, Jobs . com, non-targeted public LinkedIn job posts, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you apply for this job?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I wouldn't recommend it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you get these jobs?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You don't want them.&lt;/p&gt;




&lt;p&gt;So that's the pipeline. The order isn't completely precise. Some companies will try the careers page first before paying for a recruiter. For example. The pipeline is basically the same across all companies, because it just makes the most business sense. Now that you understand it, you can work your way up to the earlier steps to get access to better jobs.&lt;/p&gt;

&lt;p&gt;Everything above this point has been very general, and is applicable to basically anyone. But the rest of this is going to get specific to programmers.&lt;/p&gt;

&lt;p&gt;It's important that more people know about this pipeline. Otherwise you end up with all the shitty React jobs making it to the sewage stage and people &lt;strong&gt;only seeing those&lt;/strong&gt; and thinking "everyone uses shitty React, guess I have to learn it", or "everyone else is hiring for shitty React, maybe our company should use it, even though it is easily the worst possible choice we could make".&lt;/p&gt;

&lt;p&gt;Which leads us to...&lt;/p&gt;




&lt;h2&gt;
  
  
  React is a litmus test for bad jobs
&lt;/h2&gt;

&lt;p&gt;Notice that you never see Vue or Rust jobs getting outsourced to India or the Philippines, because those are very desirable jobs. But shitty React jobs? Yeah, those flood the job boards, and eventually get outsourced because no one with any experience wants to use the worst technology choice.&lt;/p&gt;

&lt;p&gt;All the good non-react jobs get taken by qualified developers. Where I work, every team can pick what they want to use, and everyone picks Vue and is very thankful they get to. So I hire up Vue devs from my network (I run the Vue.js meetup group in Indianapolis). You'll never see our Vue jobs on a public board, because they all get filled internally or via recommendation.&lt;/p&gt;

&lt;p&gt;As a &lt;a href="https://dev.to/thejaredwilcurt/primary-responsibilities-of-ui-architects-1a7j"&gt;UI Architect&lt;/a&gt;, I've talked to many other experienced developers, in our community, or even at conferences I've attended or spoken at. I've found an interesting pattern among these groups. They use certain technologies, like React, as a kind of litmus test. The idea follows this logic:&lt;/p&gt;

&lt;p&gt;Because all other alternatives to React are better than it, picking it shows poor decision making skills. They went with the most &lt;em&gt;well known&lt;/em&gt; choice, without comparing it to anything else. This is a thoughtless approach. So if they are this bad at picking a technology, what other bad business, or management decisions will they make. They probably will not be a good place to work at in general.&lt;/p&gt;

&lt;p&gt;If no experienced people are willing to work in React, that means that only &lt;em&gt;inexperienced&lt;/em&gt; developers are building these projects. So any React project over 6 months old is basically guaranteed to be a spaghetti code train wreck. Which reinforces the decision of experienced developers to pass on these jobs.&lt;/p&gt;

&lt;p&gt;That's why you never see good jobs on public marketplaces, and why you see so many React jobs.&lt;/p&gt;

&lt;p&gt;I'm picking on React, because it's the worst choice for frontend you can make, so it is a fairly non-controversial whipping boy. But it's not alone. As you talk to people in the industry, you will hear about specific technologies people will never ever use again, no matter what the pay is. These vary greatly, but everyone has horror stories.&lt;/p&gt;




&lt;h2&gt;
  
  
  Advice for those entering the industry
&lt;/h2&gt;

&lt;p&gt;If you are new to development, and someone told you "Learn React, there are a lot of jobs for it"... well, you weren't &lt;em&gt;lied&lt;/em&gt; to, but you were somewhat misinformed.&lt;/p&gt;

&lt;p&gt;Yes, these jobs really do exist, but they're all going to be bad for your career. Your likelihood of getting to work with a really good senior developer is near 0%. Good devs don't take these jobs to begin with, or they leave them quickly. Without good mentorship in your early career, it will take you dramatically longer to get good at software development (and SWD is hard enough as it is).&lt;/p&gt;

&lt;p&gt;When you are ready to move on and work somewhere else, you might get stuck, trapped, in the largely underpaid React world. We're not at the stage yet were we just throw out any resume that mentions React, like we do with Flash or CoffeeScript, but those days are coming, and having it on your resume today does de-value it. Unless you are applying to a job that uses it. But again, you don't want those jobs. React is known for having hundreds of React-specific problems you need to solve that no other framework makes you deal with, due to how badly React is designed, and how they've consistently refused to learn from any of the other better frameworks that have come since it.&lt;/p&gt;

&lt;p&gt;You will spend years getting good at, and learning how to solve, problems that are created by the framework (React). This is 100% wasted time and effort. You will &lt;em&gt;never&lt;/em&gt; use that knowledge, those patterns, or skills again, after you switch to &lt;strong&gt;ANYTHING&lt;/strong&gt; else. This is why I devalue React developers compared to other candidates applying for a role.&lt;/p&gt;

&lt;p&gt;If I see someone with 5 years React experience, I have to ask "how many years do I need to subtract from that for it to be equivalent to my other candidates". Maybe, 3 years? That sounds about right, for all the time they've wasted learning shit that won't be of use here, or anywhere else for that matter. Compare that to someone with 3 years Vue or Svelte, experience, they are going to be better hires for whatever role I'm offering if it relates to frontend software development at all. Almost all of their time was spent learning how to develop software, not how to use their tools, or more accurately, work around the deficiencies of their tools.&lt;/p&gt;

&lt;p&gt;Further, because the virus that is React is so pervasive, and React developers are devalued, you WILL be paid less on average. It is harder to find someone with decent Vue experience, than it is to find someone with deep React experience. So Vue devs are higher valued, and paid more on average.&lt;/p&gt;

&lt;p&gt;Heed this warning, new devs.&lt;/p&gt;




&lt;p&gt;Good luck out there...&lt;/p&gt;

</description>
      <category>career</category>
      <category>hiring</category>
      <category>resume</category>
      <category>jobmarket</category>
    </item>
    <item>
      <title>Concentric Call Methodology: Organizing network calls in Web Apps</title>
      <dc:creator>The Jared Wilcurt</dc:creator>
      <pubDate>Wed, 21 May 2025 18:42:09 +0000</pubDate>
      <link>https://forem.com/thejaredwilcurt/organizing-network-calls-in-web-apps-with-concentric-call-methodology-186l</link>
      <guid>https://forem.com/thejaredwilcurt/organizing-network-calls-in-web-apps-with-concentric-call-methodology-186l</guid>
      <description>&lt;p&gt;&lt;strong&gt;Table of Contents:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Intro&lt;/li&gt;
&lt;li&gt;
Setting up the files

&lt;ul&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;li&gt;Each API gets a file&lt;/li&gt;
&lt;li&gt;Proxies and Environments&lt;/li&gt;
&lt;li&gt;Verbs live in one place&lt;/li&gt;
&lt;li&gt;Non-network data&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Benefits&lt;/li&gt;
&lt;li&gt;In conclusion&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;As a &lt;a href="https://dev.to/thejaredwilcurt/primary-responsibilities-of-ui-architects-1a7j"&gt;UI Architect&lt;/a&gt; one common problem space I've noticed across teams and repos is how to organize network calls in web apps.&lt;/p&gt;

&lt;p&gt;Without a plan in place, you are likely to naively just call &lt;code&gt;axios&lt;/code&gt; or &lt;code&gt;fetch&lt;/code&gt; from any random component, JS file, or global store. Or you may try moving all network calls into your global stores so at least there is some consistency and it gets them out of the components.&lt;/p&gt;

&lt;p&gt;We tend to think of network calls as just a simple function that has two results (success/failure). This thought process can lead to underestimating the need for putting in the effort to organize them better. You may easily end up with a ton of network calls spread across a codebase with repeated boilerplate and imports copy/pasted around. Not great! But fret not, you are are not alone!&lt;/p&gt;

&lt;p&gt;Below is a methodology you can adopt for new codebases, or start migrating existing codebases over to at your own pace. The teams where I work that have switched to this have all enjoyed it and much preferred it to their own past attempts. This encouragement from them is why I've wanted to document it here for others.&lt;/p&gt;

&lt;p&gt;I've named it the "Concentric Call Methodology", which will be explained at the end.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;First create these files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;/src/data/README.md
/src/data/localStorage.js
/src/data/apis/users.js
/src/services/index.js
/src/services/verbs.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below we will go over what goes in each file, and why they are split up this way.&lt;/p&gt;




&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;/src/data/README.md&lt;/code&gt; is a very important document. As with all programming patterns, if the tools (language/framework/linter/etc) aren't enforcing organization, then it must be communicated and enforced socially. This document clearly and succinctly conveys the approach to anyone working in your codebase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Concentric Call Methodology&lt;/span&gt;

&lt;span class="gu"&gt;## Data/Network Call Organization&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; Network calls are organized into subfolders for each API.
&lt;span class="p"&gt;*&lt;/span&gt; All network calls go through the main GET, PUT, POST, PATCH, DELETE verb functions.
&lt;span class="p"&gt;  *&lt;/span&gt; Located here: &lt;span class="sb"&gt;`src/services/verbs.js`&lt;/span&gt; - You should almost never need to touch these.
&lt;span class="p"&gt;*&lt;/span&gt; API specific files, like &lt;span class="sb"&gt;`src/data/apis/users.js`&lt;/span&gt;, will have 3 sections:
&lt;span class="p"&gt;  1.&lt;/span&gt; &lt;span class="gs"&gt;**Private verb functions**&lt;/span&gt; only to be used by that file.
&lt;span class="p"&gt;  1.&lt;/span&gt; &lt;span class="gs"&gt;**Endpoint functions**&lt;/span&gt; that can be called from anywhere and always return the &lt;span class="gs"&gt;**exact data**&lt;/span&gt; from the endpoint.
&lt;span class="p"&gt;  1.&lt;/span&gt; &lt;span class="gs"&gt;**Transform functions**&lt;/span&gt; that modify data before or after calling an endpoint function.

Non-network related functions dealing with data can also be stored in the &lt;span class="sb"&gt;`src/data`&lt;/span&gt; folder, such as &lt;span class="sb"&gt;`localStorage.js`&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Each API gets a file
&lt;/h3&gt;

&lt;p&gt;Assuming your app has many different API's it hits, you would have several files in the &lt;code&gt;src/data/apis&lt;/code&gt; folder. Where I work, all our apps hit the same "users" API. So we'll use that as an example of what files would look like in this folder:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/src/data/apis/users.js&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;usersApi&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;@/services/index.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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createApiVerbs&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;@/services/verbs.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * PRIVATE: DO NOT EXPORT.
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usersVerbs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createApiVerbs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usersApi&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;span class="cm"&gt;/**
 * ENDPOINTS
 */&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Get the currently logged in user's User object.
 *
 * @param  {object} params  Any URL params
 * @return {object}         A user object or empty object
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCurrentUser&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&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;usersVerbs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/current&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;message&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 getting user account.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;defaultReturn&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;span class="cm"&gt;/**
 * Get a list of all admins as user objects.
 *
 * @param  {object}   params  Any URL params
 * @return {object[]}         Array of admin user objects or empty array
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getAdmins&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&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;usersVerbs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/admins&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;message&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 getting list of admins.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;defaultReturn&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;span class="cm"&gt;/**
 * TRANSFORMS
 */&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Get a list of the last names of super users.
 *
 * @param  {object}   params  Any URL params
 * @return {string[]}         Array of super admin last names or empty array
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getSuperAdminLastNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&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;admins&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;getAdmins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&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;admins&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;admin&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;return&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;super&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;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;admin&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;return&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&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;p&gt;&lt;strong&gt;Things to note in this example:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We are exporting a simple function for each endpoint used in the app.&lt;/li&gt;
&lt;li&gt;If we need fresh data, but it needs mutated in some way, then we call a transform, so mutating of data never happens within the components/stores, but explicitly when obtaining it. From a "functional programming" perspective, this means we minimize the amount of time this data is mutable.&lt;/li&gt;
&lt;li&gt;From the apps perspective, calling a transform looks and feels identical to calling an endpoint. This is intentional. We isolate where the difference between the two matters exclusively to this file to reduce mental overhead throughout the rest of the app.&lt;/li&gt;
&lt;li&gt;If you are doing a PUT, POST, or PATCH, you may want to send your data into a transform to mutate it into the shape the endpoint wants before calling to the network function. This allows the component code to work with the data in the shape that makes sense for the UI, and to offload the needs of the API to a transform function.&lt;/li&gt;
&lt;li&gt;There are some imports at the top of this file, we'll look at those next.&lt;/li&gt;
&lt;li&gt;For APIs where you hit a lot of endpoints, you may want to create a folder with many files in it. Example: &lt;code&gt;/src/data/apis/users/foo.js&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Proxies and Environments
&lt;/h3&gt;

&lt;p&gt;For your app, you may deploy to multiple environments (DEV, TEST, PROD), and you may have endpoints you want to hit in your app that you need to proxy against when running your frontend locally.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/src/services/index.js&lt;/code&gt; exists to create the base URL for each endpoint you will hit. It deals with the environments &amp;amp; proxies for these endpoints. It will return the correct URL for them during runtime for you to use.&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ProxyMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;urlBuilder&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;@my-company/network-utilities&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;proxyMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProxyMap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inventoryAppUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;urlBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inventory-api&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usersApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;proxyMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addHostname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users-api&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;Where I work, we have a shared Network Utilities library so all apps can import common functions for our environments/proxies/auth.&lt;/p&gt;

&lt;p&gt;You may need to write your own helper functions for these, but they will be specific to your environment, so I can't help you with that. Feel free to either keep them in his &lt;code&gt;/src/services/index.js&lt;/code&gt; file or store them in your own &lt;code&gt;networkUtilities.js&lt;/code&gt; and import them in.&lt;/p&gt;




&lt;h3&gt;
  
  
  Verbs live in one place
&lt;/h3&gt;

&lt;p&gt;This is the most important part of this organizational structure. Ultimately, there is only ONE function in your entire app that makes a GET network call, and all GET requests must funnel through it. The same is true for all other verbs (PUT, POST, PATCH, DELETE).&lt;/p&gt;

&lt;p&gt;This means you have a singular point in your app where you can globally change anything about network calls.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/src/services/verbs.js&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&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;axios&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;globalAlertsStore&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;@/stores/globalAlerts.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * The global GET network utility function. All GET calls in the app
 * will pass through this function.
 *
 * @param {object} options
 * @param {string} options.url            The URL to call
 * @param {object} options.options        Axios options
 * @param {string} options.message        Message to display if an error occurs
 * @param {any}    options.defaultReturn  Generally an empty object or array, returned if network call fails
 */&lt;/span&gt;
&lt;span class="k"&gt;export&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;GET&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;options&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;defaultReturn&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;defaultReturn&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="s1"&gt;ERROR: All of the following are required:&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;url&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;defaultReturn&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;optionsWithCredentials&lt;/span&gt; &lt;span class="o"&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;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;withCredentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&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="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;optionsWithCredentials&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="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;defaultReturn&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="nf"&gt;globalAlertsStore&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;addAlert&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;error&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;defaultReturn&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="cm"&gt;/**
 * The global POST network utility function. All POST calls in the app
 * will pass through this function.
 *
 * @param {object} options
 * @param {string} options.url            The URL to call
 * @param {object} options.body           Axios body
 * @param {object} options.options        Axios options
 * @param {string} options.message        Message to display if an error occurs
 * @param {any}    options.defaultReturn  Generally an empty object or array, returned if network call fails
 */&lt;/span&gt;
&lt;span class="k"&gt;export&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;POST&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;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&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;defaultReturn&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;defaultReturn&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="s1"&gt;ERROR: All of the following are required:&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;url&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;defaultReturn&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;optionsWithCredentials&lt;/span&gt; &lt;span class="o"&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;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;withCredentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&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;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;optionsWithCredentials&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="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;defaultReturn&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="nf"&gt;globalAlertsStore&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;addAlert&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;error&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;defaultReturn&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="cm"&gt;/**
 * Creates API specific GET/POST/PATCH/PUT/DELETE verbs. These are basically
 * passthrough methods that prefix a provided base url to endpoints.
 *
 * @param  {string} baseUrl  The part of the url prior to the endpoint.
 * @return {object}          Object with API specific GET, POST, DELETE, etc methods
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createApiVerbs&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&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="cm"&gt;/**
     * All GET calls for a specific API go through this function.
     * @param  {object}         options
     * @param  {string}         options.url            The endpoint
     * @param  {object}         options.options        Axios options
     * @param  {string}         options.message        Human readable error message
     * @param  {(object|array)} options.defaultReturn  Empty array or object
     * @return {(object|array)}                        The data or defaultReturn
     */&lt;/span&gt;
    &lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &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;options&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;defaultReturn&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;url&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="s1"&gt;ERROR: URL is required&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;url&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="nc"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;baseUrl&lt;/span&gt; &lt;span class="o"&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;options&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;defaultReturn&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * All POST calls for a specific API go through this function.
     * @param  {object}         options
     * @param  {string}         options.url            The endpoint
     * @param  {object}         options.body           Axios body
     * @param  {object}         options.options        Axios options
     * @param  {string}         options.message        Human readable error message
     * @param  {(object|array)} options.defaultReturn  Empty array or object
     * @return {(object|array)}                        The data or defaultReturn
     */&lt;/span&gt;
    &lt;span class="na"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &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;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&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;defaultReturn&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;url&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="s1"&gt;ERROR: URL is required&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;url&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="nc"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;baseUrl&lt;/span&gt; &lt;span class="o"&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;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&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;defaultReturn&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;p&gt;This is a long file for a code example, so let's break it down.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We are importing &lt;code&gt;axios&lt;/code&gt;, a library for making network calls. It's very convenient, simplifying working with network calls, and makes mocking network calls in unit tests very easy. But you can import whatever you want, or just use the native &lt;code&gt;fetch&lt;/code&gt; API. It doesn't matter.&lt;/li&gt;
&lt;li&gt;Next we import our global alerts store, when adding alerts here, they will show up as toast messages in the UI. You will want to change this for however you handle alerts in your app.&lt;/li&gt;
&lt;li&gt;Next we have a GET and POST example. I didn't do all of them, but I think you get the point and can flesh these out as you need them.&lt;/li&gt;
&lt;li&gt;The GET and POST examples will always return either the data from the network response, or the &lt;code&gt;defaultReturn&lt;/code&gt;, which is just an empty data type matching what the API would return. Generally APIs for a single record return an object, so the &lt;code&gt;defaultReturn&lt;/code&gt; would be &lt;code&gt;{}&lt;/code&gt;, but for APIs returning many records you'd probably want &lt;code&gt;[]&lt;/code&gt; for the &lt;code&gt;defaultReturn&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Note:&lt;/strong&gt; You don't have to use the &lt;code&gt;defaultReturn&lt;/code&gt; approach at all! For our apps, this approach works well, and when you call &lt;code&gt;getSomeRecord()&lt;/code&gt; you know you'll always get data back, and don't need to worry about error handling at all, because the error is handled in the global &lt;code&gt;GET&lt;/code&gt; function and added as a toast. So your code just becomes: &lt;code&gt;const user = await getCurrentUser();&lt;/code&gt;. And that's it! But if you want to return promises instead and deal with them at a higher level, you can do that too.

&lt;ul&gt;
&lt;li&gt;Example: We have one app that the UI needs to know when a network call fails to change things in the UI beyond just showing a toast. In that case, the &lt;code&gt;GET&lt;/code&gt; function throws. Then all of the Endpoint calls (&lt;code&gt;getWhateverRecord&lt;/code&gt;) have a &lt;code&gt;catch&lt;/code&gt;. Instead of passing in a &lt;code&gt;defaultReturn&lt;/code&gt;, they return the default during the catch, or run other logic.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Notice the &lt;code&gt;withCredentials: true&lt;/code&gt;, we found a weird error/bug with our network calls and realized adding &lt;code&gt;withCredentials: true&lt;/code&gt; was all that was needed to fix it. Because we organized our code this way, we only had to add it to the global Verb functions, rather than all over the place.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;createApiVerbs&lt;/code&gt; helper lives here too. You've already seen it in use in the &lt;code&gt;users.js&lt;/code&gt; code example.&lt;/li&gt;
&lt;li&gt;Notice how each function here does runtime type checking of the inputs they expect, but &lt;strong&gt;only&lt;/strong&gt; of the inputs they actually use themselves. If a function is primarily just a passthrough, it doesn't worry about the other arguments, it just passes them along.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Non-network data
&lt;/h3&gt;

&lt;p&gt;Though this approach is primarily focused on organizing network calls, we created a &lt;code&gt;data&lt;/code&gt; folder, rather than a &lt;code&gt;network&lt;/code&gt; folder on purpose. Your app shouldn't care where the data it is getting comes from. So below we have one more example of retrieving and storing data, this time via &lt;code&gt;localStorage&lt;/code&gt; in the &lt;code&gt;/src/data/localStorage.js&lt;/code&gt; file.&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="cm"&gt;/**
 * This lists serves as documentation of all the current localStorage keys.
 * Forcing us to add values here helps prevent potential key overlap.
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localStorageKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;appTheme&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setLocalStorageValue&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="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;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;localStorageKeys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&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;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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid setLocalStorageValue key: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&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;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="nx"&gt;key&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;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getLocalStorageValue&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;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;localStorageKeys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&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;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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid getLocalStorageValue key: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&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;span class="k"&gt;return&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="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;If your app heavily uses localStorage, you may want to re-write this file to better match what makes sense for your app. It's mostly just here as an example.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;p&gt;The approach above forces your code into concentric rings of abstraction.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;At the lowest level is the global verb, like the &lt;code&gt;GET&lt;/code&gt; function.

&lt;ul&gt;
&lt;li&gt;All GET calls in your app will go through it.&lt;/li&gt;
&lt;li&gt;This is the only place that needs to worry about error handling (if following the example shown)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The next level up is the API Verbs wrapper. Like the &lt;code&gt;usersVerbs.GET&lt;/code&gt; example.

&lt;ul&gt;
&lt;li&gt;All GET calls to this specific API will go through this helper&lt;/li&gt;
&lt;li&gt;Any special params/tokens/keys that are always required for this endpoint can live with this helper in one place&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Next up is the actual endpoint calls like &lt;code&gt;getCurrentUser&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Because this is just a simple JavaScript function, it can be imported anywhere (components, stores, route guards, plugins, other JS files, etc).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Lastly transform functions like the &lt;code&gt;getSuperAdminLastNames&lt;/code&gt; example.

&lt;ul&gt;
&lt;li&gt;Isolates data mutations in a reusable helper function.&lt;/li&gt;
&lt;li&gt;Transforms are fantastic when dealing with 3rd party components that want data in a specific shape different from what your API provides.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your app only has like 2 network calls, clearly this approach will be overkill. But the apps I deal with tend to hit tons of network calls and at least a few different APIs.&lt;/p&gt;

&lt;p&gt;It bears repeating that the usage of this approach is dead simple:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getCurrentUser&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;@/data/apis/users.js&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;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;function &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;user&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;getCurrentUser&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;user&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;This results in the very positive developer experience I mentioned at the start. DX matters.&lt;/p&gt;

&lt;p&gt;We decided to set up our network calls with a "default return no-matter-what", and to put all error handling in the global verbs. It means when using these helper functions, you don't have to worry about anything. You know they are guaranteed to always return a value that is the correct type, and that you don't need to worry about errors.&lt;/p&gt;

&lt;p&gt;The error handling approach won't work if you need to do app-specific logic based on returned errors. But usually that is an indicator that you've designed something wrong (though not always). So feel free to tweak the examples if you need access to the error from a failed call.&lt;/p&gt;




&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;This post is not about a library. It isn't about how to write functions. It's about how to &lt;em&gt;think about&lt;/em&gt; the way you organize the code you write that deals with data. It presents a methodology you can apply to your projects. You are expected to take these above examples and adapt them to fit your needs.&lt;/p&gt;

&lt;p&gt;Nothing about this approach is framework, or even language, specific.&lt;/p&gt;

&lt;p&gt;As you try it out, be sure to comment below as to what things you changed. Your feedback will help evolve this methodology and improve it for others.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Credits:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"Concentric rings in sand" photo by &lt;a href="https://unsplash.com/@fabriziochiagano" rel="noopener noreferrer"&gt;Fabrizio Chiagano&lt;/a&gt; from Enkō-ji temple, Kyoto, Japan&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>softwaredevelopment</category>
      <category>webapp</category>
    </item>
    <item>
      <title>What's changed in Webdev in the past few years</title>
      <dc:creator>The Jared Wilcurt</dc:creator>
      <pubDate>Sun, 04 May 2025 05:48:09 +0000</pubDate>
      <link>https://forem.com/thejaredwilcurt/whats-changed-in-webdev-in-the-past-few-years-p7e</link>
      <guid>https://forem.com/thejaredwilcurt/whats-changed-in-webdev-in-the-past-few-years-p7e</guid>
      <description>&lt;p&gt;In the magical world of WebDev, things move fast. Because of this you should be aware of what the hot new things are, but more importantly, you should be looking for "boring technologies that just work". Practical tools will save you years of hassle and headeache. But most importantly is to kill technologies that serve no purpose any longer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Types&lt;/li&gt;
&lt;li&gt;JS Frameworks&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;li&gt;Bundling, treeshaking, live-reloading, HMR, etc&lt;/li&gt;
&lt;li&gt;Local JS runtimes/package managers&lt;/li&gt;
&lt;li&gt;Styling&lt;/li&gt;
&lt;li&gt;Linting&lt;/li&gt;
&lt;li&gt;Browsers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Types
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;JS is and always will be a dynamically typed language. There is a lot of power and convenience that comes with this. But with power comes dangers. There are those that dedicate themselves to JS and know it well enough to have no problem working around the danger and still taking advantage of this power.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;"TypeScript solves problems I don't have, in ways I don't like."&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
– Kyle Simpson, Author of the highly influential &lt;em&gt;"You Don't Know JS"&lt;/em&gt; book series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;But if you don't want to be an expert, or just want a tool to make sure you don't run into these problems, that's where TypeScript comes in.&lt;/li&gt;
&lt;li&gt;TS hype hit its peak a few years ago and has mostly plateaued. It solves some problems, but also creates &lt;a href="https://thejaredwilcurt.com/vue-snapshot-serializer/#types" rel="noopener noreferrer"&gt;a lot of new ones&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;Though adoption has slowed down, it is still extremely widely used, and there is wide support across the ecosystem and tooling for it. Though having to deal with so much tooling could be avoided by using the next option:&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Some people use &lt;a href="https://github.com/tjw-lint/eslint-config-tjw-jsdoc" rel="noopener noreferrer"&gt;JSDocs + ESLint-Plugin-JSDoc&lt;/a&gt; to solve the same problems differently without all the downsides TS comes with.

&lt;ul&gt;
&lt;li&gt;Svelte, for example, switched over to this approach, and many others (myself included) have as well.&lt;/li&gt;
&lt;li&gt;The JSDoc approach is fully compatible with the TypeScript Compiler (&lt;code&gt;tsc&lt;/code&gt;) and the TypeScript Engine (used in editors like VSCode), and is also recommended by the TS maintainers.&lt;/li&gt;
&lt;li&gt;JSDocs isn't a "cool" or "sexy" option, but it is very practical.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  JS Frameworks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt; is still the "most used", but is also quickly becoming quite unpopular.

&lt;ul&gt;
&lt;li&gt;It has consistently been the worst option every year since its inception. Despite massive improvements over the years, its just never been able to keep up with the rest of the landscape. For example, in the past ~5 years all JS frameworks have introduced some form of "signals-like" API. React was the last one to the party, releasing their attempt at this concept less than a year ago. Even Angular beat them to the punch. But with all these years, and all these other examples to look at and learn from, their API was still somehow the worst designed of them all.&lt;/li&gt;
&lt;li&gt;React, to this day has &lt;em&gt;still&lt;/em&gt;, never come up with a solution for how to deal with styling that doesn't have huge drawbacks.&lt;/li&gt;
&lt;li&gt;It has thousands of weird idiosyncrasies that require you to learn entire books of bandaid patterns to work around these react-exclusive problems.&lt;/li&gt;
&lt;li&gt;It's just plain slow and painful. The only people using it now are newbies that have never tried anything other than it, or people that are forced to by their jobs.&lt;/li&gt;
&lt;li&gt;The current trend for those stuck with using React is to try to obfuscate it as much as possible behind Next (mediocre meta framework). Next has had a lot of controversy recently though due to its security issues and the company that owns it being dicks or something, I don't know, I don't care about this ghetto-ass basic-bitch drama. Fuck anyone still using this trash.&lt;/li&gt;
&lt;li&gt;Because no one wants to deal with this garbage anymore, there are tons and tons of "red flag" React jobs that flood all the online job markets, which perpetuates the stereotype that everyone is hiring for it, which makes newbies think they need to learn it, and it makes other companies think it's a good idea to use it. It's basically the same problem we saw with PHP in the 2000's and early 2010's.&lt;/li&gt;
&lt;li&gt;Similarly I think the only path forward for React is for the community to relentlessly mock it, like we did PHP for over a decade until PHP finally fixed all of its issues. New generations need to be warned away from React the same way we warned them away from PHP.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Svelte&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;It has the most hype at the moment. Its main claim to fame is that it does not use a Virtual DOM, and instead requires a compilation step to produce render functions that mutate the DOM directly. It is the fastest JS framework. Its templating system isn't the best, but it's much better than JSX (commonly used by other JS Frameworks, like React, Solid, etc). It has a much smaller ecosystem. However, because it's mutating the DOM directly, it's more compatible with existing "vanilla js" libraries, which sort of helps. But ultimately you use a framework for the ergonomics, so having libraries built specifically in the same style with it in mind will feel better to use, there just isn't a lot of that.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Vue&lt;/strong&gt; - Still the best option, though hype has completely died off at this point.

&lt;ul&gt;
&lt;li&gt;Vue's hayday was back in 2018 where it out-paced React in GitHub stars and was the open-source darling saving us from a miserable life of using React and Angular (the worst, and second-worst frameworks that were consequently the most and second most used 🤦).&lt;/li&gt;
&lt;li&gt;Because of Vue having the best templating system in all of JS, despite using a virtual DOM, it ends up being ~99% the speed of Svelte. A very close second place. Vue renders 2-6 times faster than React. It's all component-dependent, but &lt;a href="https://old.reddit.com/r/vuejs/comments/1c5m24s/comparing_vuejs_and_reactjs_state_management_and/l0ap9yh/" rel="noopener noreferrer"&gt;Vue's worst case scenario will still be twice as fast as React's best-case scenario&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;They are currently trying to add in "vapor" mode, which would allow for toggling using the real or virtual DOM on a per-component basis. If that every comes out (who knows), they would be the only framework with this ability, unlocking speed advantages no other framework could offer.&lt;/li&gt;
&lt;li&gt;Vue can be compiled, just like Svelte, but it can also be used directly in a browser, via CDN for simpler use cases.&lt;/li&gt;
&lt;li&gt;It comes with the most important innovation in Frontend since the V8 engine, "Options API". This is a built-in way to write your components that is self-organizing. Solving the hardest problem in frontend, how to keep your code organized. I can go to any Vue component in any repo in the world, and as long as it's using Options API I will instantly know where everything is. This is the one feature every JS framework needs to steal from Vue, but as of yet, none have.&lt;/li&gt;
&lt;li&gt;It also offers access to atomic reactivity functions, which can even be used as a replacement to Options API if you prefer to write spaghetti code. I jest, but it is very useful to have this low level access to the world's most advanced reactivity engine. However, I would not recommend using it for components in an application, it is better used for rare advanced usecases or building libraries.&lt;/li&gt;
&lt;li&gt;Vue has the second largest ecosystem, after React. But more importantly, it has the best secondary libraries of any JS framework, which is the real reason you use it.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;State Management&lt;/strong&gt; - Pinia is a goddamn miracle. It is perfect. No notes. I would not change a single thing about it. It solves every problem I care about, and every problem I could imagine someone caring about. We do not deserve it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client-Side Routing&lt;/strong&gt; - Vue-Router. It is officially maintained by the Vue core team. It used to be slightly easier to use, but it's still by far the best solution in the JS landscape to this problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dev-Tools&lt;/strong&gt; - There is the browser dev tools, however you're better off pulling in the Vite-Vue-DevTools plugin. It's great, works with Vue, Pinia, Vue-Router, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing&lt;/strong&gt; - Vue-Test-Utils is really solid. Gives you great control for writing frontend unit tests. Pair it with the &lt;a href="https://thejaredwilcurt.com/vue-snapshot-serializer" rel="noopener noreferrer"&gt;Vue3-Snapshot-Serializer&lt;/a&gt; for a much easier way of writing unit tests that no other JS Framework can compare to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Component Documentation&lt;/strong&gt; - Vue-Doxen is as easy as it gets. It's just a Vue component that you pass your component in to and it does all the rest. Extremely extensible and customizable. Again, this is a Vue-exclusive benefit. No other JS framework has anything like this.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit:&lt;/strong&gt; Jest and Vitest are like 98% identical and are both the best option today, all other options are pretty shitty in comparison.

&lt;ul&gt;
&lt;li&gt;Jest is slightly faster&lt;/li&gt;
&lt;li&gt;Vitest is slightly slower, because it prioritizes correctness over speed (be thankful that it does)&lt;/li&gt;
&lt;li&gt;Vitest is architected in a way to take better advantage of "Shadow Realms", an upcoming JavaScript feature. Once added into Node.js, it will allow Vitest to go much faster than Jest&lt;/li&gt;
&lt;li&gt;Under the hood they share about 80% of the same code, and their API's are almost identical.&lt;/li&gt;
&lt;li&gt;I prefer Vitest, but both are good and practically the same.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;E2E:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cypress:&lt;/strong&gt; This was the go-to option for a long time, but has so many weird API choices that feel very much like the jQuery era of JavaScript it was created in. In the past 5 years Cypress has gotten much faster, which is great for those with large codebases already in it, but ultimately going from 50% as fast as Playwright to 80% as fast, is good, but still noticably slower.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Playwright:&lt;/strong&gt; This is honestly the only good option for E2E currently. The way it allows you to organize and write tests feels much more modern and cleaner. It's the fastest option, but ultimately it will still be orders of magnitude slower per-test compared to writing unit tests.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bundling, treeshaking, live-reloading, HMR, etc
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Webpack:&lt;/strong&gt; It's long dead, no one misses it. Technically it is still useful in the sense that it can handle like 5 different JS module systems. But now-a-days if you are using anything other than ESM you are doing it wrong.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vite:&lt;/strong&gt; From the creators of Vue.js, the best JS framework, come the best JS Build tool. It is extremely fast, because it only supports ESM. Under the hood much of the underlying tooling has been re-written in Rust to make it as fast as possible. The config tool for it is also pretty straightforward and easy to use. Vitest (mentioned in unit testing) is built on top of it, and uses the same config file, making everything simpler.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Local JS runtimes/package managers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;There are options like Bun and Deno, but 99% of people still just use Node.

&lt;ul&gt;
&lt;li&gt;Bun uses the same JS engine that Safari does, giving it some cool tricks. Its main purpose is to be as fast as possible. It's VC funded and &lt;a href="https://www.youtube.com/watch?v=lhcn07y0PqE" rel="noopener noreferrer"&gt;many are skeptical&lt;/a&gt; of its long term utility.&lt;/li&gt;
&lt;li&gt;Deno is from the same person that created Node, but this time "done right". What that means, is your imports can point to URL's, and everytime any module tries to access the file system or make a network call, it has to ask for permission first. This is much more security minded, but also a massive pain in the ass to deal with.&lt;/li&gt;
&lt;li&gt;Both Deno and Bun are basically just "Node, but with TypeScript support". In the sense that they can process TS to JS, or can use &lt;code&gt;.ts&lt;/code&gt; files directly without having to process them first. But the latest version of Node can also do this (kinda). When fed a &lt;code&gt;.ts&lt;/code&gt; file, Node will now just ignore all the TS syntax (as if they were comments), and execute it as though it were normal JS. Because of this, there's really no one using Bun or Deno, except for rare, specific usecases.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Package managers

&lt;ul&gt;
&lt;li&gt;Yarn - Dead, this was around for a few years. It came out with 12 features npm did not have and was much faster than npm. But then npm became faster than Yarn (and still is), and over time all Yarn-specific features got added to npm, so no one bothers to use Yarn anymore, as it does the same thing and is slower. Facebook created it, then handed it over to the OpenJS foundation to maintain it because they were done with it. If you are doing a monorepo (&lt;a href="https://dev.to/thejaredwilcurt/how-to-not-do-monorepos-n6i"&gt;which you probably shouldn't be&lt;/a&gt;, but if you are), there are options like npm Workspaces, Lerna, Turbo, and Yarn. They are all basically the same and most people will be fine with npm Workspaces, but each has some unique thing it does the rest don't, so that's really the only thing Yarn is still used for. Some people need its niche monorepo features.&lt;/li&gt;
&lt;li&gt;npm - Basically 100% of people use npm. It's fine, and works well enough.&lt;/li&gt;
&lt;li&gt;pnpm - This does a few things differently, mainly using less disk space than npm, but who cares you have so much disk space, this isn't the 90's. Performance wise, in some cases it is much faster than npm, but not in a way that you care about as a human. The percent of people using it is a rounding error. Its got some niche edge case uses, but most of them are deprecated or recommended not to use by the maintainers.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;a href="https://volta.sh" rel="noopener noreferrer"&gt;Volta&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;omg you guys, Volta is so fucking good&lt;/li&gt;
&lt;li&gt;Don't install Node or npm yourself, just install Volta&lt;/li&gt;
&lt;li&gt;Put this in your &lt;code&gt;package.json&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&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;"volta"&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;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"23.11.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;"npm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"11.3.0"&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;ul&gt;
&lt;li&gt;With this, when you &lt;code&gt;cd&lt;/code&gt; into your project, you will already be on the correct Node/npm.&lt;/li&gt;
&lt;li&gt;You can run &lt;code&gt;volta pin node@latest&lt;/code&gt; or &lt;code&gt;volta pin npm@latest&lt;/code&gt; and it will update the version in your &lt;code&gt;package.json&lt;/code&gt; for you. Works on all platforms. Highly recommend.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Styling
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sass&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Sass was used for decades as a simple tool for everyone. Though it was extremely powerful, most of the people using it were just trying to get these main features:

&lt;ul&gt;
&lt;li&gt;Variables and nesting in CSS&lt;/li&gt;
&lt;li&gt;File modularity and automatic concatenation/minification&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;We all use tools like Vite now that handle the concat/minify for us.&lt;/li&gt;

&lt;li&gt;CSS as a language has added in &lt;strong&gt;CSS custom properties&lt;/strong&gt;, which, are much more powerful than "variables", but can also be used as them. It also added in &lt;a href="https://caniuse.com/css-nesting" rel="noopener noreferrer"&gt;CSS nesting&lt;/a&gt; which has wide browser support now too.&lt;/li&gt;

&lt;li&gt;With these common problems solved outside of Sass, its utility has waned. So the maintainers of it pivoted and the &lt;em&gt;new&lt;/em&gt; versions of the Sass language are no longer focused on being "an easy tool for everyone to use" and instead are now "a complex and powerful tool for people building large complex CSS systems and frameworks".&lt;/li&gt;

&lt;li&gt;So it doesn't get used much anymore&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;Bootstrap was for over a decade the go-to solution for "please god, just do CSS for me, I don't want to learn CSS". But it has fallen out of favor, as &lt;strong&gt;Tailwind and component libraries&lt;/strong&gt; have taken its place.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Vue&lt;/strong&gt; has really good solutions for styling. It has component specific scoped styles, supports Sass, Tailwind, and CSS Modules.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Linting
&lt;/h2&gt;

&lt;p&gt;If you will be working in a project for more than 5 days, you need to set up linting, it will save you so much time and hassle. Any time you say "I don't get it, that should have worked, why doesn't that work", the first thing you should do is run the linter. If you are lucky it will solve your problem in a few seconds and save you 20 minutes of banging your head on the desk looking into why your code doesn't work just to find out you forgot a &lt;a href="https://i.imgur.com/9VyUtbu.jpeg" rel="noopener noreferrer"&gt;semi-colon&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ESLint is still the king, nothing else comes close. However, they've recently externalized all their style-based linting to a plugin called Stylistic. There are actually a bunch of really good plugins for ESLint to handle things like organizing ESM imports, accessibility, etc.

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://tjw-lint.github.io" rel="noopener noreferrer"&gt;Config Generator&lt;/a&gt; - Creates an ESLint config with a bunch of preset (TJW) options to make your life easier, while still giving total control right in the ESLint config file.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/antfu/eslint-config" rel="noopener noreferrer"&gt;AntFu Config&lt;/a&gt; - A JS function you import and run, passing options into. Handles a lot of cases, and offers some control, but not full control. May be too much of an abstraction for some.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Prettier - This is a technology that conflicts with all other technologies including itself. There really isn't anything it can do that ESLint can't do. It has a lot of really dumb default settings that don't match what anyone in the JS ecosystem uses, and most of its settings can't be changed. I seriously can't warn you against this enough, it causes so many problems with other tools. ESLint can auto-fix things on save as well if you want that.&lt;/li&gt;

&lt;li&gt;There are several other smaller linting tool alternatives. ALL of which are much &lt;em&gt;faster&lt;/em&gt; than ESLint, however, &lt;em&gt;none&lt;/em&gt; of them support the insanely large ecosystem of plugins ESLint has, which is really the reason you use it.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Browsers
&lt;/h2&gt;

&lt;p&gt;There's really only 3 browser engines in use now. Everything is either a derivative of Firefox or Chromium, or it's Safari. All Firefox based browsers will use Gecko and Spidermonkey. All Chromium based browsers will use Blink and V8. So you should manually test in at least one browser for each of those, and maybe Safari &lt;a href="https://i.imgur.com/bGR6UOl.jpeg" rel="noopener noreferrer"&gt;if you feel like it&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chromium - There's really only one option, &lt;a href="https://ungoogled-software.github.io/ungoogled-chromium-binaries/" rel="noopener noreferrer"&gt;Ungoogled Chromium&lt;/a&gt;. Despite there being a bunch of Chromium based browsers, this is the &lt;strong&gt;only one&lt;/strong&gt; that doesn't actively spy on you, or come with a massive amount of preinstalled junk and ads.&lt;/li&gt;
&lt;li&gt;Firefox - Sadly, Firefox recently removed all mentions of "we do not sell your data" from their license, website, and legal docs. Which... means they sell your data. Sad times. But fortunately there is &lt;a href="https://www.waterfox.net" rel="noopener noreferrer"&gt;Waterfox&lt;/a&gt;. Been using it for a while and it's literally just "better Firefox". Doesn't spy on you or sell your data. Has better Tab UI customization. No built in "Try our Mozilla VPN" or any other product ads. Better default settings overall. It's just better.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Kill your darlings
&lt;/h2&gt;

&lt;p&gt;Technologies come and go, new ones fix the problems of the old ones and we move on and evolve. This happens faster on the web than anywhere else, and so we must be vigilant not to get attached. Rip those bandaids off.&lt;/p&gt;

&lt;p&gt;The following are my recommendations based on being completely practical and objective, based on the pros/cons of these technologies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TypeScript is completely replaceable by JSDocs. It has all the same abilities (even enums/tuples), plus more, and none of the &lt;a href="https://thejaredwilcurt.com/vue-snapshot-serializer/#types" rel="noopener noreferrer"&gt;downsides&lt;/a&gt;. Some people don't like the way TS looks, some don't like the way JSDocs looks. But between the two, you can code-fold the JSDocs comment blocks (Ctrl+K,Ctrl+1) and you don't need to look at them. So even for this non-practical, personal preference, they win out.&lt;/li&gt;
&lt;li&gt;Webpack is slow and hard to configure and use. Vite is faster, simpler, and easier to maintain. It has become the recommend approach by all major JS frameworks.&lt;/li&gt;
&lt;li&gt;React is so bad that if you use it I will make fun of you, just use anything else. Vue is the obvious winner, but as long as you aren't using React, I really don't care what you are doing instead.

&lt;ul&gt;
&lt;li&gt;Except Web components. These never got off the ground. There's no good tooling or options for them and they just flat out don't work in production.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;nvm&lt;/code&gt;, &lt;code&gt;nodist&lt;/code&gt;, &lt;code&gt;n&lt;/code&gt;, and &lt;code&gt;nvm-windows&lt;/code&gt; are all buggy, and platform specific. Just use Volta, it's cross-platform, stable, reliable, and doesn't require you to manually switch Node versions. You'll never be on the wrong Node version again, it's so good.&lt;/li&gt;

&lt;li&gt;Yarn is long past it's prime. npm is faster and can do all the same stuff, and everyone else that switched to Yarn has switched back to npm.&lt;/li&gt;

&lt;li&gt;Cypress has been usurped. Playwright is much faster, easier to use, and allows for better code organization and test writing.&lt;/li&gt;

&lt;li&gt;There are a lot of unit testing tools (Jasmine, Chai, Ava, Tape, QUnit, etc) and they are all very dated compared to Jest and Vitest. Just use Vite and Vitest together. They use the same config file, so it's much simpler.&lt;/li&gt;

&lt;li&gt;Unless you are doing a very complex CSS framework, you're better off moving away from Sass.&lt;/li&gt;

&lt;li&gt;Uninstall Prettier from your editor. Disabling it probably won't be enough, it is extremely aggressive about doing it's one job (conflicting with other tools). Get rid of it. Use ESLint, it's worth the extra time to set it up, you'll get more out of it. You can also have multiple ESLint config files if you want to run a subset of your linting options for faster linting of specific folders with unique npm script commands.&lt;/li&gt;

&lt;li&gt;It's a good day to switch your browser. Try one that actually respects you.&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>node</category>
    </item>
    <item>
      <title>How to NOT do monorepos</title>
      <dc:creator>The Jared Wilcurt</dc:creator>
      <pubDate>Sun, 04 May 2025 05:17:29 +0000</pubDate>
      <link>https://forem.com/thejaredwilcurt/how-to-not-do-monorepos-n6i</link>
      <guid>https://forem.com/thejaredwilcurt/how-to-not-do-monorepos-n6i</guid>
      <description>&lt;h2&gt;
  
  
  Who &lt;em&gt;actually&lt;/em&gt; needs a monorepo?
&lt;/h2&gt;

&lt;p&gt;Monorepos exist to solve the problems that arise when you you have deeply coupled and interconnected projects.&lt;/p&gt;

&lt;p&gt;For example, Vue.js has many libraries that depend on it, like Vue-Router, Pinia, Vue-I18N, Vue-DevTools, Vue Test-Utils, etc. So when tweaking the internals of how Vue works, it's important to know that this new version of Vue won't break any of these other libraries, &lt;em&gt;before&lt;/em&gt; doing a new Vue release.&lt;/p&gt;

&lt;p&gt;Another example is Jest, a unit-testing library. It solves dozens of unique problems around unit testing. And consequently those unique problems have been isolated into their own independent repos solely focused on solving their one problem in a version controlled way, like Snapshot testing for example. These other libraries all live in the same monorepo as Jest to make sure that as each is updated, they all work together happily! Yay!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why you don't want a monorepo
&lt;/h2&gt;

&lt;p&gt;Though they do solve the problems outlined above they come with some drawbacks. In the past monorepos were notorious for not being able to run on Windows machines. However, with npm Workspaces, this is no longer the case. But if you are using a different monorepo tool (Yarn, Lerna, Turbo, etc). You &lt;em&gt;will&lt;/em&gt; have this problem. They just don't play nice on Windows computers. But you don't use Windows, and worse you're a selfish piece of shit that doesn't care about others, so this lack of support doesn't bother you (seriously, just use npm Workspaces, they're good).&lt;/p&gt;

&lt;p&gt;The real issue with monorepos is they have a ton of added complexity. It makes sense, you are combining all of the project setup complexity of all other projects into one system. So that requires it to be more complex than any of them would be on their own. Having multiple nested &lt;code&gt;package.json&lt;/code&gt; files in a project also can cause issues with 3rd party tooling and editors. It's not always obvious where a dependency should be installed either.&lt;/p&gt;

&lt;p&gt;Initial setup of the repo is also much more cumbersome for new devs, as it requires a massive &lt;code&gt;npm install&lt;/code&gt; to create a huge shared &lt;code&gt;node_modules&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Abstracting &lt;code&gt;npm scripts&lt;/code&gt; across all your repos is more of a pain.&lt;/p&gt;

&lt;p&gt;Setting up publishing of all packages at the same time is a benefit but also complex, and results in much uglier and harder to use GitHub Releases pages.&lt;/p&gt;

&lt;p&gt;etc. etc. etc.&lt;/p&gt;

&lt;p&gt;It's a technology, it has pros and cons, big whoop.&lt;/p&gt;

&lt;p&gt;Some projects really do justify the need for this extra effort and hassle, but if you can avoid it, you should try your best to.&lt;/p&gt;

&lt;h2&gt;
  
  
  You probably don't need a mono repo.
&lt;/h2&gt;

&lt;p&gt;Here's a case where you might &lt;em&gt;think&lt;/em&gt; you need one.... but nehhhh you don't.&lt;/p&gt;

&lt;p&gt;Let's say you have a component library. You'll need to be able to build this library to a "dist" folder, and publish it to npm (including the &lt;code&gt;package.json&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;You'll also need to create a documentation website. As you write a new component, it would be nice to document it as you go, so you can see the component live in the docs site locally and play with it as you build it to make sure it works.&lt;/p&gt;

&lt;p&gt;This means that you will be updating the docs site and the component library in the same branch at the same time. Pretty convenient. But the docs site needs it's own build process. So it can create a "site" folder of static assets that gets deployed.&lt;/p&gt;

&lt;p&gt;How can we solve this &lt;em&gt;without&lt;/em&gt; all of the headache of a monorepo? How can we do this in a simpler way?&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;In this scenario the solution is actually pretty easy. Use multiple Vite config files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;vite.config.lib.js&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;This config file has all the build options for the &lt;code&gt;/lib&lt;/code&gt; folder to create the &lt;code&gt;/dist&lt;/code&gt; folder. It also has all the Vitest unit testing options for the component library set up.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;vite.config.docs.js&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;This config file has all the build options for the &lt;code&gt;/docs&lt;/code&gt; folder to create the &lt;code&gt;/site&lt;/code&gt; folder. It also has options related to running the server locally for development.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;In your &lt;code&gt;package.json&lt;/code&gt; you will have different npm Scripts: like:
&lt;/li&gt;

&lt;/ul&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;"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="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite --config vite.config.docs.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build:docs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite build --config vite.config.docs.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build:lib"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite build --config vite.config.lib.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vitest --config vite.config.lib.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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Then you can run &lt;code&gt;npm start&lt;/code&gt; to start the docs site, or &lt;code&gt;npm run build&lt;/code&gt; to build both the docs site and the library.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Benefits/Drawbacks
&lt;/h2&gt;

&lt;p&gt;This system is dramatically simpler to deal with. It's just a few config files.&lt;/p&gt;

&lt;p&gt;However, the downside is you have one &lt;code&gt;package.json&lt;/code&gt; for everything, and you'll need to put everything in the &lt;code&gt;"devDependencies"&lt;/code&gt; section, unless you want users of your library to receive them when they &lt;code&gt;npm install&lt;/code&gt; your library.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>monorepos</category>
    </item>
    <item>
      <title>Zorin setup</title>
      <dc:creator>The Jared Wilcurt</dc:creator>
      <pubDate>Mon, 24 Mar 2025 00:28:31 +0000</pubDate>
      <link>https://forem.com/thejaredwilcurt/zorin-setup-4jpf</link>
      <guid>https://forem.com/thejaredwilcurt/zorin-setup-4jpf</guid>
      <description>&lt;h2&gt;
  
  
  General OS Setup
&lt;/h2&gt;

&lt;p&gt;This first section would be applicable to anyone&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove Firefox because &lt;a href="https://arstechnica.com/tech-policy/2025/02/firefox-deletes-promise-to-never-sell-personal-data-asks-users-not-to-panic/" rel="noopener noreferrer"&gt;they sell your data&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;You can uninstall it from the store, but I don't take chances when it comes to spyware. This is the command to fully remove it:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo apt purge firefox -f&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;I think the newer version of Zorin comes with Brave? Which is &lt;a href="https://old.reddit.com/r/24hoursupport/wiki/productstoavoid#wiki_brave" rel="noopener noreferrer"&gt;10000000% spyware&lt;/a&gt;. Easily the worst possible browser you could use. So absolutely remove that shit.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo apt purge brave-browser brave-keyring&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo apt autoremove&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo rm /etc/apt/sources.list.d/brave-browser-*.list&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rm -rf ~/.config/BraveSoftware&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rm -rf ~/.cache/BraveSoftware&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rm -rf ~/.local/share/keyrings/brave-browser*&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Install Waterfox via the store

&lt;ul&gt;
&lt;li&gt;It's literally just "Better Firefox"&lt;/li&gt;
&lt;li&gt;Better default settings, no ads built in ("Mozilla VPN", etc)&lt;/li&gt;
&lt;li&gt;Has some fun UI settings, like changing the look of the tabs&lt;/li&gt;
&lt;li&gt;Just go through all the settings and change stuff however you like&lt;/li&gt;
&lt;li&gt;Or you can try &lt;strong&gt;Floorp&lt;/strong&gt; or &lt;strong&gt;Ungoogled Chromium&lt;/strong&gt;. Those are the only 3 browser's I'd recommend that actually respect you, and are easy to use.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Settings &amp;gt; Users &amp;gt; Avatar&lt;/li&gt;
&lt;li&gt;Open Zorin Appearance

&lt;ul&gt;
&lt;li&gt;Start with the 3rd layout&lt;/li&gt;
&lt;li&gt;Theme: Blue, Dark&lt;/li&gt;
&lt;li&gt;Icons - Dark Reversal Orange

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pling.com/p/1340791" rel="noopener noreferrer"&gt;https://www.pling.com/p/1340791&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Effects: idk&lt;/li&gt;
&lt;li&gt;Desktop: enable all, standard&lt;/li&gt;
&lt;li&gt;Windows: Centered, Super, Attached, no idea, Right, toggle max, minimize, menu, click to focus, no idea&lt;/li&gt;
&lt;li&gt;Interface: No idea, off, off&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Wallpaper

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://i.imgur.com/rSxpVtb.jpeg" rel="noopener noreferrer"&gt;https://i.imgur.com/rSxpVtb.jpeg&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Taskbar settings

&lt;ul&gt;
&lt;li&gt;Style: intellihide off, override on, 70, dynamic on (all windows, 100)&lt;/li&gt;
&lt;li&gt;Position: Apply to all mon, bottom, 48, 100, left. All visible except Show Apps Button.&lt;/li&gt;
&lt;li&gt;Behavior: all checked, ungrouped (160, off, off), preview (on, 200, on)&lt;/li&gt;
&lt;li&gt;Action: no clue, keep orig: off&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If you want to set some programs to launch on start up install "Ignition" from the store.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt install tts-mscorefonts-installer&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;This gives you common Windows fonts, only needed for software that expects you to have them, like some Windows programs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Disable multi-touch gestures, like pinch/zoom or 3-finger-swipe to show all windows. It keeps 2 finger scroll, and 3 finger middle-click.

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://extensions.gnome.org/extension/8066/disable-gestures-wayland/" rel="noopener noreferrer"&gt;https://extensions.gnome.org/extension/8066/disable-gestures-wayland/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Unfortunately NO operating systems give you control over how rounded the corners are on the windows. However, this is Linux, so if you want something done, you can just do it yourself.

&lt;ul&gt;
&lt;li&gt;Create &lt;code&gt;~/.config/gtk-3.0/gtk.css&lt;/code&gt; and put this in it:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;* { border-radius: 4px; } decoration, window { border-radius: 0px; }&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Install ArcMenu to replace the start menu

&lt;ul&gt;
&lt;li&gt;This is a fork of ZorinMenu that better recreates the Windows start menu&lt;/li&gt;
&lt;li&gt;&lt;a href="https://extensions.gnome.org/extension/3628/arcmenu/" rel="noopener noreferrer"&gt;https://extensions.gnome.org/extension/3628/arcmenu/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Use this settings file, &lt;code&gt;tjw-arc-menu&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[/]
arcmenu-extra-categories-links=[(0, true), (1, false), (2, false), (3, false), (4, false)]
arcmenu-extra-categories-links-location='Top'
avatar-style='Square'
context-menu-shortcuts=[['ArcMenu Settings', '/home/owner/.local/share/gnome-shell/extensions/arcmenu@arcmenu.com/icons/arcmenu-logo-symbolic.svg', 'ArcMenu_Settings'], ['Panel Extension Settings', 'application-x-addon-symbolic', 'ArcMenu_PanelExtensionSettings'], ['Separator', 'list-remove-symbolic', 'ArcMenu_Separator'], ['Power Options', 'system-shutdown-symbolic', 'ArcMenu_PowerOptions'], ['Show Desktop', 'computer-symbolic', 'ArcMenu_ShowDesktop']]
custom-menu-button-icon-size=34.0
default-menu-view='Frequent_Apps'
disable-scrollview-fade-effect=true
disable-user-avatar=false
distro-icon=17
enable-horizontal-flip=false
enable-standlone-runner-menu=false
extra-categories=[(3, true), (1, true), (0, false), (4, true), (2, true)]
hide-overview-on-startup=false
menu-background-color='rgb(30,37,41)'
menu-border-color='rgb(42,52,57)'
menu-border-radius=0
menu-button-appearance='Icon'
menu-button-icon='Distro_Icon'
menu-foreground-color='rgb(189,230,251)'
menu-item-active-bg-color='rgba(189,230,251,0.15)'
menu-item-active-fg-color='rgb(189,230,251)'
menu-item-hover-bg-color='rgba(189,230,251,0.08)'
menu-item-hover-fg-color='rgb(189,230,251)'
menu-item-icon-size='Extralarge'
menu-layout='Default'
menu-separator-color='rgba(99,99,98,0.56)'
menu-themes=[['ArcMenu Style', 'rgba(48,48,49,0.98)', 'rgb(223,223,223)', 'rgb(60,60,60)', '1', '14', '11', 'rgba(255,255,255,0.1)', 'rgb(21,83,158)', 'rgb(255,255,255)', 'rgb(25,98,163)', 'rgb(255,255,255)'], ['Simply Dark', 'rgba(28,28,28,0.98)', 'rgb(211,218,227)', 'rgb(63,62,64)', '1', '14', '11', 'rgb(63,62,64)', 'rgba(238,238,236,0.08)', 'rgb(255,255,255)', 'rgba(228,228,226,0.15)', 'rgb(255,255,255)'], ['Dark Blue', 'rgb(30,37,41)', 'rgb(189,230,251)', 'rgb(41,50,55)', '1', '14', '11', 'rgba(99,99,98,0.56)', 'rgba(189,230,251,0.08)', 'rgb(189,230,251)', 'rgba(189,230,251,0.15)', 'rgb(189,230,251)'], ['Light Blue', 'rgb(245,247,250)', 'rgb(18,51,84)', 'rgba(18,51,84,0.2)', '1', '14', '11', 'rgba(18,51,84,0.15)', 'rgba(18,51,84,0.08)', 'rgb(18,51,84)', 'rgba(18,51,84,0.15)', 'rgb(18,51,84)'], ['TJW-Zorin', 'rgb(30,37,41)', 'rgb(189,230,251)', 'rgb(42,52,57)', '1', '0', '11', 'rgba(99,99,98,0.56)', 'rgba(189,230,251,0.08)', 'rgb(189,230,251)', 'rgba(189,230,251,0.15)', 'rgb(189,230,251)']]
multi-monitor=true
override-menu-theme=true
pinned-app-list=['Files', 'org.gnome.Nautilus', 'org.gnome.Nautilus.desktop', 'Terminal', 'org.gnome.Terminal', 'org.gnome.Terminal.desktop', 'ArcMenu Settings', '/home/owner/.local/share/gnome-shell/extensions/arcmenu@arcmenu.com/icons/arcmenu-logo-symbolic.svg', 'gnome-extensions prefs arcmenu@arcmenu.com', 'Git Cola', '', 'com.github.git_cola.git-cola.desktop']
pop-folders-data={'Library Home': 'Library Home', 'Utilities': 'Utilities'}
prefs-visible-page=0
search-entry-border-radius=(true, 25)
searchbar-default-top-location='Bottom'
show-activities-button=false
show-hidden-recent-files=true
vert-separator=true
windows-disable-frequent-apps=false
windows-disable-pinned-apps=false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Developer stuff
&lt;/h2&gt;

&lt;p&gt;The rest of this is my setup for programming related things.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install VSCodium via store even though you'll never use it&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install Sublime via &lt;code&gt;.deb&lt;/code&gt; file from website&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.sublimetext.com/download" rel="noopener noreferrer"&gt;https://www.sublimetext.com/download&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Preferences &amp;gt; Keybindings
&lt;/li&gt;
&lt;/ul&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"keys"&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;"ctrl+tab"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next_view"&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;"keys"&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;"ctrl+shift+tab"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prev_view"&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;"keys"&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;"ctrl+alt+up"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"select_lines"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"args"&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;"forward"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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;span class="nl"&gt;"keys"&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;"ctrl+alt+down"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"select_lines"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"args"&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;"forward"&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="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;/li&gt;
&lt;li&gt;&lt;p&gt;Install git cola from the store&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tweak terminal colors&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add &lt;code&gt;"\C-i": menu-complete&lt;/code&gt; to &lt;code&gt;~/.inputrc&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Git stuff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto fix &lt;code&gt;git push&lt;/code&gt; needing upstream set

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git config --global push.default current&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git config --global user.email "TheJaredWilcurt@users.noreply.github.com"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git config --global user.name "The Jared Wilcurt"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create SSH key file, run this, enter &amp;gt; enter &amp;gt; enter

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ssh-keygen -t ed25519 -C "TheJaredWilcurt@users.noreply.github.com"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Start SSH Agent

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;eval "$(ssh-agent -s)"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Add SSH keys

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ssh-add ~/.ssh/id_ed25519&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Run this and copy the output to clipboard

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cat ~/.ssh/id_ed25519.pub&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/settings/ssh" rel="noopener noreferrer"&gt;https://github.com/settings/ssh&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;New SSH &amp;gt; Title, Type: Auth, Key: paste &amp;gt; Add SSH Key&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install &lt;code&gt;dconf-editor&lt;/code&gt; from the store&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;org/gnome/desktop/wm/keybindings/move-to-workspace-up&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org/gnome/desktop/wm/keybindings/move-to-workspace-down&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Remove the keybinding from both of these, so Sublime can use ctrl+alt+up/down.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To get Ctrl+Tab and Ctrl+Shift+Tab to work in the terminal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gsettings set org.gnome.Terminal.Legacy.Keybindings:/org/gnome/terminal/legacy/keybindings/ next-tab '&amp;lt;Primary&amp;gt;Tab'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gsettings set org.gnome.Terminal.Legacy.Keybindings:/org/gnome/terminal/legacy/keybindings/ prev-tab '&amp;lt;Primary&amp;gt;&amp;lt;Shift&amp;gt;Tab'&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>cli</category>
      <category>linux</category>
      <category>privacy</category>
    </item>
    <item>
      <title>Desktop apps for Windows XP in 2025</title>
      <dc:creator>The Jared Wilcurt</dc:creator>
      <pubDate>Mon, 10 Feb 2025 21:38:16 +0000</pubDate>
      <link>https://forem.com/thejaredwilcurt/desktop-apps-for-windows-xp-in-2025-2cpc</link>
      <guid>https://forem.com/thejaredwilcurt/desktop-apps-for-windows-xp-in-2025-2cpc</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Inspired by the &lt;a href="https://www.youtube.com/watch?v=L7IyT2x10mg" rel="noopener noreferrer"&gt;Action Retro&lt;/a&gt; YouTube channel trying to get Spotify to run on Windows XP, I thought I'd share a quick walk through of using NW.js for Windows XP development.&lt;/p&gt;

&lt;p&gt;NW.js is a modified Chromium browser with Node.js built in. It has an older "Long Term Support" (LTS) release (v0.14.7) that supports "Legacy Operating Systems", like Windows XP and OSX 10.6.&lt;/p&gt;

&lt;p&gt;However, it is pretty old at this point and has some caveats. But we'll get there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boot up XP
&lt;/h2&gt;

&lt;p&gt;First off I'm going to boot up my old Win Pro SP3 virtual machine. I'd recommend setting up your own, there are guides online for that, or just using real hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download NW.js
&lt;/h2&gt;

&lt;p&gt;Go to this archive for version 0.14.7:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://dl.nwjs.io/v0.14.7" rel="noopener noreferrer"&gt;http://dl.nwjs.io/v0.14.7&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll explain the different flavors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"nwjs-sdk-symbol*" and "nwjs-symbol*" files are for advanced use cases, you won't need these.&lt;/li&gt;
&lt;li&gt;"nwjs-sdk-v0.14.7*" Is NW.js with Chromium dev tools built in&lt;/li&gt;
&lt;li&gt;"nwjs-v0.14.7*" Is the same thing, just without the dev tools, so it is slightly smaller. This is for distribution to end users&lt;/li&gt;
&lt;li&gt;Then they'll have the operating system (win, lin, osx)&lt;/li&gt;
&lt;li&gt;And then the architecture, 32-Bit (ia32) and 64-Bit (x64)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I assume you'll want &lt;code&gt;nwjs-sdk-v0.14.7-win-ia32.zip&lt;/code&gt;. But if you plan on distributing this for others to download, they probably won't need the dev tools, so you can use the slightly smaller version for them.&lt;/p&gt;

&lt;p&gt;The 32-bit version will run on both 32 and 64-bit versions of Windows just fine. It will also run on XP, Vista, 7, 8, 8.1, 10, 11, and 12, and likely anything else in the future as Microsoft has always prioritized backwards compatibility. But who knows, 11 and 12 are so bad I wouldn't be surprised at what they do anymore. Honestly, having to use 11 so much recently and then booting up this XP VM is just pissing me off at much better XP is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting it up
&lt;/h2&gt;

&lt;p&gt;You downloaded a zip file, good job! You should be able to open it and drag the folder out to your desktop or wherever. Feel free to rename the folder from "nwjs-sdk-v0.14.7-win-ia32" to "MyApp" or whatever.&lt;/p&gt;

&lt;p&gt;Inside the folder is all the files NW.js needs to run, it doesn't need installed, it works sort of like a portable app. So you can just double-click on &lt;code&gt;nw.exe&lt;/code&gt; to see a window pop up, then you can close the window.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;nw.exe&lt;/code&gt; file can be renamed to whatever you want, &lt;code&gt;MyApp.exe&lt;/code&gt; for example, and you can even use a tool like &lt;a href="https://www.angusj.com/resourcehacker" rel="noopener noreferrer"&gt;ResourceHacker&lt;/a&gt; to edit it and change the icon to any ICO file you want. You can grab a random ICO file from the &lt;a href="https://www.iconarchive.com" rel="noopener noreferrer"&gt;IconArchive&lt;/a&gt; website, or use a tool like &lt;a href="https://greenfishsoftware.org/gfie.php" rel="noopener noreferrer"&gt;Greenfish Icon Editor&lt;/a&gt; to convert any image file to an ICO. All of that runs fine on Windows XP+.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an app
&lt;/h2&gt;

&lt;p&gt;Inside your "MyApp" folder, create a new folder called &lt;code&gt;package.nw&lt;/code&gt;. All of your code and files will live inside this folder. Which makes it easy to copy it around to other versions of NW.js later. As long as the &lt;code&gt;package.nw&lt;/code&gt; folder is next to the &lt;code&gt;nw.exe&lt;/code&gt; (or whatever you renamed it to), it will work.&lt;/p&gt;

&lt;p&gt;Then, inside the &lt;code&gt;package.nw&lt;/code&gt; folder create a &lt;code&gt;package.json&lt;/code&gt; file. This is the first thing the &lt;code&gt;nw.exe&lt;/code&gt; file will look for when it launches. It tells it what to do next. Inside the file there are only 2 required fields so we'll start with those:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; - This is the name of your app. It is required because any time you open NW.js, Chromium will control showing a window, and Chromium needs to make a bunch of user-specific files. So for Windows XP that would be at &lt;code&gt;C:\Documents and Settings\YourUserName\Local Settings\Application Data\my-app&lt;/code&gt;. The "my-app" part is whatever you put in this &lt;code&gt;name&lt;/code&gt; field. It must be a url and file-system safe name. I'd recommend all lowercase and hyphens instead of spaces.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main&lt;/code&gt; - This tells NW.js what to load in the window when it launches. Usually you'd set it to &lt;code&gt;index.html&lt;/code&gt; and then create that file and put whatever you want in it to make your app. However you can also set it to a URL, so we'll start there, as it will show an XP specific problem we'll need to solve.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;MyApp\package.nw\package.json&lt;/code&gt;&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;"my-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://google.com"&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;With that in place, now when you run &lt;code&gt;nw.exe&lt;/code&gt;, it will open a window and take you to Google.com. Or at least, that's what it &lt;em&gt;would&lt;/em&gt; do, but instead you'll see this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ir0c4ln7oxhgorwza5q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ir0c4ln7oxhgorwza5q.png" alt="Your clock is ahead warning" width="569" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chromium dropped support for XP a long time ago. So we must use a very old version that still works with XP. However, the certificate it ships with is now long expired.&lt;/p&gt;

&lt;p&gt;We can work around this by adding one more item to the &lt;code&gt;package.json&lt;/code&gt; 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;"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-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://google.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"chromium-args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--ignore-certificate-errors"&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;Save that, and re-run &lt;code&gt;nw.exe&lt;/code&gt; and &lt;em&gt;now&lt;/em&gt; it should launch a window with Google loaded inside it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9taxgzuqog0xi1a17t9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9taxgzuqog0xi1a17t9.png" alt="Google.com successfully loaded in the window" width="667" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a bunch of other settings you can put in the &lt;code&gt;package.json&lt;/code&gt;, including adjusting the starting window size and position. More information can be found in the docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nwjs.readthedocs.io/en/latest/References/Manifest%20Format/" rel="noopener noreferrer"&gt;https://nwjs.readthedocs.io/en/latest/References/Manifest%20Format/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Version stuff
&lt;/h2&gt;

&lt;p&gt;At this point you can make whatever you want. Well kind of. NW.js v0.14.7 was released on 2016-07-22 and comes with Chromium 50 and Node.js 5.11.1. Both of these are very old now. If you are used to modern webdev tooling, writing code for them will be more difficult.&lt;/p&gt;

&lt;p&gt;Fortunately we have tools like &lt;a href="https://postcss.org" rel="noopener noreferrer"&gt;PostCSS&lt;/a&gt; and &lt;a href="https://babeljs.io" rel="noopener noreferrer"&gt;Babel&lt;/a&gt;, that let you target your specific Browser version, and they'll do their best to transpile and polyfill your code to work with that version. This alone will do a lot of the heavy lifting for you if you are working with a lot of code. However, if you are just writing out a few HTML, CSS, and JS files, then that would be overkill and you can just figure out what code to use by consulting &lt;a href="https://caniuse.com" rel="noopener noreferrer"&gt;CanIUse.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Be aware, that many new web technologies have been added to the browser since 2016. Some specific websites, may not load. For example, using &lt;code&gt;"main": "https://spotify.com"&lt;/code&gt; will load their site, but it will tell you that your browser doesn't support Widevine. Widevine is a DRM technology they use for playing audio files that wasn't added into Chromium until years after they dropped support for XP. So sadly, you can't just point to any website and expect it to work. Though, most sites actually still work with this older version of Chromium, overtime more and more will adopt new technologies not available in this old version of Chromium. The march of progress is sad for our friend XP. Fortunately, for just browsing the web &lt;a href="https://www.mypal-browser.org" rel="noopener noreferrer"&gt;MyPal&lt;/a&gt;, an XP focused fork of Firefox, is available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your own app
&lt;/h2&gt;

&lt;p&gt;In the example above we just loaded a website, but as mentioned, you can also create your own apps from scratch. Let's do a quick example.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MyApp\package.nw\package.json&lt;/code&gt;&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;"my-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"chromium-args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--ignore-certificate-errors"&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;&lt;code&gt;MyApp\package.nw\index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My App&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#334&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#DDE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello World&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"example"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&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;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1qehdc79wca08yga08e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1qehdc79wca08yga08e.png" alt="Hello world example" width="522" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example code we are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Styling the app with CSS&lt;/li&gt;
&lt;li&gt;Setting the window title with the &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; tag&lt;/li&gt;
&lt;li&gt;Use Node.js's &lt;code&gt;require&lt;/code&gt; function to access the computer's File System (fs)&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;fs&lt;/code&gt; to get a list of all the items in the current directory (&lt;code&gt;.&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Targeting an element in the DOM by ID and updating its inner text value to be the list of comma-separated files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will be able to use any of the built-in Node modules, or any 3rd party modules you would &lt;code&gt;npm install&lt;/code&gt; that are compatible with Node.js v5.11.1 (basically stuff from around 2013-2017).&lt;/p&gt;

&lt;p&gt;But just using the built-ins alone, you have access to the hardware (CPU, memory, etc), file system (Read/Write/Create/Delete files), executables (child processes, spawns, forks), and more.&lt;/p&gt;

&lt;p&gt;The cool part is, if your app code doesn't use any windows specific code (like calling powershell or something), then it will be possible to ship your app on Linux and OSX too!&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Node
&lt;/h2&gt;

&lt;p&gt;Installing Node.js on your machine is not a requirement for using NW.js. If you want to use 3rd party Node modules, you will need to install them via the "Node Package Manager", or &lt;code&gt;npm&lt;/code&gt;. Node.js comes with npm when installed. Most likely all you'll need to do is download and run this installer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/dist/v5.11.1/node-v5.11.1-x86.msi" rel="noopener noreferrer"&gt;https://nodejs.org/dist/v5.11.1/node-v5.11.1-x86.msi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run it to globally install the same version of Node.js (5.11.1) that is built in to NW.js (0.14.7). You'll run into less issues if they match.&lt;/p&gt;

&lt;p&gt;If you have issues installing Node, you can look into the other Node downloads for that version:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/dist/v5.11.1/" rel="noopener noreferrer"&gt;https://nodejs.org/dist/v5.11.1/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or you can try &lt;a href="https://volta.sh" rel="noopener noreferrer"&gt;Volta&lt;/a&gt;. Which I've gotten to work on XP in the past, but don't know how. Volta is a Node version manager that works on all platforms and is really great.&lt;/p&gt;

&lt;p&gt;Also, depending on the updates you've done to your XP machine, you may be on an older version of "Windows Installer". You can check by running &lt;code&gt;msiexec&lt;/code&gt; to see the version. If you want to install version 4.5, just go to Microsoft's website and, ha ha, just kidding, that will take you to a 404 page. So instead, go to &lt;a href="https://archive.org/details/windows-xp-kb-942288-v-3-x-86_202309" rel="noopener noreferrer"&gt;The Internet Archive&lt;/a&gt; to get the update. Then &lt;a href="https://archive.org/donate" rel="noopener noreferrer"&gt;donate&lt;/a&gt; to them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Distributing your app
&lt;/h2&gt;

&lt;p&gt;When you are ready to share your app with other cool XP users, just zip up your MyApp folder and send it to them. It's that easy. Then they just unzip it and double click on the &lt;code&gt;nw.exe&lt;/code&gt; (which you probably renamed). Or you can download the non-sdk version of NW.js and move your &lt;code&gt;package.nw&lt;/code&gt; folder over to get a slightly smaller file size. Then zip and ship it.&lt;/p&gt;

&lt;p&gt;There are other options too. Another one is to use WinRAR to create a self-extracting executable (look up a tutorial). That will make a small installer file for your app. &lt;/p&gt;

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

&lt;p&gt;Have fun making apps!&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://nwutils.io" rel="noopener noreferrer"&gt;NW Utils&lt;/a&gt; for additional NW.js resources (libraries, tutorials, boilerplates, examples, etc).&lt;/p&gt;

&lt;p&gt;Here's an old XP compatible NW.js framework for making GUIs for CLI's:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ugui.io" rel="noopener noreferrer"&gt;UGUI: Universal Graphical User Interface&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>desktop</category>
      <category>nwjs</category>
      <category>windowsxp</category>
      <category>node</category>
    </item>
    <item>
      <title>TS is bad at hover text</title>
      <dc:creator>The Jared Wilcurt</dc:creator>
      <pubDate>Wed, 08 Jan 2025 04:53:01 +0000</pubDate>
      <link>https://forem.com/thejaredwilcurt/ts-is-bad-at-hover-text-3n0j</link>
      <guid>https://forem.com/thejaredwilcurt/ts-is-bad-at-hover-text-3n0j</guid>
      <description>&lt;p&gt;A literal angel (&lt;a href="https://github.com/AngelCMHxD" rel="noopener noreferrer"&gt;AngelCMHxD&lt;/a&gt;), made a PR against one of my repos to add a &lt;code&gt;.d.ts&lt;/code&gt; definition file for both auto-complete, and hover text. This is what happened next...&lt;/p&gt;




&lt;p&gt;After testing his PR locally with the TypeScript &lt;code&gt;.d.ts&lt;/code&gt; file, the result was this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffet0z1t7xo6wy5wp5y5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffet0z1t7xo6wy5wp5y5o.png" alt="Unreadable TypeScript Garbage" width="557" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that I'm hovering over the &lt;code&gt;windows&lt;/code&gt; key and it is not giving me any valuable information. It provides the same truncated mess of text (that is hard to visually parse), as when you hover over &lt;code&gt;createDesktopShortcuts&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;The repo was already written with JSDocs enforced everywhere via a simple linting plugin (&lt;a href="https://github.com/tjw-lint/eslint-config-tjw-jsdoc" rel="noopener noreferrer"&gt;use it, it's very good&lt;/a&gt;). In comparison, JSDocs provides identical type support as what TS does, and far better hints.&lt;/p&gt;




&lt;p&gt;With JSDocs, we get a cleaner hover:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnf6sylbr9ufeyhbefi61.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnf6sylbr9ufeyhbefi61.png" alt="top level JSDocs hover" width="678" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And on hover of the &lt;code&gt;windows&lt;/code&gt; key, we get much better context, explaining that it requires a &lt;code&gt;filePath&lt;/code&gt; string.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fio1l87ewvjjeh1z2pgdw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fio1l87ewvjjeh1z2pgdw.png" alt="Next level JSDocs hover" width="800" height="184"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Ultimately, there was no way to get TS to generate a usable hover tooltip. Their official recommendation is to use JSDocs.&lt;/p&gt;

&lt;p&gt;Because the TypeScript Engine and Compiler work exactly the same with types defined in JSDocs as they do with types written in the TypeScript syntax, my library does not use any TypeScript at all, but is fully typed and fully TS compatible.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>jsdocs</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Primary Responsibilities of UI Architects</title>
      <dc:creator>The Jared Wilcurt</dc:creator>
      <pubDate>Tue, 03 Dec 2024 18:39:50 +0000</pubDate>
      <link>https://forem.com/thejaredwilcurt/primary-responsibilities-of-ui-architects-1a7j</link>
      <guid>https://forem.com/thejaredwilcurt/primary-responsibilities-of-ui-architects-1a7j</guid>
      <description>&lt;p&gt;UI Architects are developers that deeply specialize in all things related to frontend. They should have expertise in JavaScript, its frameworks &amp;amp; tooling, as well as software patterns. They can build anything with pixel perfect accuracy in HTML &amp;amp; CSS in a clean, semantic, and accessible manner. They should be deeply familiar with all the different approaches for how to organize and handle large/complex CSS. They may be called upon to help with a specific team, or work on code that can be used across teams. They're familiar with UX patterns and terminology and can work and communicate with UX Researchers, Designers and Developers, and act as bridge between them. They tend to work across teams and disciplines.&lt;/p&gt;

&lt;p&gt;Below we outline the core responsibilities of people in this role.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;UI Architects are expected to write and work on code, primarily used across teams within an organization. This includes libraries (CSS libraries, component libraries, utilities), tooling (linting, testing, building, documenting, deploying, etc), boilerplates, open source contributions to resolve 3rd-party issues, and more. The product of these efforts results in speeding up development, improving the developer experience, reducing rework across teams, and leads to an overall more consistent user experience.&lt;/p&gt;

&lt;p&gt;Besides shared code, UI Architects may be pulled in to help with code specific to a single project or team. Such as rare events that members of the team may not feel comfortable doing as it is outside of their day-to-day work. Work that requires niche and rarely useful knowledge, not worth training others on. Or work with a much higher than normal level of complexity. Examples include setting up a repo for the first time, updating dependencies in old repos, code migrations, automating tasks, CI/CD/deployments, advanced optimization techniques, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consultation
&lt;/h2&gt;

&lt;p&gt;UI Architects must be extremely knowledgeable in all things related to frontend development. They should be seen as a resource who assists in solving problems when others are stuck, gives advice or direction, and explains concepts or niche aspects of UI work.&lt;/p&gt;

&lt;p&gt;A team may need help planning out large projects like migrating a code base between technologies (build tools, testing frameworks, frontend frameworks, state management libraries, etc). They may want counsel and recommendations around adopting a technology that is new to the team. UI Architects should be able to speak from experience, but also in an unbiased way, pointing out the situations that make technologies most useful, and the pros and cons of any potential technology choice, pattern, or approach.&lt;/p&gt;

&lt;p&gt;Having this expertise internally also allows giving context of what internal resources exist for a choice that would make it more beneficial to adopt. Internal resources may be preexisting libraries compatible with the choice, or experts within the organization that could be tapped for assistance in the future.&lt;/p&gt;

&lt;p&gt;A UI Architect should contrast choices to similar alternatives. Ultimately this is guidance, not rules. Teams can use this summarized information to make the decisions they believe are best for their team and the project. Even if it is differs from what the Architect would have chosen, or what other teams have chosen. Teams choosing to go in a new direction will have a harder time, but also are more likely to innovate, and may be trailblazers to allow others in the organization to follow in their steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Communication/Context
&lt;/h2&gt;

&lt;p&gt;Part of the role of a UI Architect is to be a bridge between UI, UX, and PM roles. They should champion the needs of developers to designers, while also explaining the reasoning behind designs to developers, when a different approach is needed.&lt;/p&gt;

&lt;p&gt;They provide and convey the context in either scenario so that &lt;em&gt;the right&lt;/em&gt; corners are cut to make a deadline, or so that the same user outcome can be reached with a different design that could be developed in less time. They don't need to be an expert in User Experience Design/Research, but they should be able to &lt;em&gt;speak&lt;/em&gt; the language of those in the UX field. Being able to effectively communicate with Project/Product managers, UX Designers, and Frontend developers is key to being this bridge. Understanding the goals of each of these groups and helping to balance them and find solutions with the fewest compromises, and where expectations are managed realistically.&lt;/p&gt;




&lt;h2&gt;
  
  
  The difference between UI Architects and UX Architects
&lt;/h2&gt;

&lt;p&gt;There is a lot of overlap between these roles. While both have technical frontend expertise, a UX Architect will work closely with UX Designers and UX Researchers. Where as a UI Architect primarily works with Frontend and Full Stack Developers. UIA will tend to have more software and library development experience. UXA will have more design and UX experience. But this isn’t a clear and defined line that both fall on opposite sides of. It can often be fuzzy and the requirements put on those in these roles are very dependent on the organization they are in.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Photo Credit:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Smolensk fortress wall&lt;/em&gt; by Anastasiya Romanova&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>webdev</category>
      <category>career</category>
      <category>ux</category>
    </item>
    <item>
      <title>Windows 11 unsuckifying guide</title>
      <dc:creator>The Jared Wilcurt</dc:creator>
      <pubDate>Wed, 26 Jun 2024 17:53:32 +0000</pubDate>
      <link>https://forem.com/thejaredwilcurt/windows-11-unsuckifying-guide-1oc5</link>
      <guid>https://forem.com/thejaredwilcurt/windows-11-unsuckifying-guide-1oc5</guid>
      <description>&lt;p&gt;Here's an incomplete list of tips, tools, and settings to help make Windows 11 suck less.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Biggest pro-tip:&lt;/strong&gt; If you are installing Windows 11 fresh, use English-Global instead of English US. This skips installing TikTok, Disney+, LinkedIn, Spotify, etc paid-promotional links everywhere. Also turns off MS Store by default until you set your region to EN-US (if you want to re-enable it).&lt;/p&gt;

&lt;p&gt;It is technically possible to create a Win 11 user account without a Microsoft account, but you'll need to look it up as MS keeps trying to make this harder.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go through every single setting on the OS and turn off all the bullshit, spyware, AI, etc.&lt;/li&gt;
&lt;li&gt;Settings &amp;gt; Accessibility &amp;gt; Visual Effects

&lt;ul&gt;
&lt;li&gt;Always show Scrollbars (why the fuck is this disabled by default)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Settings &amp;gt; Accessibility &amp;gt; Keyboard

&lt;ul&gt;
&lt;li&gt;Sticky/Filter/Toggle Keys: OFF&lt;/li&gt;
&lt;li&gt;Underline Access Keys: ON&lt;/li&gt;
&lt;li&gt;Print Screen opens a stupid fucking program instead of doing print screen: OFF&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Settings &amp;gt; System &amp;gt; Multitasking &amp;gt; Snap Windows:

&lt;ul&gt;
&lt;li&gt;Turn off "Show Snap layouts when I hover over a Window's Maximize button"&lt;/li&gt;
&lt;li&gt;Turn off "Show snap layouts when I drag a window to the top of my screen"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Constantly leave feedback as you try to do common basic shit and Windows just sucks now and has no option to make it unsuck

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;a href="https://old.reddit.com/r/Windows11/comments/s3f2y9/please_separate_calendar_and_notifications/" rel="noopener noreferrer"&gt;https://old.reddit.com/r/Windows11/comments/s3f2y9/please_separate_calendar_and_notifications/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RegEdit: &lt;a href="https://www.tenforums.com/tutorials/79875-change-size-scroll-bars-windows-10-a.html" rel="noopener noreferrer"&gt;Make Scrollbars wider&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HKCU\Control Panel\Desktop\WindowMetrics&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Double click &lt;code&gt;ScrollHeight&lt;/code&gt; and &lt;code&gt;ScrollWidth&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enter a value between &lt;code&gt;-120&lt;/code&gt; (thinner) to &lt;code&gt;-1500&lt;/code&gt; (thicker) and click OK. (&lt;code&gt;-255&lt;/code&gt; is probably fine)&lt;/li&gt;
&lt;li&gt;Restart to apply.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RegEdit: &lt;a href="https://www.tenforums.com/tutorials/104754-change-width-taskbar-buttons-windows.html" rel="noopener noreferrer"&gt;Stop taskbar app label widths from fluctuating constantly&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;For some stupid reason, the width of apps in the taskbar expands and contracts as the title of the window changes, causing one app to shift the position of all other apps that come after it in the taskbar. Happens a lot when running commands that chain other commands (like &lt;code&gt;npm t&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;There are two solutions, neither seemed to work for me. Regedit and WindHawk&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HKCU\Control Panel\Desktop\WindowMetrics&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Right-click blank space &amp;gt; New String&lt;/li&gt;
&lt;li&gt;Name: &lt;code&gt;MinWidth&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value: &lt;code&gt;38&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://windhawk.net/mods/taskbar-labels" rel="noopener noreferrer"&gt;WindHawk&lt;/a&gt; - Note: Because WindHawk does code injection, it can be seen as malicious by some protection software. It isn't, but my work computer really doesn't like it.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ramensoftware/windhawk/releases/latest" rel="noopener noreferrer"&gt;https://github.com/ramensoftware/windhawk/releases/latest&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RegEdit: &lt;a href="https://www.howtogeek.com/826967/how-to-disable-bing-in-the-windows-11-start-menu/" rel="noopener noreferrer"&gt;Stop sending start menu searches to Bing's servers&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HKCU\SOFTWARE\Policies\Microsoft\Windows&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Right-Click &lt;code&gt;Windows&lt;/code&gt; &amp;gt; New &amp;gt; Key &amp;gt; &lt;code&gt;Explorer&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Right-Click &lt;code&gt;Explorer&lt;/code&gt; &amp;gt; New &amp;gt; DWORD32 &amp;gt; &lt;code&gt;DisableSearchBoxSuggestions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Double-Click &lt;code&gt;DisableSearchBoxSuggestions&lt;/code&gt; &amp;gt; &lt;code&gt;1&lt;/code&gt; (Hex) &amp;gt; OK&lt;/li&gt;
&lt;li&gt;Restart Explorer or computer to apply&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Open-Shell/Open-Shell-Menu/releases" rel="noopener noreferrer"&gt;Replace the start menu which is filled with ads and widget bullshit&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Open-Shell/Open-Shell-Menu/discussions/1942" rel="noopener noreferrer"&gt;Replace Windows 11 logo with Windows 7 logo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RegEdit: &lt;a href="https://answers.microsoft.com/en-us/windows/forum/all/restore-old-right-click-context-menu-in-windows-11/a62e797c-eaf3-411b-aeec-e460e6e5a82a" rel="noopener noreferrer"&gt;Bring back the original right click menu&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Restart Explorer or computer to apply&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/valinet/Win11DisableRoundedCorners" rel="noopener noreferrer"&gt;Turn off rounded corners on every window&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IMPORTANT:&lt;/strong&gt; Make sure only one &lt;code&gt;dwm.exe&lt;/code&gt; is running before executing. Do not run this remotely, run it on the actual machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NOTE:&lt;/strong&gt; Unfortunately, after every Windows update, this gets reset on reboot. So you have to re-run this, but because it creates a backup file, it won't re-run until you delete the backup located at: &lt;code&gt;C:\Windows\System32\uDWM_win11drc.bak&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.digitallis.co.uk/pc/ResizeEnable/" rel="noopener noreferrer"&gt;Make any window resizable&lt;/a&gt;. Hey my Outlook notifications are in a tiny window that I can't resize and the buttons to dismiss notifications are so far to the right, they aren't visible. Guess I'll have to download a random tool to make the window resizable to have access to these buttons. Thanks Microsoft Windows 11, thanks Microsoft Outlook. Real cool.&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://github.com/rcmaehl/MSEdgeRedirect" rel="noopener noreferrer"&gt;MSEdgeRedirect&lt;/a&gt; to have News, Search, Widgets, Weather and more use your default browser instead of MS Edge.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ChrisTitusTech/winutil" rel="noopener noreferrer"&gt;Chris Titus Win Util (Win 11 Debloating/Spam removal)&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;This utility does a TON of things, be very careful and read everything before applying changes as many settings it offers are bonkers and it even warns you not to do them. But it also does a ton of very useful things.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=5_AaHXrelTE" rel="noopener noreferrer"&gt;Intro Video for it&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The notification sounds on W11 might as well not exist, they are so soft and quiet and barely noticeable even when you are right in front of the computer, let alone in the other room when you want to hear the sounds.

&lt;ul&gt;
&lt;li&gt;Download a sound pack: &lt;a href="https://winsounds.com" rel="noopener noreferrer"&gt;https://winsounds.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go to Settings &amp;gt; Sound &amp;gt; More sound Settings &amp;gt; Sounds&lt;/li&gt;
&lt;li&gt;Select each sound in the list, click Test to hear it, then replace it with your downloaded sounds.&lt;/li&gt;
&lt;li&gt;When done, save your scheme&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Alternatively you could just do this:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install &lt;a href="https://zorin.com/os" rel="noopener noreferrer"&gt;Zorin OS&lt;/a&gt; instead of Windows.&lt;/li&gt;
&lt;li&gt;Install the "ArcMenu" Gnome Extension to get a more Windows-like start menu&lt;/li&gt;
&lt;li&gt;That's it. It works fine, it's the closest thing you'll get to Windows 7 that isn't Windows 7. It even runs some Windows programs perfectly fine just by double-clicking them.&lt;/li&gt;
&lt;li&gt;"Wait, did you just trick me into using... &lt;em&gt;Linux&lt;/em&gt;, gross." Yes I did. I hate Linux too, but with how bad Win11 is, Zorin is legitimately better. No AI bullshit, no spyware, fully customizable. etc.&lt;/li&gt;
&lt;li&gt;I've not had to use the commandline at all on Linux. That bullshit is in the past, modern Linux is finally usable by actual humans. Or at least Zorin is.&lt;/li&gt;
&lt;li&gt;Here is &lt;a href="https://dev.to/thejaredwilcurt/zorin-setup-4jpf"&gt;my personal Zorin settings&lt;/a&gt;, but you really don't need it, you can just play with the settings yourself.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>windows</category>
      <category>windows11</category>
      <category>guide</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
