<?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: Daniel Elkington</title>
    <description>The latest articles on DEV Community by Daniel Elkington (@danielelkington).</description>
    <link>https://dev.to/danielelkington</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%2F82772%2F83023ddf-9c80-40e3-a2ae-44f8c4a4d8dd.jpeg</url>
      <title>DEV Community: Daniel Elkington</title>
      <link>https://dev.to/danielelkington</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/danielelkington"/>
    <language>en</language>
    <item>
      <title>Teaching coding to kids</title>
      <dc:creator>Daniel Elkington</dc:creator>
      <pubDate>Sun, 28 Aug 2022 12:54:25 +0000</pubDate>
      <link>https://dev.to/danielelkington/teaching-coding-to-kids-1fj7</link>
      <guid>https://dev.to/danielelkington/teaching-coding-to-kids-1fj7</guid>
      <description>&lt;p&gt;Recently I was invited to teach an 80 minute programming class to a small class of high school students with special needs. I'm aware of some fantastic resources such as &lt;a href="https://hourofcode.com/"&gt;Hour of Code&lt;/a&gt;, which provides free short coding activities designed for absolute beginners. However, I find that these activities don't always feel "real" - you're usually writing code within a web app that feels like a game, and after writing the code required it feels more like you've simply won a game instead of having actually &lt;em&gt;created&lt;/em&gt; an app that can be run and shared with others. Hour of Code is great for teaching students the logical thinking required when coding, but I feel like it misses the potential excitement that one could have in finding that they can actually &lt;em&gt;build an app&lt;/em&gt; like the ones they use each day.&lt;/p&gt;

&lt;p&gt;So I decided to try designing my own class to introduce students to code. My aims were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero setup - students should not need to install anything new on their laptops&lt;/li&gt;
&lt;li&gt;Students should use a real programming language&lt;/li&gt;
&lt;li&gt;Students should start with an empty file, type some code in it, and run it to see the result&lt;/li&gt;
&lt;li&gt;Students should need to copy as little boilerplate code as possible&lt;/li&gt;
&lt;li&gt;The code should do something visual and fun&lt;/li&gt;
&lt;li&gt;The code should use very simple programming concepts such as function calls, and basic control flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And so I created &lt;a href="https://github.com/danielelkington/tribot"&gt;Tribot&lt;/a&gt;, a library that allows programmers to easily create a website where a triangular robot (or Tribot) attempts to retrieve some treasure.&lt;/p&gt;

&lt;p&gt;I wasn't sure how it would go. I was worried that my class might be too advanced for the students, and they would just become frustrated. Or maybe they would find it boring compared to the more game-like Hour of Code activities that are available.&lt;/p&gt;

&lt;p&gt;Anyway, here's how it went.&lt;/p&gt;

&lt;p&gt;First I introduced myself, explaining that I was a software developer who makes apps and games. The students all had laptops, and I got them all to open up Chrome and showed them how to open the DevTools, which they'd never seen before. They then followed along as I executed some basic commands into the console. They learned how to do a JavaScript &lt;code&gt;alert&lt;/code&gt;, a &lt;code&gt;prompt&lt;/code&gt;, and basic control flow as we wrote a very simple program 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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What is your name?&lt;/span&gt;&lt;span class="dl"&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;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bob&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;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello Bob!!!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What an interesting name!&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;Having experienced the basics of JavaScript, it was time to introduce the Tribot. I got them to open up TextEdit/Notepad, and they copied the following boilerplate, which imported the library I created:&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://unpkg.com/tribot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// Your code goes here&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then showed them how to save this as &lt;code&gt;index.html&lt;/code&gt; and open the file in their browser, and they saw this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yMoW-1MT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6s4p6u98hzyatlswbt4d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yMoW-1MT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6s4p6u98hzyatlswbt4d.png" alt="A game-like interface with a simple 5x2 grid. A red triangular robot is in the upper left corner, a treasure chest is in another cell, and there is a start button." width="880" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking "Start" didn't do anything - it was up to them to make the robot go to the treasure. I showed them a few commands, and they soon got the hang of it - they could move the robot with commands 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="nx"&gt;moveForward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;turnRight&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;moveForward&lt;/span&gt;&lt;span class="p"&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--8vk1B-0w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8hl1tvlcls61j0sp6mdq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8vk1B-0w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8hl1tvlcls61j0sp6mdq.gif" alt="After clicking start, the Tribot moves one cell forward, turns right, then moves forward another cell." width="880" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They could also have fun running functions to change the Tribot's colour and make it beep.&lt;/p&gt;

