<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jake Dohm</title>
    <description>The latest articles on DEV Community by Jake Dohm (@jakedohm_34).</description>
    <link>https://dev.to/jakedohm_34</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%2F18535%2Fda254aa3-f09d-437f-8cc7-47577e423137.jpg</url>
      <title>DEV Community: Jake Dohm</title>
      <link>https://dev.to/jakedohm_34</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jakedohm_34"/>
    <language>en</language>
    <item>
      <title>Auto-registering all your components in Vue 3 with Vite</title>
      <dc:creator>Jake Dohm</dc:creator>
      <pubDate>Mon, 10 May 2021 20:40:02 +0000</pubDate>
      <link>https://dev.to/jakedohm_34/auto-registering-all-your-components-in-vue-3-with-vite-4884</link>
      <guid>https://dev.to/jakedohm_34/auto-registering-all-your-components-in-vue-3-with-vite-4884</guid>
      <description>&lt;h2&gt;
  
  
  Why auto-register components?
&lt;/h2&gt;

&lt;p&gt;I'm actually a big fan of manually importing components in Vue applications. It makes it very clear where every component comes from, doesn't rely on ✨magic✨, and most IDEs can do auto-imports for you anyway so it's not much more work for you.&lt;/p&gt;

&lt;p&gt;That said, in an environment where I'm not building an SPA, and I'm using Vue as a progressive enhancement tool, I want all of my components to be available in HTML. To make this happen, I have to register all of them in the root Vue instance....&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;createApp&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="c1"&gt;// import each component&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Fruits&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;./components/Fruits.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vegetables&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;./components/Vegetables.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vueApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// register each component&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;Fruits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Vegetables&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 process is tedious, and makes component auto-registration totally worth it IMO.&lt;/p&gt;

&lt;h2&gt;
  
  
  How
&lt;/h2&gt;

&lt;p&gt;So, to auto-register our components, we need to do a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get a list of each component&lt;/li&gt;
&lt;li&gt;Import that component&lt;/li&gt;
&lt;li&gt;Register it on our Vue instance&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Luckily, Vite has an amazing feature which takes care of steps #1 and #2 for us&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1+2: Glob Imports.
&lt;/h2&gt;

&lt;p&gt;Glob Imports is feature of Vite that allows us to import multiple files based on a filepath.&lt;/p&gt;

&lt;p&gt;There are two ways to use Glob Imports in Vite: lazy or eager. If you use the standard &lt;code&gt;glob&lt;/code&gt; method, the imports will be processed as dynamic imports, so the components will be lazy-loaded. In our case, we want to import all of the components directly into our main bundle, so we'll use the &lt;code&gt;globEager&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Glob Imports is a Vite feature, and is not part of any JS or "platform" standards.&lt;/p&gt;

&lt;p&gt;Here's how Glob Imports works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// import multiple components&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;components&lt;/span&gt; &lt;span class="o"&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;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;globEager&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&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;And here's the result of that import:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// code produced by vite&lt;/span&gt;

&lt;span class="c1"&gt;// magically autogenerated module imports&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;__glob__0_0&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;./components/Fruits.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;__glob__0_1&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;./components/Vegetables.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// our components variable now contains an object with key/values&lt;/span&gt;
&lt;span class="c1"&gt;// representing each module's path and definition&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;components&lt;/span&gt; &lt;span class="o"&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;./components/Fruits.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;__glob__0_0&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/Vegetables.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;__glob__0_1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Registering components
&lt;/h2&gt;

&lt;p&gt;Now that we've actually imported each component, and we have a list containing the path and definition, we need to define these components on our Vue instance.&lt;/p&gt;

&lt;p&gt;To do that, we'll loop over each entry in our &lt;code&gt;components&lt;/code&gt; object, figure out the component's name based on the file name, and then register the component on our Vue instance.&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;definition&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="c1"&gt;// Get name of component, based on filename&lt;/span&gt;
  &lt;span class="c1"&gt;// "./components/Fruits.vue" will become "Fruits"&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;componentName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&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="nx"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.\w&lt;/span&gt;&lt;span class="sr"&gt;+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Register component on this Vue instance&lt;/span&gt;
  &lt;span class="nx"&gt;vueApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;componentName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&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;h2&gt;
  
  
  Putting it all together
