<?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: James Byrne </title>
    <description>The latest articles on DEV Community by James Byrne  (@jamesbyrne).</description>
    <link>https://dev.to/jamesbyrne</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%2F13926%2F576fdc11-c8e7-4c60-afe8-a55861250a27.jpg</url>
      <title>DEV Community: James Byrne </title>
      <link>https://dev.to/jamesbyrne</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jamesbyrne"/>
    <language>en</language>
    <item>
      <title>Using TailwindCss with Ember</title>
      <dc:creator>James Byrne </dc:creator>
      <pubDate>Fri, 03 Jan 2020 19:47:12 +0000</pubDate>
      <link>https://dev.to/jamesbyrne/using-tailwindcss-with-ember-41el</link>
      <guid>https://dev.to/jamesbyrne/using-tailwindcss-with-ember-41el</guid>
      <description>&lt;h3&gt;
  
  
  Using tailwindcss
&lt;/h3&gt;

&lt;p&gt;For the last year or more, both in work and at home, I've been using &lt;a href="//tailwindcss.com"&gt;tailwindcss&lt;/a&gt; for styling. I love composing styles together with css utility classes to create great User Interfaces (UI) &amp;amp; User Experiences (UX). Overall I've found it great and it's functional/compositional nature really gels with me.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I also love it's component system as well! Reducing the number of abstractions to be made up front is a godsend for any project growing quickly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since I like it so much and I use it in pretty much all my examples for all of my posts I thought I'd write up a quick guide for how to get running with tailwindcss and ember.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cool! …. but what is it though?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;feel free to skip if you know what tailwind is&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ok for those of you that haven't worked with it yet, tailwindcss is a &lt;a href="https://tailwindcss.com/docs/utility-first/"&gt;utility-first&lt;/a&gt; framework. You start with a set of css classes, each of which do one thing well. You then compose these classes together to get more complex behaviour. For example, below is a simple, overly excited, button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-pink-500 text-white"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Press ME!&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rk2604nt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/cvft2oo8khbweyrmhesd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rk2604nt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/cvft2oo8khbweyrmhesd.png" alt="simple-button-step-1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the classes here are pretty self explanatory but let's go through them anyway.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bg-pink-500&lt;/code&gt;: set the background colour to pink with a hue of 500

&lt;ul&gt;
&lt;li&gt;Hue is a bit like &lt;code&gt;font-weight&lt;/code&gt;, in increments of 100 it gets darker starting at &lt;code&gt;100&lt;/code&gt; and ending at &lt;code&gt;900&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;text-white&lt;/code&gt;: sets the text colour to white&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple enough right? But it's not really a nice looking button yet. For one the button is only as big as the text we put into it. Let's make it a tad nicer, we'll add a shadow, round the corners, add margin and some padding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"shadow bg-pink-500 text-white px-4 py-2 rounded m-10"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Press ME!
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vbKnPqN2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/unljp0gz4mi64i2su57l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vbKnPqN2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/unljp0gz4mi64i2su57l.png" alt="simple-button-step-2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Much better! See how easy it is to update the styles of a component, no other files, picking colours or shadows. Just sensible, configurable defaults. I'll do the same as above and go through what we've added just to be sure we're all on the same page too.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;shadow&lt;/code&gt; : Adds a medium sized shadow