&lt;p&gt;At this point they quickly got into the hang of changing some code, saving the file, and refreshing the browser to run it.&lt;/p&gt;

&lt;p&gt;(If you know JavaScript you may be confused about how the code is working under the hood - how can they call synchronous functions to move the Tribot without freezing the browser? The answer is that when we load the page we run the whole script but simply save the actions performed, and then gradually replay them with some delays to animate the Tribot.)&lt;/p&gt;

&lt;p&gt;Soon enough some of the students were able to get the Tribot to reach the treasure. At this point I told them that there was another function they could call at the start of their script - &lt;code&gt;setRoom(2)&lt;/code&gt; to change to another room. And there were 3 rooms in total for them to try.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--u-snhJ_p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u7gbkdzs3aoh355q2tn4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u-snhJ_p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u7gbkdzs3aoh355q2tn4.png" alt="A different layout with obstacles as well as treasure." width="880" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some of the students were able to quickly get the Tribot winning in these rooms, so I then revealed that they could create their own custom rooms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;setRoom&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&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;W&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;W&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;W&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 finally I challenged them to see whether they could write some code for a Tribot that could find the treasure in &lt;em&gt;any room&lt;/em&gt; without needing its code changed.&lt;/p&gt;

&lt;p&gt;Overall the students seemed to enjoy the class, and were all able to get through at least part of the activity. Some of them were asking really good questions about how they could go about putting this web app on the internet, or how they could add keyboard controls to the Tribot.&lt;/p&gt;

&lt;p&gt;Very exciting to see how fast these students were able to learn some simple programming - I'm sure they all have bright futures ahead of them.&lt;/p&gt;

&lt;p&gt;The Tribot code is open source and freely available on &lt;a href="https://github.com/danielelkington/tribot"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>teaching</category>
    </item>
    <item>
      <title>Vue Camera Gestures - add AI powered gesture controls to your app in 1 line of HTML</title>
      <dc:creator>Daniel Elkington</dc:creator>
      <pubDate>Sat, 19 Oct 2019 10:52:28 +0000</pubDate>
      <link>https://dev.to/danielelkington/vue-camera-gestures-add-ai-powered-gesture-controls-to-your-app-in-1-line-of-html-35j4</link>
      <guid>https://dev.to/danielelkington/vue-camera-gestures-add-ai-powered-gesture-controls-to-your-app-in-1-line-of-html-35j4</guid>
      <description>&lt;p&gt;Consider a basic Vue application. There's a ball, and clicking "left" or "right" buttons make it move left or right.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y2BFxsce--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/a5kmk2boveynpwxyxd83.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y2BFxsce--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/a5kmk2boveynpwxyxd83.gif" alt='Red ball in a box with "Left" and "Right" buttons underneath. Clicking the buttons moves the ball in that direction.'&gt;&lt;/a&gt;&lt;br&gt;
We'll suppose that you have a component called &lt;code&gt;MovingBall&lt;/code&gt; that deals with displaying the ball and moving it, and we are using that component as follows:&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;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;moving-ball&lt;/span&gt; &lt;span class="na"&gt;:direction=&lt;/span&gt;&lt;span class="s"&gt;"direction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/moving-ball&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"left"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Left&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"right"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Right&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;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MovingBall&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;./MovingBall&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;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;MovingBall&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="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;left&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;direction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;right&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;direction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Controlling the ball using buttons is a bit boring. What if you could instead control it by gesturing a direction to your device's camera?&lt;/p&gt;