&lt;/h2&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;createApp&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vueApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createApp&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;components&lt;/span&gt; &lt;span class="o"&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;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;globEager&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/*.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;definition&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="c1"&gt;// Get name of component, based on filename&lt;/span&gt;
  &lt;span class="c1"&gt;// "./components/Fruits.vue" will become "Fruits"&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;componentName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&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="nx"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.\w&lt;/span&gt;&lt;span class="sr"&gt;+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Register component on this Vue instance&lt;/span&gt;
  &lt;span class="nx"&gt;vueApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;componentName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&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;



</description>
      <category>vue</category>
      <category>vitejs</category>
      <category>components</category>
    </item>
    <item>
      <title>How to make a GraphQL Query (or Mutation!) in PHP with Guzzle</title>
      <dc:creator>Jake Dohm</dc:creator>
      <pubDate>Wed, 21 Oct 2020 22:43:58 +0000</pubDate>
      <link>https://dev.to/jakedohm_34/how-to-make-a-graphql-query-or-mutation-in-php-with-guzzle-359o</link>
      <guid>https://dev.to/jakedohm_34/how-to-make-a-graphql-query-or-mutation-in-php-with-guzzle-359o</guid>
      <description>&lt;h3&gt;
  
  
  1: Define a Query
&lt;/h3&gt;

&lt;p&gt;First, we're going to start off with creating a query. This will be a simple query that will ask for the "name" field for our site.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'query { site { name } }'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, this works, but it gets awkward and inconvenient to have to keep our whole query on one line. To fix this, we can use a &lt;a href="https://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc"&gt;Heredoc&lt;/a&gt; which will allow us to break our query into multiple lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;&amp;lt;&amp;lt;&amp;lt;GQL
  query {
    site {
      name
    }
  }
GQL;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note: Make sure the ending &lt;code&gt;GQL;&lt;/code&gt; statement is not indented at all as that breaks Heredoc syntax.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2: Make the HTTP request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$graphqlEndpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'https://example.com/graphql-api'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nf"&gt;GuzzleHttp\Client&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'POST'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$graphqlEndpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s1"&gt;'headers'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// include any auth tokens here&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="s1"&gt;'json'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'query'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$query&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 pretty standard request, but there are two notable things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We're making a POST request. All (properly configured) GraphQL endpoints will only accept a POST request.&lt;/li&gt;
&lt;li&gt;We're using &lt;code&gt;json&lt;/code&gt; not &lt;code&gt;body&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We're not doing any authentication, but you probably will. This will often either be a token you can add as a header, or it will be basic HTTP authentication that you can pass as a top-level option to Guzzle (&lt;a href="https://docs.guzzlephp.org/en/stable/request-options.html#auth"&gt;see docs&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3: Retrieve the response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$json = $response-&amp;gt;getBody()-&amp;gt;getContents();
$body = json_decode($json);
$data = $body-&amp;gt;data;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4: Put it all together
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;&amp;lt;&amp;lt;&amp;lt;GQL
  query {
    site {
      name
    }
  }
GQL;&lt;/span&gt;
&lt;span class="nv"&gt;$graphqlEndpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'https://example.com/graphql-api'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nf"&gt;GuzzleHttp\Client&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'POST'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$graphqlEndpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s1"&gt;'headers'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'application/json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// include any auth tokens here&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="s1"&gt;'json'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'query'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$query&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nv"&gt;$json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getBody&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getContents&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>graphql</category>
      <category>php</category>
    </item>
    <item>
      <title>Defining "Done"</title>
      <dc:creator>Jake Dohm</dc:creator>
      <pubDate>Mon, 18 May 2020 17:58:55 +0000</pubDate>
      <link>https://dev.to/jakedohm_34/defining-done-1oii</link>
      <guid>https://dev.to/jakedohm_34/defining-done-1oii</guid>
      <description>&lt;p&gt;What does "done" mean? Well, it means you've decided that you're finished. With a task, a project, a JIRA ticket, whatever. But it's very possible that when you say you're done, you're actually 80% of the way to finished, and the last 20% will eventually come around to haunt you and steal your time and money.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different Types of Done
&lt;/h2&gt;

&lt;p&gt;There are many different valid types of "done". Here are a few of them I could think of, sorted by timeline (ish):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code works (matches a spec or design)&lt;/li&gt;
&lt;li&gt;Code produces accessible and performant UI&lt;/li&gt;
&lt;li&gt;Code is tested (either manually or automated)&lt;/li&gt;
&lt;li&gt;Ready for internal review (maybe a PR review)&lt;/li&gt;
&lt;li&gt;Ready for stakeholder review (client, product manger)&lt;/li&gt;
&lt;li&gt;Client has approved&lt;/li&gt;
&lt;li&gt;Client has given the go-ahead for launch&lt;/li&gt;
&lt;li&gt;Project is launched&lt;/li&gt;
&lt;li&gt;Internal team has recapped project internally, and "resolved" that project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are all very real states, but if you call all of them "done" you'll never know when you're really done, and you'll underestimate the amount of work left to do, and it will cause problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem #1: Frustration
&lt;/h3&gt;

&lt;p&gt;When you say you're done with something, your brain believes you. So when you inevitably have to come back and finish the last 20% you get frustrated. Because you were &lt;strong&gt;done&lt;/strong&gt;. It was &lt;strong&gt;finished&lt;/strong&gt;. So, the work that should've included in the definition of "done", becomes nagging "extra" work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem #2: Team Friction &amp;amp; Expectations
&lt;/h3&gt;

&lt;p&gt;When you haven't defined "done" for your team, it's going to cause problems. Take for example a web agency with two developers and a project manager. Here's how they all individually define done:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dev #1&lt;/strong&gt;: The project is finished when: it looks like the designs and it doesn't have any glaring functionality bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dev #2&lt;/strong&gt;: Everything that Dev #1 said, &lt;strong&gt;and&lt;/strong&gt;: every page has lighthouse score of 90+, it has been audited for SEO issues, and every page is accessible and is at least AA compliant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PM&lt;/strong&gt;: The project is finished, functional, matches the team's development standards, &lt;strong&gt;and&lt;/strong&gt;: it has been documented, pushed to Staging for review, and you've set up users for any stakeholders who should have access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can immediately see where problems will arise. Dev #1 and Dev #2 are working with entirely different standards of work, and their PM is coming from a completely different perspective. This will cause friction, and lose you money.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem #3: Inconsistency
&lt;/h3&gt;

&lt;p&gt;Do you think McDonald's got to where it was, a literal global superpower, without consistency? No, that's one of the things that made it great! You can step into any McDonald's &lt;em&gt;in the World&lt;/em&gt; and ask for a #1 and you'll receive the same thing every time. Consistency is key.&lt;/p&gt;

&lt;p&gt;Consistency is key, no matter what you're doing. You work for an agency? You need to produce consistently &lt;a href="https://simplygoodwork.com/"&gt;Good Work&lt;/a&gt; 😉 or your clients will work with someone else. You work for a product company? You need to produce consistent, stable software or people won't use it (or won't stay). Are you building a component library? You need to have a consistent API across components, and you need to make sure good documentation and examples are always written before you launch a new component.&lt;/p&gt;

&lt;p&gt;In any line of work, defining "done" is a crucial part of producing consistent work.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to define done
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Talk with your (complete) team&lt;/strong&gt;: Bring everyone in that you work with together, and come up with language and processes around what "done"  means for each department, and each type of project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Define done for each &lt;em&gt;aspect&lt;/em&gt; of a project&lt;/strong&gt;: QA should have a "done". Dev should have a "done".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set up your workflow tools to recognize different "done" states&lt;/strong&gt;: For instance, at &lt;a href="https://simplygoodwork.com"&gt;Good Work&lt;/a&gt;, we have Trello columns for To Do, Ready for Review (internal), Ready for Review (client), and Done (which means &lt;em&gt;really&lt;/em&gt; done).&lt;/p&gt;

&lt;h2&gt;
  
  
  Lastly
&lt;/h2&gt;

&lt;p&gt;You might be thinking:&lt;/p&gt;

&lt;blockquote&gt;I don't have the power to define "done"&lt;/blockquote&gt;

&lt;p&gt;This might be true. You might not be a manager or even the most experienced dev on your team. That's fine! Start by defining "done" for yourself and communicating it clearly to your manager(s) and collaborators. Set clear expectations for yourself, and let anyone you work directly with know what your expectations of them are.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclaimer #1: I'm no expert. I've never taken an Agile course. I'm not a scrum master. I don't manage a team. But I work with a team, and I've seen when things have gone poorly and when they go well.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer #2: I'm not the first, or last, person to write about this. This is one of the core principles of Agile (probably, who even knows) and so it has been covered in depth before me, and will be again after me.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>projectmanagement</category>
      <category>opensource</category>
      <category>web</category>
    </item>
    <item>
      <title>Registering Global Components with Vue 3</title>
      <dc:creator>Jake Dohm</dc:creator>
      <pubDate>Wed, 22 Apr 2020 13:49:42 +0000</pubDate>
      <link>https://dev.to/jakedohm_34/registering-global-components-with-vue-3-2kgl</link>
      <guid>https://dev.to/jakedohm_34/registering-global-components-with-vue-3-2kgl</guid>
      <description>&lt;p&gt;Vue 3 is now in beta &lt;a href="https://vueschool.io/articles/news/vue-3-beta-is-released/"&gt;(learn more)&lt;/a&gt; so I decided to test it out (using &lt;a href="https://github.com/vuejs/vue-next"&gt;vue-next&lt;/a&gt;), and one of the things I had to tweak in my current application is how I was registering my "global" components.&lt;/p&gt;

&lt;p&gt;I'll talk about &lt;em&gt;why&lt;/em&gt; these changes are necessary below, but if you're just here for the meat of the post, the examples really speak for themselves so here are the actual code changes:&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="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;Vue&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Header&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;./components/Button.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&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;./App.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Register Button component globally&lt;/span&gt;
&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Create and mount Vue instance&lt;/span&gt;
&lt;span class="k"&gt;new&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;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;$mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&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;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="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;createApp&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Header&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;./components/Button.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&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;./App.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Create Vue instance&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;createApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Register Button component globally&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Mount Vue instance&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&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;h3&gt;
  
  
  Why are these changes necessary?
&lt;/h3&gt;

&lt;p&gt;Hey, you ask great questions!! Vue 3 changed the way "instances" of Vue work so that they could make the Vue prototype immutable. So now you customize an "instance" of Vue (created with &lt;code&gt;createApp&lt;/code&gt;) instead of directly changing the Vue prototype. I'm not sure exactly why this change was made, but that's how things work in Vue 3.&lt;/p&gt;

&lt;p&gt;This also means if you're running an app that has &lt;em&gt;multiple&lt;/em&gt; Vue instances that share configuration, you'll now need to either 1) duplicate some code or 2) create your own abstraction to share configuration. I'll write more about this soon!&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;If you have any questions about this, or any Vue 3 changes, drop me a comment or find me on Twitter &lt;a class="comment-mentioned-user" href="https://dev.to/jakedohm"&gt;@jakedohm&lt;/a&gt;
. I plan on writing more about Vue 3, so let me know what you'd like me to cover!&lt;/p&gt;

</description>
      <category>vue</category>
      <category>vue3</category>
      <category>components</category>
    </item>
    <item>
      <title>Using Tailwind in SASS with Gatsby JS</title>
      <dc:creator>Jake Dohm</dc:creator>
      <pubDate>Thu, 12 Dec 2019 20:41:45 +0000</pubDate>
      <link>https://dev.to/jakedohm_34/using-tailwind-in-sass-with-gatsby-js-n9a</link>
      <guid>https://dev.to/jakedohm_34/using-tailwind-in-sass-with-gatsby-js-n9a</guid>
      <description>&lt;p&gt;I recently had project to convert a site to Gatsby, and it was using both &lt;a href="https://tailwindcss.com/"&gt;Tailwind CSS&lt;/a&gt; and SASS, so I had to figure out how to convince those two to play nice. I tried a few different solutions that were not ideal, and then found a simpler way to do it. So here it is!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: I started on this article before the Gatsby documentation had an official recommendation for this, and just got around to finishing it, but thankfully their recommendation is the same as what I ended up doing. This article contains a few extra steps for a "from scratch" setup, but if you can find the official documentation here: &lt;a href="https://www.gatsbyjs.org/docs/tailwind-css/#option-3-scss"&gt;https://www.gatsbyjs.org/docs/tailwind-css/#option-3-scss&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Install Dependencies
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Using npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;gatsby-plugin-sass node-sass tailwindcss &lt;span class="nt"&gt;--save&lt;/span&gt;

&lt;span class="c"&gt;# Using Yarn&lt;/span&gt;
yarn add gatsby-plugin-sass tailwindcss &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Configure gatsby-plugin-sass to use Tailwind
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;gatsby-plugin-sass&lt;/code&gt; plugin you installed has a fantastic option allowing you to configure it to use PostCSS plugins, like autoprefixer. Which works out nicely because Tailwind is actuall a PostCSS plugin! So, to use Tailwind directives within your CSS, you can drop the following code into your Gatbsy configuration 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="c1"&gt;// gatbsy-config.js&lt;/span&gt;

&lt;span class="nx"&gt;plugins&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;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-plugin-sass`&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="c1"&gt;// Configure SASS to process Tailwind&lt;/span&gt;
      &lt;span class="na"&gt;postCssPlugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&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;tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// ... more plugins ... &lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Generate Tailwind Config File
&lt;/h2&gt;

&lt;p&gt;To configure Tailwind, we'll need to add a Tailwind configuration file. Luckily, Tailwind has a built-in script to do this. Just run the following command (again, in your project's root directory).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./node_modules/.bin/tailwind init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a &lt;code&gt;tailwind.js&lt;/code&gt; file containing Tailwind's default configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Add a SASS/SCSS File With Tailwind Directives
&lt;/h2&gt;

&lt;p&gt;Everything should be ready to go, all we need to do now is to actually &lt;em&gt;use&lt;/em&gt; Tailwind within our styles! First, create a &lt;code&gt;global.scss&lt;/code&gt; file. I put mine at &lt;code&gt;src/css/global.scss&lt;/code&gt;. Then, add the following Tailwind directives to your new file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="c1"&gt;// global.scss&lt;/span&gt;

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="nt"&gt;preflight&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="nt"&gt;components&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="nt"&gt;utilities&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two notes:&lt;br&gt;
1) &lt;code&gt;gatsby-plugin-sass&lt;/code&gt; works with both &lt;code&gt;scss&lt;/code&gt; and &lt;code&gt;sass&lt;/code&gt; files.&lt;br&gt;
2) For this step, I opted to create a new &lt;code&gt;global.scss&lt;/code&gt; file, but you could just as easily put the Tailwind directives in an existing SASS file.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 5: Import Our Tailwind CSS
&lt;/h2&gt;

&lt;p&gt;The last thing we need to do is to import our new SASS file into a page or layout so that our Tailwind CSS is actually injected into our pages. In &lt;code&gt;layout.js&lt;/code&gt;, or wherever you want your Tailwind CSS to appear, add the following import:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// layout.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../css/global.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  You're Finished!
&lt;/h2&gt;

&lt;p&gt;That's it, you should have a beautiful SASS + Tailwind + Gatsby setup!&lt;/p&gt;

&lt;p&gt;If you run into any trouble along the way, let me know in the comments and I'll happily help out and/or revise this article with any corrections!&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>css</category>
      <category>sass</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Adding an "Update Browser" Banner for Legacy Browsers</title>
      <dc:creator>Jake Dohm</dc:creator>
      <pubDate>Tue, 19 Nov 2019 20:29:29 +0000</pubDate>
      <link>https://dev.to/jakedohm_34/adding-an-update-browser-banner-for-legacy-browsers-39n7</link>
      <guid>https://dev.to/jakedohm_34/adding-an-update-browser-banner-for-legacy-browsers-39n7</guid>
      <description>&lt;p&gt;Every day Internet Explorer gets older and users are (slowly) migrating away to more modern browsers. As IE's marketshare decreases, it makes more and more sense to drop IE support and spend that time you would've spend bug-fixing other things like accessibility! But, if you &lt;em&gt;don't&lt;/em&gt; optimize your site for IE, the experience &lt;em&gt;will&lt;/em&gt; be subpar, which could lead your users to navigate away from your site thinking it is broken for everyone.&lt;/p&gt;

&lt;p&gt;Oh how I wish there was a way to solve this problem!!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hold on a second, I'm getting a call...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*answers the phone*&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smart Person&lt;/strong&gt;: Hey, I heard you were monologuing about how IE looking bad could reflect badly on your site's reputation. I just wanted to tell you, this problem has been solved...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Me&lt;/strong&gt;: Oh, &lt;em&gt;sure it has&lt;/em&gt; 🙄. The solution is probably complex and takes hours or days to implement, right?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SP&lt;/strong&gt;: Nah, it's like, 8 lines of CSS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Me&lt;/strong&gt;: Yeah sure, but how much JavaScript do I have to load?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SP&lt;/strong&gt;: None. Literally none.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Me&lt;/strong&gt;: Hmm, sounds too good to be true, but I'd love to try it out, can you send it over?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*fax machine starts up*&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*code prints out*&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;
&lt;span class="c"&gt;/* Hide IE banner by default */&lt;/span&gt;
&lt;span class="nc"&gt;.ie-notice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Show IE banner on IE10/11 */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;-ms-high-contrast&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;-ms-high-contrast&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.ie-notice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&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;Okay, all joking aside, this solution really does work. The &lt;code&gt;@media&lt;/code&gt; query that we're using here is taken from the &lt;a href="http://browserhacks.com/#hack-6615a4a5434dc55fc1c01736edb32cb7"&gt;Media Query section&lt;/a&gt; on BrowserHacks.com, and can be adjusted to work for any browser that has a trait that can be feature detected with media queries.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Side note&lt;/em&gt;: If you're not familiar with feature detection, it's worth learning about! Here are some articles here on Dev.to to help you out: &lt;a href="https://dev.to/search?q=feature%20detection"&gt;https://dev.to/search?q=feature%20detection&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  One more thing
&lt;/h3&gt;