&lt;ul&gt;
&lt;li&gt;We can also use &lt;code&gt;-sm&lt;/code&gt;, &lt;code&gt;-lg&lt;/code&gt; etc. for bigger or smaller options&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;px-4&lt;/code&gt;: This adds padding in the x axis, with the &lt;code&gt;4&lt;/code&gt; relating to the amount of &lt;code&gt;rem&lt;/code&gt; to add, in this case &lt;code&gt;1rem&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;py-2&lt;/code&gt; : The same as &lt;code&gt;px&lt;/code&gt; but in the y axis and &lt;code&gt;2&lt;/code&gt; gives us &lt;code&gt;.5rem&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rounded&lt;/code&gt; : This adds a &lt;code&gt;border-radius&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-sm&lt;/code&gt;, &lt;code&gt;-lg&lt;/code&gt; etc. applies here too&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;m-10&lt;/code&gt; : Adds margin of &lt;code&gt;2.5rem&lt;/code&gt; in both the x &amp;amp; y axis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok cool, but it's kinda boring right? You hover over it and nothing happens. What if we made it look more interactive. Let's do that, we'll add a simple hover effect to increase the shadow size and darken the button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"shadow hover:shadow-lg bg-pink-500 hover:bg-pink-700 text-white px-4 py-2 rounded m-10"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Press ME!
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M8K58zUh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kcfn9tbsfx7r48sad263.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M8K58zUh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kcfn9tbsfx7r48sad263.gif" alt="button-hover"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm going to take it you get the gist by now. By using these small independent classes we can specify good looking and complex designs  without having to worry about writing our own styles. This has a huge impact when creating mocks UIs and helps set a standard set of classes for growing or already large projects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For large projects under re-write or time critical tasks you'll find the amount of css you &lt;em&gt;don't&lt;/em&gt; need to write is a godsend! Speaking from first hand experience on this one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ok now that I have you sold on how awesome tailwindcss is let's add it to your ember project!&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding tailwindcss to an ember app
&lt;/h3&gt;

&lt;p&gt;Previously we could install the library using &lt;code&gt;ember-cli-tailwind&lt;/code&gt; by the great people at &lt;a href="//embermap.com"&gt;embermap&lt;/a&gt; but it has been deprecated in favour of another package. While more configurable and undoubtably    better there is a little more setup involved and since I use it &lt;em&gt;a lot&lt;/em&gt; I want to write a small guide on adding it to your projects.&lt;/p&gt;

&lt;p&gt;So this section covers how we can get an ember app up and running with tailwind but if your pretty comfortable with embers basics you can check out the excellent documentation on the github page &lt;a href="https://github.com/chrism/emberjs-tailwind-purgecss"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting started
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;skip this if it's an existing app&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First of all let's get ember installed. We'll need a version of node installed first, details here. Then we can install ember using ‘npm' like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;ember-cli &lt;span class="nt"&gt;-g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have ember installed we can create our new project and set it running with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ember new tailwind-app
&lt;span class="nb"&gt;cd &lt;/span&gt;tailwind-app/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
   A quick proof of concept
&lt;/h3&gt;

&lt;p&gt;Now before we dive into setting up tailwind let's first create a small example that uses tailwind classes, that way we know they are working later. Add the following to your &lt;code&gt;app/templates/application.hbs&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight handlebars"&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;"flex items-center justify-center h-screen bg-gray-100"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"shadow-md hover:shadow-lg hover:bg-green-500 bg-green-400 text-white px-8 py-5 rounded"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    A beautiful button!
  &lt;span class="nt"&gt;&amp;lt;/button&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;Now to get our ember app up and running we need to run &lt;code&gt;ember serve&lt;/code&gt;. Once that's finished building visit &lt;code&gt;localhost:4200&lt;/code&gt; in your browser. You should see the following beautiful button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7BORza59--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9dzhrs0wk7pglf1skahz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7BORza59--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9dzhrs0wk7pglf1skahz.png" alt="plain-button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;..... anyway on with the tutorial!&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring PostCSS
&lt;/h3&gt;