&lt;p&gt;If you think that would take a lot of code to achieve, think again! I've just released a library, &lt;a href="https://vue.cameragestures.com"&gt;Vue Camera Gestures&lt;/a&gt;, that will let you do that in just one line in your component's template. We just need to install the library,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install vue-camera-gestures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;import and register the component,&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;CameraGestures&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-camera-gestures&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;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;CameraGestures&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and put the following line into our template, under the buttons.&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;camera-gestures&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;left=&lt;/span&gt;&lt;span class="s"&gt;"left"&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;right=&lt;/span&gt;&lt;span class="s"&gt;"right"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/camera-gestures&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And that's it! When the user opens the page, they'll be prompted to train a left and a right gesture, verify them, and then they can control the ball using the trained gestures.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--imgH-AZ6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/e39wuudhosk0f47wyn3n.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--imgH-AZ6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/e39wuudhosk0f47wyn3n.gif" alt='In a Chrome window, a camera feed is displayed with instructions to maintain a neutral position, and perform "left" and "right" gestures. The user does so. After this the user can use the trained gestures to control the movement of a ball.'&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that the gestures don't have to involve pointing - the user can do basically anything they're comfortable with. Under the hood, the &lt;a href="https://www.tensorflow.org/hub/tutorials/image_retraining"&gt;transfer learning&lt;/a&gt; technique is used to retrain an &lt;a href="https://github.com/tensorflow/tfjs-models/tree/master/mobilenet"&gt;existing image recognition library&lt;/a&gt;. We then use a &lt;a href="https://github.com/tensorflow/tfjs-models/tree/master/knn-classifier"&gt;KNN classifier&lt;/a&gt; algorithm which, after training, takes a frame of video, and finds the 10 nearest frames from the training phase that match. We assume that the user is performing the gesture that has the most matching cases.&lt;/p&gt;

&lt;p&gt;But you don't need to know any of that - you can just use the component, and have all the AI complexity abstracted away. The &lt;code&gt;camera-gestures&lt;/code&gt; component's events are completely configurable, and you can have as many of them as you like. So if you had a blogging app, you could do something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;camera&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;gestures&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;newPost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;savePost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;save&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;enterBoldText&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;undo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;undo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;redo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;redo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/camera-gestures&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and the user will be prompted to train the five gestures, and can then use them to control the blogging app. After training, the specified events will be fired whenever the user performs the associated gesture.&lt;/p&gt;

&lt;p&gt;Give it a go! Easily make your app more accessible/fun! Find a demo and full documentation at &lt;a href="https://vue.cameragestures.com"&gt;vue.cameragestures.com&lt;/a&gt; and explore the source code &lt;a href="https://github.com/danielelkington/vue-camera-gestures"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Vue's Darkest Day</title>
      <dc:creator>Daniel Elkington</dc:creator>
      <pubDate>Fri, 21 Jun 2019 12:33:18 +0000</pubDate>
      <link>https://dev.to/danielelkington/vue-s-darkest-day-3fgh</link>
      <guid>https://dev.to/danielelkington/vue-s-darkest-day-3fgh</guid>
      <description>&lt;p&gt;Today I was amazed to see the usually positive and friendly VueJS community descend into a bitter war. Two weeks ago Vue creator Evan You released a &lt;a href="https://github.com/vuejs/rfcs/pull/42"&gt;Request for Comment&lt;/a&gt; (RFC) for a new function-based way of writing Vue components in the upcoming Vue 3.0. Today a critical &lt;a href="https://www.reddit.com/r/vuejs/comments/c319el/vue_3_will_change_vue_in_a_big_way_current_syntax/"&gt;Reddit thread&lt;/a&gt; followed by similarly critical comments in a &lt;a href="https://news.ycombinator.com/item?id=20237568"&gt;Hacker News thread&lt;/a&gt; caused a flood of developers to flock to the original RFC to voice their outrage, some of which were borderline abusive. It was claimed in various places that&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All Vue code would have to be rewritten in a totally new way because the existing syntax was being removed and replaced with something else;&lt;/li&gt;
&lt;li&gt;All the time people had spent learning Vue had been wasted given everything was about to change;&lt;/li&gt;
&lt;li&gt;The new syntax was worse than the old, did not enforce structure, and would lead to spaghetti code;&lt;/li&gt;
&lt;li&gt;The Vue Core team had suddenly implemented a huge breaking change without any consultation;&lt;/li&gt;
&lt;li&gt;Vue is turning into React!&lt;/li&gt;
&lt;li&gt;No, Vue is turning into AngularJS/Angular!&lt;/li&gt;
&lt;li&gt;All HTML now needs to be written as a giant string!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With walls of negative comments on the Reddit Thread one may be surprised to discover on going to the &lt;a href="https://github.com/vuejs/rfcs/pull/42"&gt;RFC page&lt;/a&gt; that You's RFC has an overwhelmingly high ratio of positive to negative emoji reactions, and many of the initial comments were quite positive. Indeed, the very first comment is particularly full of praise.&lt;/p&gt;