&lt;p&gt;There's an awesome site called &lt;a href="http://outdatedbrowser.com"&gt;OutdatedBrowser.com&lt;/a&gt; that you can link to from your compatibility banner to help your users download a modern browser.&lt;/p&gt;

&lt;p&gt;Here's an example of some content you could use for your banner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ie-notice"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&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="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
      Your web browser is out of date. Update your browser for more security,
      speed and the best experience on this site.
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"http://outdatedbrowser.com"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Update your browser&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;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;p&gt;I work for an awesome company called Good Work. We are an expert team of web developers helping design teams at agencies, brands and startups build things for web and mobile.&lt;/p&gt;

&lt;p&gt;If you're looking for someone to help out on Gatsby, Vue, Tailwind, or other projects, don't hesitate to &lt;a href="https://simplygoodwork.com/contact"&gt;reach out&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>browsers</category>
      <category>compatibility</category>
      <category>ie</category>
      <category>internetexplorer</category>
    </item>
    <item>
      <title>Quick Start: Gridsome + Craft CMS GraphQL API</title>
      <dc:creator>Jake Dohm</dc:creator>
      <pubDate>Mon, 02 Sep 2019 03:13:33 +0000</pubDate>
      <link>https://dev.to/jakedohm_34/quick-start-gridsome-craft-cms-graphql-api-47cj</link>
      <guid>https://dev.to/jakedohm_34/quick-start-gridsome-craft-cms-graphql-api-47cj</guid>
      <description>&lt;p&gt;Craft CMS is a fantastic CMS that just got a whole lot easier to use with Gridsome (or any static site generator). The Craft team appears to have noticed the trend of people starting (or hoping) to use Craft as a "Headless CMS". Now, in the &lt;a href="https://craftcms.com/blog/craft-33"&gt;newest release (Craft 3.3)&lt;/a&gt;, they've added an out-of-the-box GraphQL API which is perfect for pulling your content into a static site generator like Gridsome or Gatsby.&lt;/p&gt;