&lt;p&gt;The next step is to add tailwind itself and configure it into the ember build pipeline. It's easier than it sounds I swear. To start we will need the following dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add ember-cli-postcss tailwindcss postcss-import @fullhuman/postcss-purgecss &lt;span class="nt"&gt;-D&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we need to generate the tailwind configuration file. To do this we need to enter the tailwind directory within our app and run the tailwind init command using &lt;code&gt;npx&lt;/code&gt; (&lt;code&gt;npm install npx -g&lt;/code&gt; if you don't have it).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;app/tailwind
npx tailwind init app/tailwind/config.js &lt;span class="nt"&gt;--full&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;For a real project we wouldn't want to use &lt;code&gt;--full&lt;/code&gt; as it includes all of Tailwinds default configuration. You can see more info on this &lt;a href="https://tailwindcss.com/docs/configuration/#creating-your-configuration-file"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before going further you might want to add &lt;code&gt;/*global module*/&lt;/code&gt; to the top of our new config file to suppress build warnings&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Only two more steps left to go! Now we want to configure PostCSS in the Ember Build Pipeline. To do this we need to open &lt;code&gt;ember-cli-build.js&lt;/code&gt; and update it to look like the following:&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;// ember-cli-build.js&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&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;EmberApp&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;ember-cli/lib/broccoli/ember-app&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;isProduction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;EmberApp&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="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&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;purgeCSS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;module&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;@fullhuman/postcss-purgecss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;// add extra paths here for components/controllers which include tailwind classes&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app/index.html&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;./app/templates/**/*.hbs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;defaultExtractor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&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;A-Za-z0-9-_:&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="o"&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;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="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;EmberApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;postcssOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;compile&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="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;module&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;postcss-import&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;path&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;node_modules&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app/tailwind/config.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;isProduction&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;purgeCSS&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toTree&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wiring up Tailwind
&lt;/h3&gt;

&lt;p&gt;The last step is to create a new css file and ensure that the tailwind css is included. We want to create &lt;code&gt;app/styles/components.css&lt;/code&gt; and &lt;code&gt;app/styles/utilities.css&lt;/code&gt; and include them in our existing &lt;code&gt;app/styles/app.css&lt;/code&gt; file like the following.&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="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss/base"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss/components"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"components.css"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss/utilities"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"utilities.css"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Awesome! Now we can restart our app (running &lt;code&gt;ember serve&lt;/code&gt;) and we should have a styled application! Our template should look like the below image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ReRZ-ffa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/xpk2yondiukh17p4mm5q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ReRZ-ffa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/xpk2yondiukh17p4mm5q.png" alt="finished-button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's a bit better 😄.&lt;/p&gt;

</description>
      <category>ember</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Static Types in EmberJs?</title>
      <dc:creator>James Byrne </dc:creator>
      <pubDate>Mon, 10 Jun 2019 08:04:20 +0000</pubDate>
      <link>https://dev.to/jamesbyrne/static-types-in-emberjs-26b7</link>
      <guid>https://dev.to/jamesbyrne/static-types-in-emberjs-26b7</guid>
      <description>&lt;h1&gt;
  
  
  Static Types in EmberJs?
&lt;/h1&gt;

&lt;p&gt;So you’ve decided to add Typescript to your Ember project. You’ve heard all about the benefits of Static Typing and how it will deliver a more maintainable codebase than plain ol’ javascript (couldn’t be that hard right?).&lt;/p&gt;

&lt;p&gt;Well before you dive in head first there are a few points I’d recommend you consider. After all, this is a change to your underlying programming language (yes I know it’s a superset and more on that later) so some pros and cons are to be expected. But to start of positive, let’s look at some of the upsides first.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note I will not be discussing Classes or decorators much in this doc, if you want an intro to them I highly recommend &lt;a href="https://www.pzuraq.com/coming-soon-in-ember-octane-part-1-native-classes/"&gt;this post&lt;/a&gt; by &lt;a href="https://www.pzuraq.com"&gt;pzuraq&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Good
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Benefits of Static Typing
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8EEiayPZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/asgg0162nmx4sphls8tq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8EEiayPZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/asgg0162nmx4sphls8tq.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is now my favourite meme ever&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Probably the most talked about feature of Typescript is its Static Types which we can use to specify the type of value we expect from a paramter/variable. This in turn gives the Typescript compiler the ability to catch common errors in the compile step, reducing the number of bugs that make it to production.&lt;/p&gt;