&lt;p&gt;I was the person who wrote that first comment. I happened to get a notification that there was a new RFC, read it straight away, saw that it was just what I wanted from Vue 3.0 and that it would help immensely, and left the first comment within 15 minutes of the RFC being published to express my gratitude. I hope to expand here on why I think the new proposal is such a great idea, but first, to address some of the criticism.&lt;/p&gt;

&lt;p&gt;I suspect that many people got a little worked up after reading the Hacker News or Reddit threads which had some somewhat misleading comments, and voiced their outrage without reading &lt;a href="https://github.com/vuejs/rfcs/blob/function-apis/active-rfcs/0000-function-api.md"&gt;the original proposal&lt;/a&gt;. Evan You has now updated the proposal with a Q&amp;amp;A that addresses many of the issues people have, but to summarise,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don't need to rewrite any code if you don't want to - the new syntax is additive, and the old syntax will remain valid throughout Vue 3.0 and as long as it is still widely used. Even if it eventually gets removed from the Core code, &lt;a href="https://github.com/vuejs/rfcs/blob/function-apis/active-rfcs/0000-function-api.md#adoption-strategy"&gt;plugins could easily allow the old syntax to be still 100% valid&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Time spent learning Vue was not wasted - the new component syntax uses the same concepts that you spent time learning, and other concepts such as Single File Components, templates, and scoped styles work exactly the same.&lt;/li&gt;
&lt;li&gt;A change hasn't been made without consultation - &lt;em&gt;the RFC &lt;strong&gt;is&lt;/strong&gt; the consultation&lt;/em&gt;. The new syntax is still a long way from being released.&lt;/li&gt;
&lt;li&gt;And no, HTML code doesn't need to be written as a giant string.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A slightly more subjective point is that the new syntax is inferior to the old, and will lead to less structured code. I hope to demonstrate with a simple example why I got so excited when I saw the RFC, and why I think it is superior and will lead to &lt;em&gt;better&lt;/em&gt; structured code.&lt;/p&gt;

&lt;p&gt;Consider the following fun component that allows a user to enter details of their pet. Note that&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A message gets displayed when they finish typing their pet's name;&lt;/li&gt;
&lt;li&gt;Another message gets displayed after they select their pet's size.
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz95yojh27zop4b6gzcev.png" alt="Form before any data entered - messages are not displayed" width="400" height="213"&gt;
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf4h845ejlf1k3e1iay3.png" alt="Form after data entered - messages are displayed" width="400" height="346"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can try out a demo of the component &lt;a href="https://7c01h.codesandbox.io/"&gt;here&lt;/a&gt; and can view the full code using Vue 2.x &lt;a href="https://codesandbox.io/s/simplified-function-based-component-example-7c01h"&gt;here&lt;/a&gt; (see components/Vue2.vue).&lt;/p&gt;

&lt;p&gt;Consider the JavaScript of this component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&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="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;petName&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="na"&gt;petNameTouched&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;petSize&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="na"&gt;petSizeTouched&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;petNameComment&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="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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;petNameTouched&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;petName&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;petSizeComment&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="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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;petSizeTouched&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;switch &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;petSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Small&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I can barely see your pet!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Medium&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your pet is pretty average.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Large&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Wow, your pet is huge!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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="kc"&gt;null&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;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;onPetNameBlur&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="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;petNameTouched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;onPetSizeChange&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="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;petSizeTouched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="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;Essentially we have some data, properties computed off that data, and methods that manipulate that data. And notice that in Vue 2.x there is &lt;em&gt;no way to keep related things together&lt;/em&gt;. We can't keep the &lt;code&gt;petName&lt;/code&gt; data declaration next to the &lt;code&gt;petNameComment&lt;/code&gt; computed property or the &lt;code&gt;onPetNameBlur&lt;/code&gt; method because in Vue 2.x things are grouped by type.&lt;/p&gt;