&lt;p&gt;Let's jump right into how to use the new GraphQL API to integrate with Gridsome.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Set up your Craft installation
&lt;/h3&gt;

&lt;p&gt;To use the GraphQL API, you need to have a Craft installation running 3.3+ and licensed as Craft Pro*. If you have a current Craft installation and running a lower version than 3.3, you can update by changing the &lt;code&gt;craftcms/cms&lt;/code&gt; version in your &lt;code&gt;composer.json&lt;/code&gt; to &lt;code&gt;"^3.3.0"&lt;/code&gt; and then running &lt;code&gt;composer update&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;*in development you can use the Craft Pro trial&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create a schema
&lt;/h3&gt;

&lt;p&gt;Schemas are the way you can access your Craft data through GraphQL. Each schema comes with an access token, that you provide to Craft with your GraphQL query to identify which schema to pull data from. Each schema has its own permissions set, so you can limit access to types of data based on which schema they're allowed querying.&lt;/p&gt;

&lt;p&gt;For this step, head over to &lt;code&gt;Control Panel &amp;gt; GraphQL &amp;gt; Schemas&lt;/code&gt;, then create a new schema, give it the proper data permissions, and copy the access token.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Set up a route to your GraphQL API.
&lt;/h3&gt;

&lt;p&gt;Add the following route to &lt;code&gt;routes.php&lt;/code&gt;. This will allow you to send GraphQL queries to &lt;code&gt;example.com/api&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// routes.php&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s1"&gt;'api'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'graphql/api'&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Set up your Craft API as a Gridsome data source
&lt;/h3&gt;

&lt;p&gt;Assuming you have a working Gridsome installation up and running, the actual integration of your CMS data into the Gridsome GraphQL store is extremely simple!&lt;/p&gt;

&lt;p&gt;First, you'll need to install the Gridsome source plugin for GraphQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @gridsome/source-graphql
yarn add @gridsome/source-graphql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, add the following to your &lt;code&gt;gridsome.config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// gridsome.config.js&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@gridsome/source-graphql&lt;/span&gt;&lt;span class="dl"&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CRAFT_API_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;fieldName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;craft&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;typeName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;craft&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CRAFT_API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="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 gets us 90% of the way to a working integration, but it still won't work &lt;em&gt;quite&lt;/em&gt; yet! You may have noticed the references to &lt;code&gt;process.env&lt;/code&gt; variables for our API URL and token. This is what we'll set up in the next, and final, step.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Create a &lt;code&gt;.env&lt;/code&gt; in your Gridsome project
&lt;/h2&gt;

&lt;p&gt;If you're familiar with Craft, you've seen a &lt;code&gt;.env&lt;/code&gt; file before. &lt;code&gt;.env&lt;/code&gt;  contains all of your "environmental variables": information specific to the environment you're working in. Gridsome takes this same approach to environmental variables, so we're going to create (or add to) a &lt;code&gt;.env&lt;/code&gt; file in our Gridsome project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .env - in Gridsome project&lt;/span&gt;
&lt;span class="nv"&gt;CRAFT_API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://example.test/api
&lt;span class="nv"&gt;CRAFT_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;schemaAccessToken
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  That's it!
&lt;/h2&gt;

&lt;p&gt;Now run &lt;code&gt;gridsome develop&lt;/code&gt; and you're off to the races! You should be able to query your Craft data from anywhere within Gridsome now. To test everything, head over to the GraphQL playground and try sending the following request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&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="n"&gt;craft&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="n"&gt;ping&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If everything's working properly, the &lt;code&gt;ping&lt;/code&gt; field should return &lt;code&gt;pong&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you have any comments/questions don't hesitate to leave a comment! I also love hearing when my articles were helpful to you, so leave a comment if these steps worked for you!&lt;/p&gt;