&lt;p&gt;An example of this would be parsing some data structure. Let’s say we are parsing an error but that the error can take a number of shapes. It can be a string or an object containing a list of strings. A potential solution might look 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;function&lt;/span&gt; &lt;span class="nx"&gt;getAllErrors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&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;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This looks good at first glance, we take in an error, check it’s types and if it matches what we want we return it, otherwise we return an empty list. However there is an bug here, if &lt;code&gt;error&lt;/code&gt; is passed as &lt;code&gt;null&lt;/code&gt; it will fail the first &lt;code&gt;if&lt;/code&gt; statement but pass the later.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;because of course &lt;code&gt;typeof null === 'object'&lt;/code&gt; ….&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Obviously that is not what we want. Luckily Static Typing will catch this error. Let’s start by writing the types (something you should always do first).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ErrorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ErrorMessage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PotentialError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;ErrorMessage&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ok now we have a good idea what the shape of our data structures will be and we can express the intent of our function more clearly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getAllErrors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PotentialError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ErrorMessage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isErrorMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Much nicer! But wait! What are those new functions? &lt;code&gt;isErrorMessage&lt;/code&gt; and &lt;code&gt;isError&lt;/code&gt;? Well those are type guards. They allow you to tell the typescript compiler what type is being returned. So for instance the &lt;code&gt;isError&lt;/code&gt; type guard could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PotentialError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;errors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And now that the compiler knows the type of the error, if we tried to change the return statement to return a parameter not in the &lt;code&gt;Error&lt;/code&gt; interface or return the first index of &lt;code&gt;errors.errors&lt;/code&gt; like below our compiler will tell us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="c1"&gt;//                               ^&lt;/span&gt;
&lt;span class="c1"&gt;//                               |&lt;/span&gt;
&lt;span class="c1"&gt;// Type string is not assignable to type string[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is a big win for maintainability because we know exactly what to expect from functions we have written and more importantly ones we didn't.&lt;/p&gt;

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

&lt;p&gt;Notice as well how clear the implementation of our example function is now. Previously, since this is a utility function meant for usage throughout the application, I would have written a set of comments like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* @method getAllErrors/1
 * @return List(Object)
 *
 * If it is a simple error (a
 * string) then that will be returned as
 * the expected return type.
 *
 * If a list of errors are found within
 * the object they will be returned.
 *
 * If it is not a string or an object we
 * will return an empty list.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getAllErrors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&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;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As the application becomes more complex I would consider this type of information to be the bare minimum required (more on that in a minute). Knowing the return types and the types of parameter a function accepts will let us both avoid issues when using the function and create a clear boundary within which we can refactor the function itself.&lt;/p&gt;

&lt;p&gt;Now if we consider the same Typescript code, it’s obvious these comments are no longer required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getAllErrors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PotentialError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ErrorMessage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;More than that these types will &lt;em&gt;have&lt;/em&gt; to stay up to date as we refactor (a big problem with regular comments) and they will give us extra information through compiler warnings and editor tools. I did say this was the bar minimum information required though so I will touch on that briefly.&lt;/p&gt;

&lt;p&gt;Typescript gives us the types to answer the &lt;em&gt;what&lt;/em&gt; of a function but not the &lt;em&gt;why&lt;/em&gt;. For very simple functions just the name of the function is enough but sometimes a function will be quite complex, have a limited scope or have side effects. These things should still be recorded within the functions documentation. Otherwise we can’t know when to use a function or more importantly &lt;em&gt;when not too&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In the case where documentation is still required (the &lt;em&gt;why&lt;/em&gt; of a function is complex) the Typescript eco-system provides &lt;a href="https://github.com/Microsoft/tsdoc"&gt;TsDoc&lt;/a&gt;. This is a standard way of writing documentation that also works with tooling such as the vscode editor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tooling
&lt;/h3&gt;

&lt;p&gt;Another benefit of Typescript is its excellent editor integration, especially with &lt;a href="https://code.visualstudio.com/docs/languages/typescript"&gt;VsCode&lt;/a&gt; where it offers intellisense, tools for refactoring, debugging, linting, documentation and formatting. All of these things will be surfaced by your editor and the compiler.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For Vim users check out &lt;a href="https://github.com/Quramy/tsuquyomi"&gt;tsuquyomi&lt;/a&gt; to get a similar set of tools&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  A Superset
&lt;/h3&gt;