&lt;p&gt;Of course this doesn't matter too much for a small example like this. But imagine a bigger example, that had multiple pieces of functionality that needed &lt;code&gt;data&lt;/code&gt;, &lt;code&gt;computed&lt;/code&gt;, &lt;code&gt;methods&lt;/code&gt;, and even a &lt;code&gt;watcher&lt;/code&gt; or two. There's currently &lt;em&gt;no good way&lt;/em&gt; to keep related things together! One might use something like Mixins or Higher Order Components but &lt;a href="https://www.vuemastery.com/conferences/vueconf-us-2019/state-of-vuenation"&gt;these have issues&lt;/a&gt; - it's hard to see where properties are coming from and there are problems with namespace clashing. (And yes, in this case it would be possible to split things into multiple components, but consider &lt;a href="https://codesandbox.io/s/function-based-component-rfc-tn99y"&gt;this similar example&lt;/a&gt; where it isn't.)&lt;/p&gt;

&lt;p&gt;Rather than organising components by option type, the new proposal allows us to organise components by actual functionality. It's similar to how you organise your personal files on your computer - you usually don't have a 'spreadsheets' folder and a 'word documents' folder, instead you might have a 'work' folder and a 'holiday plans' folder. Consider the above component written in the proposed syntax (as best as I am able to without seeing the output - let me know of any bugs you see!):&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;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Pet name&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;petNameState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;touched&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;petNameComment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;petNameState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;touched&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;petNameState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onPetNameBlur&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="nx"&gt;petNameState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;touched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// Pet size&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;petSizeState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;size&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="na"&gt;touched&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;petSizeComment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;petSizeState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;touched&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;switch &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;petSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Small&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I can barely see your pet!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Medium&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your pet is pretty average.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Large&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Wow, your pet is huge!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onPetSizeChange&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="nx"&gt;petSizeState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;touched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// All properties we can bind to in our template&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;petName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;petNameState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;petNameComment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;onPetNameBlur&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;petSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;petSizeState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;petSizeComment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;onPetSizeChange&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;Note that&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's ridiculously easy to group related things together;&lt;/li&gt;
&lt;li&gt;By looking at what gets returned by the setup function we can easily see what we have access to in our template;&lt;/li&gt;
&lt;li&gt;We can even avoid exposing internal state ('touched') that the template doesn't need access to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On top of that, the new syntax easily allows full TypeScript support which was difficult to achieve in the Vue 2.x object-based syntax. And we can easily extract out reusable logic into reusable functions. Something like&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;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;usePetName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;petNameState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;touched&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;petNameComment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;petNameState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;touched&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;petNameState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onPetNameBlur&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="nx"&gt;petNameState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;touched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;petName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;petNameState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;petNameComment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;onPetNameBlur&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="nf"&gt;usePetSize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;petSizeState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;size&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="na"&gt;touched&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;petSizeComment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;petSizeState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;touched&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;switch &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;petSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Small&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I can barely see your pet!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Medium&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your pet is pretty average.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Large&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Wow, your pet is huge!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onPetSizeChange&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="nx"&gt;petSizeState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;touched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;petSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;petSizeState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;petSizeComment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;onPetSizeChange&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;petName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;petNameComment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onPetNameBlur&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;usePetName&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;petSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;petSizeComment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onPetSizeChange&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;usePetSize&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;petName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;petNameComment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;onPetNameBlur&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;petSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;petSizeComment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;onPetSizeChange&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;In Vue 2.x I often find myself writing a "monster component" that is hard to break up into smaller pieces - it can't be decomposed into other components because there is too much happening based on a small amount of state. However using the proposed syntax it's easy to see how big components could have logic broken up into smaller reusable pieces, moved into separate files if necessary, leaving you with small, easy-to-understand functions and components.&lt;/p&gt;

&lt;p&gt;Is this Vue's darkest day so far? It looks like it. What was until now a community mostly united behind the project's direction has splintered. But I have hope that people will take another look at a proposal that doesn't break anything, &lt;a href="https://github.com/vuejs/rfcs/pull/42#issuecomment-502736555"&gt;still allows them to group things by option type if that's what they like doing&lt;/a&gt;, but allows for so much more - clearer code, cleaner code, more interesting library possibilities, and full TypeScript support.&lt;/p&gt;