</description>
      <category>craftcms</category>
      <category>gridsome</category>
      <category>vue</category>
      <category>jamstack</category>
    </item>
    <item>
      <title>Using Axios with Craft and Vue</title>
      <dc:creator>Jake Dohm</dc:creator>
      <pubDate>Fri, 22 Mar 2019 14:44:09 +0000</pubDate>
      <link>https://dev.to/jakedohm_34/using-axios-with-craft-and-vue-3ceb</link>
      <guid>https://dev.to/jakedohm_34/using-axios-with-craft-and-vue-3ceb</guid>
      <description>&lt;p&gt;I spent a solid chunk of my morning digging through StackOverflow articles, documentation, and Twitter threads to try to find out how to submit a login form with Axios. If you've ever tried to use Axios or a similar library to make requests on a Craft CMS site, you know it's a very hairy experience.&lt;/p&gt;

&lt;p&gt;But not anymore! I'm going to show you how to configure Axios to play nice with Craft, and then how to tie that into Vue. &lt;em&gt;Note: the Vue part is optional, most of this article (steps 1-3) will work with any or no framework.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;Before we get into how to accomplish a clean setup, it's nice to understand some of the challenges that we're facing. Here are the two main issues with using Axios with Craft:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Craft expects your data to be serialized, not JSON: If you attempt to send a JSON object to Craft, it won't accept it.&lt;/li&gt;
&lt;li&gt;Craft expects a CSRF token, so that it can validate the request.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With these issues in mind, let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Create an Axios instance
&lt;/h3&gt;

&lt;p&gt;Our first step is to install Axios (&lt;code&gt;npm install axios || yarn add axios&lt;/code&gt;), and create an instance of it that we'll use to make requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axiosInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

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



&lt;p&gt;You can now use this Axios instance to make requests. Running &lt;code&gt;axiosInstance.get('/endpoint')&lt;/code&gt; will work as expected!&lt;/p&gt;

&lt;p&gt;You may be thinking "why create an instance when you can use Axios directly?" Great question! Creating an instance of Axios will allow us to configure it specifically for Craft, and attach &lt;strong&gt;our instance&lt;/strong&gt; to Vue for use in any component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Add your CSRF token
&lt;/h3&gt;

&lt;p&gt;Generally when making requests to Craft, I see people passing their CSRF token with every request, doing something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;greeting&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, World!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;csrfTokenName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&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;csrfTokenValue&lt;/span&gt;
&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// note: this code won't actually work, because "data" isn't serialized&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That method works fine, but it's clunky to have to attach your CSRF token to each request. Thankfully, there's a solution to this problem!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Right Way™️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Craft will allow you to pass a &lt;code&gt;X-CSRF-Token&lt;/code&gt; header with your request to bypass sending it along as a query parameter. Let's configure our Axios instance to send that header along automatically with each request, so we don't have to even think about it.&lt;/p&gt;