&lt;p&gt;Maybe Typescripts biggest feature and without question one of the biggest reasons for its growth. It’s a superset of javascript, which means that any javascript is also valid typescript. This makes becoming a typescript developer as easy as re-naming your &lt;code&gt;.js&lt;/code&gt; files to &lt;code&gt;.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;From there you can gradually type more and more of the code and make the compiler stricter until your whole codebase (or whatever amount you want) is fully written with Typescript in mind. This is huge for existing projects that don’t want to start all over again but still want the benefits of a typed language.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note you will need to configure some sort of build pipeline but I’m considering that as separate&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Bad
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Breaking Changes
&lt;/h3&gt;

&lt;p&gt;Unfortunately Typescript does not strictly follow &lt;a href="https://github.com/Microsoft/TypeScript/issues/14116"&gt;semver&lt;/a&gt;, something we take for granted within the Ember eco-system. Due to marketing pressure breaking changes are introduced through minor versions, though they do maintain some semblance of semver after that. A helpful diagram/comment from &lt;a href="https://github.com/Microsoft/TypeScript/issues/14116#issuecomment-280915422"&gt;niieani&lt;/a&gt;  shows how we should approach this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       marketing
           ∨
TypeScript 2.34.2.1
             ∧∧ ∧ ∧
          major ∧ patch
                ∧
              minor
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is a problem in an eco-system that expects things to follow server and not make breaking changes on minor releases. But it surfaces a bigger problem. Besides Ember itself (though this applies to all frameworks), Typescript has the potential to require the largest refactors of your codebase.&lt;/p&gt;

&lt;p&gt;Although unlikely, any fundamental changes to Typescript will have a knock on effect to your codebase and potentially a large swath of it. This makes the lack of semver even more concerning and is something that must be considered carefully before diving straight in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conventions &amp;amp; Expertise
&lt;/h3&gt;

&lt;p&gt;Another consideration which I think is often glossed over is conventions and the expertise of your team. Sure Typescript is a super set of javascript but that doesn’t mean your team is positioned to take advantage of that. For instance, a question that arises from our previous example.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Should the types we declared above exist within a global types file?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How would you answer this question? I can definitely see the &lt;code&gt;PotentialError&lt;/code&gt; type being used elsewhere in the application and Typescript offers us a way of declaring a global type within a project.&lt;/p&gt;

&lt;p&gt;It sounds reasonable and useful, however my answer would be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No. They are too specific, any global &lt;code&gt;Error&lt;/code&gt; type would have to be far more generic. These types are specific to the structures expected by the functions within the file. At best they could be some sub-type of a broader type within the global types namespace.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I am lucky to have worked with a variety of different languages and frameworks from early in my career that includes both typed and non-typed languages. But not all teams have that kind of experience and coming from a Javascript background it will be important to make sure your team has the expertise they need to make the right decisions. Otherwise you can create one hell of a mess.&lt;/p&gt;

&lt;h3&gt;
  
  
  Missing Typings
&lt;/h3&gt;

&lt;p&gt;Unfortunately not every library comes with a set of types fresh out of the oven. As a result you may run into issues where common libraries don’t have types. “Sure no problem, it’s a superset, it will still work” I hear you say.&lt;/p&gt;

&lt;p&gt;While true the Typescript compiler &amp;amp; tools are able to strut their stuff best when the configuration is stricter. This will lead to errors &amp;amp; warnings when attempting to compile code that does not have types or at the least no type safety, which kind of defeats the point.&lt;/p&gt;

&lt;p&gt;Now there are great projects such as &lt;a href="https://definitelytyped.org/"&gt;DefinitelyTyped&lt;/a&gt; which provides a huge library of type definitions but even then common libraries such as &lt;a href="http://ember-concurrency.com/docs/introduction/"&gt;ember-concurrency&lt;/a&gt; and &lt;a href="https://embermap.github.io/ember-data-storefront/"&gt;Ember Data Storefront&lt;/a&gt; do not have types. This means either adding your own types though a &lt;code&gt;.d.ts&lt;/code&gt; (a type definitions file) or compromising on the type safety you are supposed to rely on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transitioning To Typescript
&lt;/h2&gt;