&lt;p&gt;Finally, when using open source software, it's good to remember that the maintainers are putting a lot of effort into something that you get to use for free. Some of the borderline abusive criticism seen today is something that they really shouldn't have to put up with. Thankfully the disrespectful comments were a minority (albeit a sizeable one) and many were able to express themselves in a more respectful manner.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update June 23 2019:&lt;/strong&gt;&lt;br&gt;
I wrote the original post very quickly and without expecting it to &lt;a href="https://twitter.com/youyuxi/status/1142280533168119808"&gt;receive the attention that it has&lt;/a&gt;. Since then I've realised that the code example was too complex for the point I was trying to illustrate, so I've simplified it greatly. The original code sample can be found &lt;a href="https://codesandbox.io/s/function-based-component-rfc-tn99y"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vue</category>
    </item>
    <item>
      <title>A bot that tweets new DEV articles about Vue</title>
      <dc:creator>Daniel Elkington</dc:creator>
      <pubDate>Sun, 03 Mar 2019 10:41:33 +0000</pubDate>
      <link>https://dev.to/danielelkington/a-bot-that-tweets-new-dev-articles-about-vue-4p5a</link>
      <guid>https://dev.to/danielelkington/a-bot-that-tweets-new-dev-articles-about-vue-4p5a</guid>
      <description>&lt;p&gt;So I love &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;VueJS&lt;/a&gt;. And I love dev.to articles about Vue. And I don't want to miss any. I could just keep constantly refreshing the &lt;a href="https://dev.to/t/vue"&gt;#vue tag&lt;/a&gt; on dev.to, but instead I decided it would be more convenient to see all new Vue articles in my Twitter feed. So I wrote my a Twitter bot - &lt;a href="https://twitter.com/TheVueDev" rel="noopener noreferrer"&gt;@TheVueDev&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Basic architecture and flow
&lt;/h1&gt;

&lt;p&gt;The basic flow I decided on was the following&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Azure Function written in Typescript runs every minute,&lt;/li&gt;
&lt;li&gt;The function scrapes &lt;a href="https://dev.to/t/vue/latest"&gt;dev.to/t/vue/latest&lt;/a&gt; to check for new articles,&lt;/li&gt;
&lt;li&gt;If new articles are found, they get automatically tweeted!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An Azure Function is Microsoft Azure's "serverless" offering that allows you to run a small piece of code in response to some trigger. There's a generous free tier (&lt;a href="https://azure.microsoft.com/en-us/pricing/details/functions/" rel="noopener noreferrer"&gt;1 million free executions per month!&lt;/a&gt;) that means this project is very cheap, though not entirely free as the Function requires an Azure Storage account to store some things related to the function. Still, the overall cost for this project is less than US$1/month.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up Twitter
&lt;/h1&gt;

&lt;p&gt;Setting up the Twitter account is relatively straightforward (you just need to be prepared to answer a lot of questions that Twitter understandably asks to try to prevent abuse). After setting up a Twitter account for the bot at &lt;a href="http://twitter.com" rel="noopener noreferrer"&gt;twitter.com&lt;/a&gt;, I went to &lt;a href="https://developer.twitter.com" rel="noopener noreferrer"&gt;developer.twitter.com&lt;/a&gt; and followed the prompts to apply for a developer account. Finally, I created a new "app", filled in some more details, requested some access tokens, and was presented with a page that looks like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkj9yq1nsapbx89fmofer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkj9yq1nsapbx89fmofer.png" alt="The Twitter developer page with some access tokens and secret keys to copy"&gt;&lt;/a&gt;&lt;br&gt;
That's right, there are four tokens/keys, and we're going to need all of them!&lt;/p&gt;
&lt;h1&gt;
  
  
  The Function
&lt;/h1&gt;

&lt;p&gt;I followed the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-function-vs-code" rel="noopener noreferrer"&gt;quickstart guide&lt;/a&gt; in the Azure docs to create an Azure Function in Visual Studio code, selecting "JavaScript" as the language. I then ran &lt;code&gt;tsc --init&lt;/code&gt; to add TypeScript, and was ready to start coding!&lt;/p&gt;
&lt;h2&gt;
  
  
  Running code every minute
&lt;/h2&gt;