&lt;p&gt;First, we need to output our CSRF token with Twig and put it somewhere that we can access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="c"&gt;{# index.twig #}&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&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;csrfToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;craft.app.request.csrfToken&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then we can configure our Vue instance to add the &lt;code&gt;X-CSRF-Token&lt;/code&gt; header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axiosInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;headers&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;X-CSRF-Token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&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;csrfToken&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We've resolved one of our two challenges: Passing the CSRF token. Now let's tackle the second! &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Tell Axios to serialize your data
&lt;/h3&gt;

&lt;p&gt;Before writing this article and trying to figure out a smooth workflow, here's how I would've tackled this problem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;stringify&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;qs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&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="nx"&gt;stringify&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;things&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;Again, this works, but it's not ideal.&lt;/p&gt;

&lt;p&gt;After some digging, I found a configuration option for Axios called &lt;code&gt;transformRequest&lt;/code&gt; which allows us to transform the data we pass into a &lt;code&gt;post&lt;/code&gt; request before sending it.&lt;/p&gt;

&lt;p&gt;Let's update our Axios instance to automatically stringify our data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;stringify&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;qs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axiosInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;headers&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;X-CSRF-Token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&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;csrfToken&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;transformRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="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;Now we have a fully working Axios instance that takes care of passing our CSRF token and converting our data to the format which Craft expects!&lt;/p&gt;

&lt;p&gt;Check out the difference between these snippets, and try to tell me that this configuration work isn't worth it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&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;stringify&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;qs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;greeting&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, World!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;csrfTokenName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&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;csrfTokenValue&lt;/span&gt;
&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&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="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Attach your Axios instance to Vue
&lt;/h3&gt;

&lt;p&gt;This last step makes it even easier to use Axios within our Vue components. We can attach our configured Axios instance to our Vue instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axiosInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// see above for config&lt;/span&gt;

&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axiosInstance&lt;/span&gt;

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



&lt;p&gt;You can then make requests from within methods, lifecycles, etc. in your Vue components like &lt;code&gt;this.$axios.get('/')&lt;/code&gt;. Here's a more real example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;things&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="nx"&gt;getThings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Full Example
&lt;/h2&gt;

&lt;p&gt;Here's the complete Twig/JS code for reference!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="c"&gt;{# index.twig #}&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&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;csrfToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;craft.app.request.csrfToken&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.js&lt;/span&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stringify&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;qs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axiosInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;headers&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;X-CSRF-Token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&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;csrfToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;transformRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&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="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axiosInstance&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>vue</category>
      <category>craftcms</category>
      <category>axios</category>
    </item>
    <item>
      <title>Emulating Components in Twig</title>
      <dc:creator>Jake Dohm</dc:creator>
      <pubDate>Tue, 22 Jan 2019 14:31:12 +0000</pubDate>
      <link>https://dev.to/jakedohm_34/emulating-components-in-twig-cjo</link>
      <guid>https://dev.to/jakedohm_34/emulating-components-in-twig-cjo</guid>
      <description>&lt;p&gt;Components are one of my favorite things about JavaScript frameworks like Vue.js. They allow you to follow DRY principles by removing repetition of code in your markup, and they provide a fantastic developer experience. When I work in Twig templates, not having access to bona fide components is definitely one of the things I miss most. Because of that, I've been looking for a solution to this problem for a while.&lt;/p&gt;

&lt;p&gt;Before I talk about the solutions I tried out, and the one I've landed on, let me first give you my criteria for what features I need out of components, or a component replacement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criteria
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Props: I should be able to pass named parameters (usually referred to as "props") into my component.&lt;/li&gt;
&lt;li&gt;Slots: I should be able to pass chunks of markup (HTML, text, whatever) into my component, and the component should determine what to do with that markup (i.e. where to render it).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have experience with Vue.js or another component-based framework, these concepts should be very familiar to you. If not, you'll have to trust me that once you've used these component features, trying to write markup without them is painful 😂&lt;/p&gt;

&lt;h2&gt;
  
  
  Explored Solutions
&lt;/h2&gt;

&lt;p&gt;There were two main Twig features that I thought I could use to achieve component-like functionality within Twig: Macros and Includes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Macros
&lt;/h3&gt;

&lt;p&gt;So I started experimenting with Macros. If you're not familiar, Macros are the "functions" of Twig. Here's an example Macro (see more in the &lt;a href="https://twig.symfony.com/doc/2.x/tags/macro.html"&gt;Twig docs&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nv"&gt;_self&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;components&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nv"&gt;button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.content&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endmacro&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;components.button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;content&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Click Me'&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Using Macros satisfied one criterion, passing props, but it didn't solve my problem of wanting to pass markup into my "component" via named slots.&lt;/p&gt;

&lt;h3&gt;
  
  
  Includes
&lt;/h3&gt;

&lt;p&gt;Next, I tried &lt;a href="https://twig.symfony.com/doc/2.x/tags/include.html"&gt;Twig's Includes&lt;/a&gt;. Includes are a way to break up your code into multiple files, and I often use them to break up my page templates so they're smaller and to make things easier to search and find. But, they have a built-in feature, "with", that allows you to pass context (i.e. variables) into the include which made me hopeful that I could hack them into working well as components!&lt;/p&gt;

&lt;p&gt;But again, they only satisfied the first criteria. There was no (built-in) way to pass in chunks of markup to be rendered within the component's markup.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Side note: Technically, for both Macros or Includes, I could do something hacky like assigning a variable to a bunch of markup and passing that variable in, but that felt very wrong and un-intuitive.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;After giving up hope, I eventually stumbled upon Twig's Embeds. I read the documentation, and instantly got excited because Embeds seemed to satisfy both criteria right out of the box! I immediately coded up an example on TwigFiddle (twigfiddle.com) and I found that Embeds fully met both of my criteria: Using the "with" functionality and "blocks" I could pass props &lt;strong&gt;and&lt;/strong&gt; chunks of markup into the embed.&lt;/p&gt;

&lt;p&gt;Here's an example of embed declaration, and its use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="nv"&gt;embed&lt;/span&gt; &lt;span class="s2"&gt;"page.twig"&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;social&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'facebook'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'twitter'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'snapchat'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Header Content&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Main Content&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="nv"&gt;endembed&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="c"&gt;{# File: page.twig #}&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"page-component"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;Default Header Content&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;Default Main Content&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;footer&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;footer&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;Default Footer Content&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;

    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;social&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"social"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;social&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;item&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This method of emulating components in Twig isn't without its drawbacks, but I think it works well for &lt;em&gt;most&lt;/em&gt; scenarios. Here are a few notes about the pros and cons of embeds:&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can pass in both props (variables) and slots (blocks).&lt;/li&gt;
&lt;li&gt;You can specify default content for each block.&lt;/li&gt;
&lt;li&gt;Using the "with only" feature, you can encapsulate your component so it won't implicitly receive any variables from the context in which it's used.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You have to specifically reference the embed's file path in every usage&lt;/li&gt;
&lt;li&gt;You do &lt;strong&gt;have&lt;/strong&gt; to use the "only" keyword to make sure your parent template's variables don't leak into the component.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I don't think Embeds are a fantastic long-term solution, and I'd love to have component functionality natively in Twig, but I was happy to find something that satisfies my needs and allows me to clean up my templates in the way that I'm comfortable with.&lt;/p&gt;

&lt;p&gt;I'm also intrigued by &lt;a href="https://packagist.org/packages/olveneer/twig-components-bundle"&gt;Twig Components Bundle&lt;/a&gt;, a Symfony package that appears to add component functionality to Twig, based on the component system of Vue.js. But, I haven't tried it out yet. I'll make sure to report back if I do!&lt;/p&gt;




&lt;p&gt;I work for an awesome company called Good Work. We are an expert team of web developers helping design teams at agencies, brands and startups build things for web and mobile.&lt;/p&gt;

&lt;p&gt;If you're looking for someone to work with on your web projects, don't hesitate to &lt;a href="https://simplygoodwork.com/contact"&gt;reach out&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>craftcms</category>
      <category>components</category>
      <category>twig</category>
    </item>
    <item>
      <title>Using Tailwind with Gatsby JS</title>
      <dc:creator>Jake Dohm</dc:creator>
      <pubDate>Thu, 03 Jan 2019 15:50:14 +0000</pubDate>
      <link>https://dev.to/jakedohm_34/using-tailwind-with-gatsby-js-10fj</link>
      <guid>https://dev.to/jakedohm_34/using-tailwind-with-gatsby-js-10fj</guid>
      <description>&lt;p&gt;I'm beginning to rebuild my personal website using Gatsby JS, and of course I want to use my favorite CSS framework, Tailwind CSS! I searched around for a guide on how to use Gatsby and Tailwind together, and couldn't find anything with a full solution, so I decided to write this article as The Definitive Guide™ for how to set up Tailwind with Gatsby 😄.&lt;/p&gt;

&lt;p&gt;FYI: If you follow this guide, hot reloading will still work and you'll also get reloading when you change your Tailwind configuration file!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Install gatsby-plugin-postcss
&lt;/h2&gt;

&lt;p&gt;&lt;a href="%5Bhttps://www.gatsbyjs.org/packages/gatsby-plugin-postcss/?=gatsby-plugin-postcss%5D(https://www.gatsbyjs.org/packages/gatsby-plugin-postcss/?=gatsby-plugin-postcss)"&gt;gatsby-plugin-postcss&lt;/a&gt; is a Gatsby plugin that allows you to use PostCSS features in CSS files that you import into pages/components. Tailwind is built on PostCSS, so this is a great starting point!&lt;/p&gt;

&lt;p&gt;To install the plugin, use your favorite package manager.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Using NPM
npm install --save gatsby-plugin-postcss

# Using Yarn
yarn add gatsby-plugin-postcss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Configure Gatsby to Use the PostCSS Plugin
&lt;/h2&gt;

&lt;p&gt;Now that we've installed a plugin, we need to configure Gatsby to use it!&lt;/p&gt;

&lt;p&gt;Open up your &lt;code&gt;gatsby-config.js&lt;/code&gt;, and add 'gatsby-plugin-postcss' to the plugins array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// gatsby-config.js&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;siteMetadata&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="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gatsby-plugin-postcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&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;h2&gt;
  
  
  Step 3: Add PostCSS Config File
&lt;/h2&gt;

&lt;p&gt;Our PostCSS plugin is installed, and Gatsby is using it, so all that's left is to configure the PostCSS side of things! To configure PostCSS, create an empty &lt;code&gt;postcss.config.js&lt;/code&gt; file in your project's root (the same folder as the &lt;code&gt;gatsby-config.js&lt;/code&gt; file).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Install Tailwind
&lt;/h2&gt;

&lt;p&gt;Now before we configure PostCSS to use Tailwind, we need to install it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Using NPM
npm install tailwindcss --save-dev

# Using Yarn
yarn add tailwindcss --dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Generate Tailwind Config File
&lt;/h2&gt;

&lt;p&gt;To configure Tailwind, we'll need to add a Tailwind configuration file. Luckily, Tailwind has a built-in script to do this. Just run the following command (again, in your project's root directory).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./node_modules/.bin/tailwind init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a &lt;code&gt;tailwind.js&lt;/code&gt; file containing Tailwind's default configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Configure PostCSS
&lt;/h2&gt;

&lt;p&gt;Okay, we've installed and configured Tailwind, now back to our PostCSS config. We need to add Tailwind to PostCSS's list of plugins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// postcss.config.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tailwind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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;tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tailwind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./tailwind.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, you'll see we're passing in a file path. That is the path to our configuration file. So if you'd like to move or rename the Tailwind configuration file, just remember to change the file path in your &lt;code&gt;postcss.config.js&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: You can add any other PostCSS plugins that you'd like to use, like autoprefixer, before or after Tailwind in the array of plugins.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Add CSS File With Tailwind Directives
&lt;/h2&gt;

&lt;p&gt;Everything should be ready to go, all we need to do now is to actually &lt;em&gt;use&lt;/em&gt; Tailwind within our CSS! First, create a &lt;code&gt;global.css&lt;/code&gt; file. I put mine at &lt;code&gt;src/css/global.css&lt;/code&gt;. Then, add the following Tailwind directives to your new file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="nt"&gt;global&lt;/span&gt;&lt;span class="nc"&gt;.css&lt;/span&gt;

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;preflight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this step, I opted to create a new &lt;code&gt;global.css&lt;/code&gt; file, but you could just as easily put the Tailwind directives in an existing CSS file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Import Our Tailwind CSS
&lt;/h2&gt;

&lt;p&gt;The last thing we need to do is to import our new CSS file into a page or layout so that our Tailwind CSS is actually injected into our pages. In &lt;code&gt;layout.js&lt;/code&gt;, or wherever you want your Tailwind CSS to appear, add the following import:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// layout.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../css/global.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  You're Finished!
&lt;/h2&gt;

&lt;p&gt;That's it, you should have a fully functional Tailwind + Gatsby setup, with Tailwind configuration, and Hot Reloading!&lt;/p&gt;

&lt;p&gt;If you run into any trouble along the way, let me know in the comments and I'll happily help out and/or revise this article with any corrections!&lt;/p&gt;




&lt;p&gt;I work for an awesome company called Good Work. We are an expert team of web developers helping design teams at agencies, brands and startups build things for web and mobile.&lt;/p&gt;

&lt;p&gt;If you're looking for someone to help out on Gatsby, Vue, Tailwind, or other projects, don't hesitate to &lt;a href="https://simplygoodwork.com/contact"&gt;reach out&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>css</category>
      <category>gatsby</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>New Mac Setup</title>
      <dc:creator>Jake Dohm</dc:creator>
      <pubDate>Mon, 31 Dec 2018 16:03:48 +0000</pubDate>
      <link>https://dev.to/jakedohm_34/new-mac-setup-5595</link>
      <guid>https://dev.to/jakedohm_34/new-mac-setup-5595</guid>
      <description>

&lt;p&gt;A couple of months ago I purchased a 2015 27" iMac to use as my main development machine for work. As I started installing and configuring all of the apps and software I needed, I thought it would be fun to document everything, and share it with you all!&lt;/p&gt;

&lt;p&gt;Let me know in the comments the apps that y'all have installed that would make my life easier!&lt;/p&gt;

&lt;p&gt;I'll share the following categories of setup: Apps, Apps for Development, Apps for Work, Chrome Extensions, CLI Tools, and Configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Chrome (daily browser)&lt;/li&gt;
&lt;li&gt;Spotify&lt;/li&gt;
&lt;li&gt;1Password&lt;/li&gt;
&lt;li&gt;Alfred App (+ Powerpack)&lt;/li&gt;
&lt;li&gt;Spectacle (window management)&lt;/li&gt;
&lt;li&gt;Dropbox&lt;/li&gt;
&lt;li&gt;Things (task management)&lt;/li&gt;
&lt;li&gt;Notion (writing/organization)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Development Apps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Github Desktop&lt;/li&gt;
&lt;li&gt;Sequel Pro (DB Management)&lt;/li&gt;
&lt;li&gt;VS Code (extensions below)

&lt;ul&gt;
&lt;li&gt;Cobalt2 Theme (Wes Bos)&lt;/li&gt;
&lt;li&gt;Import Cost&lt;/li&gt;
&lt;li&gt;Prettier - Code formatter (Esben Petersen)&lt;/li&gt;
&lt;li&gt;Vetur (Pine Wu)&lt;/li&gt;
&lt;li&gt;VS Live Share&lt;/li&gt;
&lt;li&gt;Twig (whatwedo)&lt;/li&gt;
&lt;li&gt;Twig for Craft 2 (Selvin Ortiz)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Transmit (FTP+)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Work Apps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Harvest app&lt;/li&gt;
&lt;li&gt;Sketch&lt;/li&gt;
&lt;li&gt;Photoshop (Adobe CC)&lt;/li&gt;
&lt;li&gt;Illustrator (Adobe CC)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Chrome Extensions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1Password&lt;/li&gt;
&lt;li&gt;Vue.js Dev Tools&lt;/li&gt;
&lt;li&gt;Adblock (and Plus)&lt;/li&gt;
&lt;li&gt;Poper Blocker&lt;/li&gt;
&lt;li&gt;Privacy (awesome credit card privacy tool)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  CLI Tools (in order)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Homebrew&lt;/li&gt;
&lt;li&gt;Composer&lt;/li&gt;
&lt;li&gt;Laravel Valet (local dev)&lt;/li&gt;
&lt;li&gt;MariaDB&lt;/li&gt;
&lt;li&gt;Node&lt;/li&gt;
&lt;li&gt;Yarn&lt;/li&gt;
&lt;li&gt;Xcode Command Line Tools&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;I love almost everything about the way macOS works, so I only had to configure one thing: By default, screenshots are saved in PNG format, and medium/large screenshots usually end up around 2mb (in my experience). I would rather have screenshots saved as JPGs, because they are much smaller, and usually end up under 1mb.&lt;/p&gt;

&lt;p&gt;To change this default, you can run a single command in Terminal:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defaults write com.apple.screencapture type jpg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once you've changed the default, you have to restart a small bit of the OS for it to take effect:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;killall SystemUIServer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then you're done, and your screenshots will automatically be saved as .jpg files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;That's it! I purposefully did &lt;em&gt;not&lt;/em&gt; install some applications that I have on my personal computer, because I am intending to use my iMac exclusively for work, so I'm trying to make it harder to get sidetracked 😬&lt;/p&gt;


</description>
      <category>computer</category>
      <category>webdev</category>
      <category>devenvironment</category>
    </item>
    <item>
      <title>5 Helpful Language Features Proposed for JavaScript (2018 edition)</title>
      <dc:creator>Jake Dohm</dc:creator>
      <pubDate>Sat, 01 Dec 2018 16:32:02 +0000</pubDate>
      <link>https://dev.to/jakedohm_34/5-helpful-language-features-proposed-for-javascript-2018-edition-4l5h</link>
      <guid>https://dev.to/jakedohm_34/5-helpful-language-features-proposed-for-javascript-2018-edition-4l5h</guid>
      <description>&lt;h2&gt;
  
  
  Proposals
&lt;/h2&gt;

&lt;p&gt;The features that I mention in this article have been &lt;em&gt;proposed&lt;/em&gt; to &lt;a href="https://github.com/tc39" rel="noopener noreferrer"&gt;TC39&lt;/a&gt;, the committee that moves JavaScript forward, but are not yet part of the standard that JavaScript conforms to.&lt;/p&gt;

&lt;p&gt;There are 5 stages that a proposal goes through to land in JavaScript: Strawman, Proposal, Draft, Candidate, and Finished.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;All of the following features are stage 1 proposals&lt;/strong&gt;, which means they have met the guidelines for what a proposal must be, and have been presented to TC39. If you're interested in learning more about proposals and the process, head over to the &lt;a href="https://github.com/tc39/proposals" rel="noopener noreferrer"&gt;official TC39 proposals repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, to the proposals!&lt;/p&gt;

&lt;h2&gt;
  
  
  Last Item
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;lastItem&lt;/code&gt; is proposed to be added to the array prototype, which would make it super easy to grab the last item in an array. I love this feature, because I think it's a step in the right direction to solve some common ergonomics issues in JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;food&lt;/span&gt; &lt;span class="o"&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;🌮&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🥑&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🥓&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="cm"&gt;/* New syntax */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bacon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;food&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastItem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 🥓&lt;/span&gt;

&lt;span class="cm"&gt;/* Old syntax */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bacon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;food&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;food&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Optional Chaining
&lt;/h2&gt;

&lt;p&gt;Optional Chaining is a proposal that streamlines the access of properties on potentially &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt; types.&lt;/p&gt;

&lt;p&gt;The reason we need this is because if &lt;code&gt;object.thing&lt;/code&gt; isn't defined, and you write &lt;code&gt;object.thing.test&lt;/code&gt;, JS won't just return &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;, it will actually throw an error: 🚩"Cannot read property 'test' of undefined".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputElement&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="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[name=email]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/* New Syntax */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;street&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;street&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// returns street value, or null&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inputElement&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="c1"&gt;// returns input value, or null&lt;/span&gt;

&lt;span class="cm"&gt;/* Old Syntax */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;street&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;street&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;inputValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inputElement&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;inputElement&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="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How it works: If the item before the &lt;code&gt;?&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt; OR &lt;code&gt;undefined&lt;/code&gt;, it will return null without processing the next item, otherwise it processes the next bit of the "chain". So in the example above, if the object &lt;code&gt;user&lt;/code&gt; &lt;em&gt;doesn't&lt;/em&gt; have a key of &lt;code&gt;address&lt;/code&gt;, then it will return &lt;code&gt;null&lt;/code&gt;. If it &lt;em&gt;does&lt;/em&gt;, it will process the &lt;code&gt;.street&lt;/code&gt; part, and return the value of &lt;code&gt;user.address.street&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I was not a fan when I first saw this proposal, but I've come around on it. The syntax is a bit funky, but it will definitely simplify your codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Null(ish) Coalescing Operator
&lt;/h2&gt;

&lt;p&gt;This proposal allows you to check if a variable or statement is &lt;code&gt;undefined&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt; and return a fallback value if it is.&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;/* New Syntax */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fallback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Fallback'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;two&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fallback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Fallback'&lt;/span&gt;

&lt;span class="cm"&gt;/* Old Syntax */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fallback&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;two&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fallback&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;From looking at the above examples, you might think the Null Coalescing operator is totally unnecessary because it does the same thing as the OR operator. But they behave differently.&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;/* The differences between ?? and ||  */&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diffOne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fallback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 0&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diffOne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fallback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Fallback'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diffTwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fallback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ''&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diffTwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fallback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Fallback'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diffThree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fallback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diffThree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fallback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Fallback'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How it works: The null coalescing operator returns the first thing that isn't &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is different from the way we usually check variables using &lt;code&gt;||&lt;/code&gt; because the OR operator returns the first thing that's truthy. This means that if the value is &lt;code&gt;false&lt;/code&gt;, an empty string, or &lt;code&gt;null&lt;/code&gt;, it will not be returned; That can be a problem if one of those (false, null, empty string) is a valid value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do Block
&lt;/h2&gt;

&lt;p&gt;The "do block" is a very interesting proposal, but it takes some getting used to. The syntax is simple: you write &lt;code&gt;do&lt;/code&gt;, and then in brackets code you'd like to be executed. This feature would allow you to do some cool things that have been hard (or seemed hacky) in the past. Like when you have complex criteria for how to define a variable:&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;/* New Syntax */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;do&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="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;g&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;h&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;/* Old Syntax */&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;g&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;h&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// OR &lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;foo&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;f&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;bar&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;g&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;h&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;As mentioned in the &lt;a href="https://github.com/tc39/proposal-do-expressions" rel="noopener noreferrer"&gt;official proposal&lt;/a&gt;, this syntax is especially helpful when used in templating languages like JSX.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Home&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loggedIn&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;LogoutButton&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoginButton&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Replace All
&lt;/h2&gt;

&lt;p&gt;Wait, why do we need this again? We were already able to do &lt;code&gt;string.replace('this', 'that')&lt;/code&gt;, right? But, &lt;code&gt;replace&lt;/code&gt; only replaced the first instance of a string, unless you used a Regex. Again, this features solves a common "small problem" and makes things easier, especially for beginners 😄.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;248.434.5508&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/* New syntax */&lt;/span&gt;
&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceAll&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="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="c1"&gt;// returns '248-434-5508'&lt;/span&gt;

&lt;span class="cm"&gt;/* Old syntax */&lt;/span&gt;
&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Learning More
&lt;/h2&gt;

&lt;p&gt;If you're interested in learning more about any of these potential features, you can check out the links to the official proposals below, or you can review &lt;a href="https://github.com/tc39/proposals" rel="noopener noreferrer"&gt;all of the JS proposals&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Last Item: &lt;a href="https://github.com/keithamus/proposal-array-last" rel="noopener noreferrer"&gt;https://github.com/keithamus/proposal-array-last&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Optional Chaining: &lt;a href="https://github.com/tc39/proposal-optional-chaining" rel="noopener noreferrer"&gt;https://github.com/tc39/proposal-optional-chaining&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Null(ish) Coalescing Operator: &lt;a href="https://github.com/tc39/proposal-nullish-coalescing" rel="noopener noreferrer"&gt;https://github.com/tc39/proposal-nullish-coalescing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Do Block: &lt;a href="https://github.com/tc39/proposal-do-expressions" rel="noopener noreferrer"&gt;https://github.com/tc39/proposal-do-expressions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Replace All: &lt;a href="https://github.com/tc39/proposal-string-replace-all" rel="noopener noreferrer"&gt;https://github.com/tc39/proposal-string-replace-all&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>languages</category>
      <category>proposals</category>
    </item>
  </channel>
</rss>