&lt;p&gt;So you’ve got this far and you’re undeterred, well then let’s outline a simple method of transitioning your existing Ember application to use Typescript.&lt;/p&gt;

&lt;p&gt;Firstly we will install the excellent project &lt;a href="https://github.com/typed-ember/ember-cli-typescript"&gt;&lt;code&gt;ember-cli-typescript&lt;/code&gt;&lt;/a&gt;  which will take care of building &amp;amp; converting our typescript files for us. This is the simplest way of setting up Typescript but it does have &lt;a href="https://typed-ember.github.io/ember-cli-typescript/docs/ts-guide/current-limitations"&gt;limitations&lt;/a&gt; that we should be aware of.&lt;/p&gt;

&lt;p&gt;As for typing the application itself &lt;a href="https://github.com/mike-north"&gt;Mike North&lt;/a&gt;  recommends the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start with allowing implicit &lt;code&gt;anys&lt;/code&gt; and just rename all &lt;code&gt;.js&lt;/code&gt; files to &lt;code&gt;.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add as much type info as possible without going into detail. Opt for explicit &lt;code&gt;any&lt;/code&gt;. Ban implicit &lt;code&gt;any&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go into detail at certain, commonly used, modules (services, models etc)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By following these steps we can convert our whole application to typescript without interfering with other members of the team or preventing feature work.&lt;/p&gt;

&lt;p&gt;And there you have it, Typescript in Ember with minimum fuss!&lt;/p&gt;

</description>
      <category>ember</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Ember Two Years On</title>
      <dc:creator>James Byrne </dc:creator>
      <pubDate>Sat, 07 Jul 2018 21:30:02 +0000</pubDate>
      <link>https://dev.to/jamesbyrne/ember-two-years-on-ele</link>
      <guid>https://dev.to/jamesbyrne/ember-two-years-on-ele</guid>
      <description>&lt;h3&gt;
  
  
  A Retrospective
&lt;/h3&gt;

&lt;p&gt;I’ve been programming professionally for a little over two years now. The majority of my time has been spent using Elixir, Erlang, Ruby on Rails and EmberJs with a brief stint of contracting with Angular 4 thrown in. &lt;/p&gt;

&lt;p&gt;Ergo I thought with my new found knowledge why not write some of it down so people on the internet could tell me I’m wrong! ....... wait.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I like about ember
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Out of the box
&lt;/h4&gt;

&lt;p&gt;Embers &lt;strong&gt;&lt;em&gt;convention over configuration&lt;/em&gt;&lt;/strong&gt; setup (the cool kids call this Zero-Config now) allows you to get up and running with your new project in the time it takes to run yarn/npm install. Which is anytime between now and the heat death of the universe, but you get my point. &lt;/p&gt;

&lt;p&gt;This is really great for experimenting since you don’t need to spend any time on setup, just get working. With bigger projects you get the same benefit &lt;em&gt;but&lt;/em&gt;, with the confidence that your project will scale over time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Solid Development Experience
&lt;/h4&gt;

&lt;p&gt;One of the things I love about Ember is the development experience. Over the last two years I have learned &lt;strong&gt;&lt;em&gt;alot!&lt;/em&gt;&lt;/strong&gt; Part of this has been how to best utilise the languages, patterns and frameworks at my disposal. &lt;/p&gt;

&lt;p&gt;With Ember I’ve learned how to use the conventions and where I can lean on the framework to do the heavy lifting for me. This means I spend less time bike shedding and more time being productive. But the best part is that I am still seeing these results two years on. Partly due to the ecosystems growth in that time and partly due to a better mastery of existing tools. &lt;/p&gt;