&lt;p&gt;For each function you create, you need to specify what will trigger it (find all the options &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-overview#what-can-i-do-with-functions" rel="noopener noreferrer"&gt;here&lt;/a&gt;). In my case I wanted to trigger the function every minute, which could be done with the following code in the function's &lt;code&gt;function.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"disabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bindings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"schedule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0 * * * * *"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"timerTrigger"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"in"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"everyMinuteTimer"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Scraping dev.to
&lt;/h2&gt;

&lt;p&gt;I want to thank Sarthak Sharma for his amazing Vue CLI - check it out if you haven't already. The code he used to scrape dev.to gave me a lot of pointers for this project.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;div class="ltag__link__content"&gt;
    &lt;div class="missing"&gt;
      &lt;h2&gt;Article No Longer Available&lt;/h2&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Like Sarthak, I used the &lt;a href="https://github.com/matthewmueller/x-ray" rel="noopener noreferrer"&gt;x-ray library&lt;/a&gt; to help with scraping. Every minute I want to load up &lt;a href="//dev.to/t/vue/latest"&gt;&lt;/a&gt;&lt;a href="https://dev.to/t/vue/latest"&gt;https://dev.to/t/vue/latest&lt;/a&gt; and scrape details of the latest VueJS articles. With the help of the Chrome devtools, grabbing things like the article title, author details, and a link to the article is quite straightforward - querying the page uses syntax very similar to CSS.&lt;br&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;xray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Xray&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;articleScrapeData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;xray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://dev.to/t/vue/latest&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;#substories .single-article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.index-article-link .content h3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h4 a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.index-article-link@href&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;tags&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;.tags .tag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// need the tags so we can strip them out of the title&lt;/span&gt;
      &lt;span class="na"&gt;authorLink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.small-pic-link-wrapper@href&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That will return an array of the articles on the page. There's a bit of cleanup of the data I needed to do (&lt;a href="https://github.com/danielelkington/twitter-vue-dev/blob/master/AutoTweetDevArticles/article.ts" rel="noopener noreferrer"&gt;here's the code&lt;/a&gt; if you're interested). Of course, it makes sense to tweet out the author's Twitter handle if they've provided it, so I scraped that from the Author page.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;socialLinks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;xray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorLink&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;.profile-details .social a@href&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;twitterLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socialLinks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;twitter.com/&lt;/span&gt;&lt;span class="dl"&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;twitterLink&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// twitterLink is in the form https://twitter.com/{blah}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;twitterURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;twitterLink&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;twitterHandle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;twitterURL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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;For each article, I could then construct the tweet. I decided that tweets would contain the article title, then the author's twitter handle or name, and finally a link to the article (which dev.to very nicely formats with a beautiful card).&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tweetContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&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="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitterHandle&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorName&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="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="c1"&gt;// Yay for Template Literals!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now all we need to do is Tweet the articles!&lt;/p&gt;
&lt;h2&gt;
  
  
  The dilemma
&lt;/h2&gt;

&lt;p&gt;The problem was that the function can't just tweet all the "recent articles" we find each minute, or we'll end up tweeting heaps of duplicates. Compounding the problem is that dev.to doesn't seem to provide an easy way to see when an article was published to anything more granular than the nearest day. I came up with three possible solutions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Only run the function once every 24 hours, and tweet out any articles with yesterday's date. Problem is that if the function fails for some reason we'll miss a day, and if it works followers need to wait up to 24 hours for new articles!&lt;/li&gt;
&lt;li&gt;Implement some sort of storage to keep track of the articles that have been tweeted. But this seems like a bit of overkill for a project like this. &lt;sup&gt;(You could argue that Typescript is also overkill for a project like this, but I wanted to use it for learning purposes ☺️)&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;Use the Twitter API to get the latest articles that the account has tweeted, do a comparison with the latest ones found on dev.to, and tweet out any that haven't yet been tweeted.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Option 3 seemed the most straightforward. Scraping &lt;a href="https://dev.to/t/vue/latest"&gt;dev.to/t/vue/latest&lt;/a&gt; only returns the last 8 articles, while the Twitter API returns the last 200 tweets from the account, so the function should always be able to accurately determine whether an article has been tweeted.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using the Twitter API
&lt;/h2&gt;

&lt;p&gt;Omar Sinan's article on building a Twitter bot was very helpful - check it out!&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;div class="ltag__link__content"&gt;
    &lt;div class="missing"&gt;
      &lt;h2&gt;Article No Longer Available&lt;/h2&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Like Omar, I used the &lt;a href="https://github.com/ttezel/twit" rel="noopener noreferrer"&gt;Twit&lt;/a&gt; library to help with tweeting. Connecting it to &lt;a href="https://twitter.com/TheVueDev" rel="noopener noreferrer"&gt;@TheVueDev&lt;/a&gt; was as simple as pasting in the four keys and tokens from the Twitter app page (as environment variables of course!).&lt;br&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Twit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;consumer_key&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;twitter_consumer_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;consumer_secret&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;twitter_consumer_secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;access_token&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;twitter_access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;access_token_secret&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;twitter_access_token_secret&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we just tweet out our articles if they haven't yet been tweeted!&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Get recent tweets&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&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;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;statuses/user_timeline&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;screen_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TheVueDev&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;recentTweets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
&lt;span class="c1"&gt;// Determine if article has been tweeted yet&lt;/span&gt;
&lt;span class="c1"&gt;// Need to look at entities.urls.expanded_url because Twitter &lt;/span&gt;
&lt;span class="c1"&gt;// automatically shortens the URL in the tweet itself.&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;recentTweets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expanded_url&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;articleLink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Article hasn't yet been tweeted - tweet it!&lt;/span&gt;
  &lt;span class="k"&gt;await&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;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;statuses/update&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tweetContent&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;(Find the more efficient version of this code &lt;a href="https://github.com/danielelkington/twitter-vue-dev/blob/master/AutoTweetDevArticles/tweet.ts" rel="noopener noreferrer"&gt;here&lt;/a&gt;.)&lt;/p&gt;
&lt;h1&gt;
  
  
  Deployment
&lt;/h1&gt;

&lt;p&gt;Deploying the function to Azure can be done right from within Visual Studio code with a few button clicks using the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions" rel="noopener noreferrer"&gt;Azure Functions extension&lt;/a&gt;. Neat!&lt;/p&gt;

&lt;p&gt;And with that, I have a functioning Twitter bot, and can now easily know about all the new VueJS articles as they appear on dev.to!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xisfpbgk3syi44ppp34.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xisfpbgk3syi44ppp34.png" alt="A tweet from my Twitter bot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/TheVueDev" rel="noopener noreferrer"&gt;Here's the Twitter account&lt;/a&gt;, and &lt;a href="https://github.com/danielelkington/twitter-vue-dev" rel="noopener noreferrer"&gt;here's the full code&lt;/a&gt;, with step-by-step instructions for deploying your own bot to tweet out any dev.to tag of your choice!&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/danielelkington" rel="noopener noreferrer"&gt;
        danielelkington
      &lt;/a&gt; / &lt;a href="https://github.com/danielelkington/twitter-vue-dev" rel="noopener noreferrer"&gt;
        twitter-vue-dev
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A bot that lives in Azure Functions and tweets all dev.to VueJS articles
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;twitter-vue-dev&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/danielelkington/twitter-vue-devimages/logo.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fdanielelkington%2Ftwitter-vue-devimages%2Flogo.png" width="400" alt="Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A bot that lives in Azure Functions and tweets all &lt;a href="https://dev.to" rel="nofollow"&gt;dev.to&lt;/a&gt; VueJS articles. Find it &lt;a href="https://twitter.com/TheVueDev" rel="nofollow noopener noreferrer"&gt;@TheVueDev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/danielelkington/a-bot-that-tweets-new-dev-articles-about-vue-4p5a" rel="nofollow"&gt;dev.to article explaining how this was created.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This same code can be used to create a Twitter bot that tweets new articles from any valid &lt;a href="https://dev.to" rel="nofollow"&gt;dev.to&lt;/a&gt; tag.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Deployment&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Follow these instructions to create your own Twitter bot that tweets &lt;a href="https://dev.to" rel="nofollow"&gt;dev.to&lt;/a&gt; articles for the tag of your choice. It will probably cost you a few cents a month in Azure Storage fees.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Setup Twitter account&lt;/h3&gt;
&lt;/div&gt;


&lt;ol&gt;

&lt;li&gt;

&lt;p&gt;Go to &lt;a href="https://twitter.com" rel="nofollow noopener noreferrer"&gt;twitter.com&lt;/a&gt; and make a Twitter account for your bot.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;While signed into your bot's Twitter account, go to &lt;a href="https://developer.twitter.com" rel="nofollow noopener noreferrer"&gt;developer.twitter.com&lt;/a&gt;, click "Apply", and then follow the prompts to apply for a developer account.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When asked to "Select a user profile to associate", ensure your bot's account is selected.&lt;/li&gt;
&lt;li&gt;Fill in the requested information about what your developer account will be used for, accept the terms and…&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/danielelkington/twitter-vue-dev" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>vue</category>
      <category>typescript</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