&lt;p&gt;The much loved &lt;a href="https://github.com/machty/ember-concurrency"&gt;ember-concurrency&lt;/a&gt; addon is a great example of this. Being new I wrote a lot of mixed synchronous/asynchronous state management code that turned out to be hard to manage and inflexible (sue me :P). Over the last year when working on smaller apps I have learned how to massively simplify managing state across an ember application using ember-concurrency &lt;code&gt;tasks&lt;/code&gt; (generator functions).&lt;/p&gt;

&lt;p&gt;As a result this new code is easier to test, maintain, change and most importantly, it’s simple. Something which is often overlooked in application design and programming but which is vitally important.&lt;/p&gt;

&lt;h4&gt;
  
  
  Community
&lt;/h4&gt;

&lt;p&gt;The Ember community is awesome, simple as that. Both the core team and the community at large are extremely friendly and there is a real spirit around the project. It’s not driven by one of the big corporations or by a single person but rather the collective passion of the commun-. Ohh that was close, if I said the "comm" word three times Jono Bacon might appear. &lt;/p&gt;

&lt;h4&gt;
  
  
  The PWA Story
&lt;/h4&gt;

&lt;p&gt;Now this is easily the thing I am most excited about. Ember has a number of really cool addons such as &lt;a href="https://github.com/DockYard/ember-service-worker"&gt;ember-service-worker&lt;/a&gt;, &lt;a href="https://github.com/sir-dunxalot/ember-cli-concat"&gt;ember-cli-concat&lt;/a&gt; and &lt;a href="https://github.com/ivanvanderbyl/ember-cli-critical"&gt;ember-cli-critical&lt;/a&gt; that make creating Progressive Web Apps  much much easier. Dockyard has made a &lt;a href="https://dockyard.com/blog/2017/07/20/how-to-build-a-pwa-with-ember"&gt;great post&lt;/a&gt; showing just how easy it is to upgrade a standard app into a PWA. &lt;/p&gt;

&lt;p&gt;And it doesn’t stop there, both &lt;a href="https://github.com/pouchdb-community/ember-pouch"&gt;ember-pouch&lt;/a&gt; and &lt;a href="https://github.com/orbitjs/ember-orbit"&gt;ember-orbit&lt;/a&gt; create a compelling story for apps that need to allow collaboration and creation while still offline and sync changes once a connection is re-established. A keen interest for me.&lt;/p&gt;

&lt;p&gt;This is something I am really excited about and I can’t wait to see what the state of Progressive Web Apps will look like in the future. &lt;em&gt;shakes fist at safari &amp;amp; iOS&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Things I don’t like
&lt;/h3&gt;

&lt;p&gt;So here’s the rub, there are not many things I dislike about Ember itself. I am a big believer of the &lt;em&gt;right tool for the job&lt;/em&gt; mentality. As a result I don’t have many complaints, because the problem isn’t an issue with Ember it’s just not the right tool for the job I want to complete. For instance, if I wasn’t building a Single Page App, I wouldn’t choose Ember. Is that a bad thing? No, it’s just not the right tool. And saying that a framework should be able to do everything is like saying a language should be able to do the same. It’s a fools errand. &lt;/p&gt;

&lt;p&gt;As a result I find the things I am not impressed with are not issues with Ember per say, but rather things I wish Javascript had. For instance I am really looking forward to having better Typescript support in Ember. My brief foray back into the Angular world (note to self: don’t mention the war) allowed me to experiment with Typescript in a real world project and I found it very useful in practice. &lt;/p&gt;

&lt;p&gt;I would also love for functional programming to become more widely used within the Ember ecosystem, but unfortunately the trend seems to be going in the other direction. Which again, is not a bad thing, just the way the tool works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing comments
&lt;/h3&gt;

&lt;p&gt;Overall I have really enjoyed my time with Ember. Compared to the other frameworks, libraries and languages I have tried, Ember has struck a cord with me in both the values it maintains and the practical benefits it boasts. Looking forward I am excited to see what comes next for Ember and how it will help me deliver value for my users.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. Also have you seen the mascots? &lt;a href="https://www.emberjs.com/mascots/"&gt;They are awesome!&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ember</category>
    </item>
  </channel>
</rss>
