<?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: Lewis Lloyd</title>
    <description>The latest articles on DEV Community by Lewis Lloyd (@tao).</description>
    <link>https://dev.to/tao</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%2F302936%2F980ece82-bcf9-44f4-aa78-b4e2cd066f92.jpg</url>
      <title>DEV Community: Lewis Lloyd</title>
      <link>https://dev.to/tao</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tao"/>
    <language>en</language>
    <item>
      <title>Adding Vitest to Nuxt 3 ⚡ (2023)</title>
      <dc:creator>Lewis Lloyd</dc:creator>
      <pubDate>Sun, 01 Jan 2023 23:43:38 +0000</pubDate>
      <link>https://dev.to/tao/adding-vitest-to-nuxt-3-2023-lpa</link>
      <guid>https://dev.to/tao/adding-vitest-to-nuxt-3-2023-lpa</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this post, we'll introduce Vitest for blazing-fast unit tests in your Nuxt 3 project.&lt;/p&gt;

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

&lt;p&gt;Unit tests are important for ensuring that your code is working correctly.&lt;/p&gt;

&lt;p&gt;This is especially important when making changes to your code, as you can ensure that you haven't introduced any new bugs or problems to existing features. Or, at least to the extent that these features have been covered by tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vitest
&lt;/h3&gt;

&lt;p&gt;Vitest is a test runner based on Vite, an alternative module bundler to webpack which Nuxt 3 uses by default.&lt;/p&gt;

&lt;p&gt;It's incredibly similar to &lt;strong&gt;Jest&lt;/strong&gt;, and often considered a drop-in replacement for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Packages
&lt;/h3&gt;

&lt;p&gt;Install 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;&lt;span class="c"&gt;# Vitest&lt;/span&gt;
yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; vitest jsdom @vitejs/plugin-vue

&lt;span class="c"&gt;# Test utils&lt;/span&gt;
yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; @vue/test-utils @nuxt/test-utils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;Create your Vitest configuration file (&lt;code&gt;vitest.config.js&lt;/code&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="c1"&gt;// vitest.config.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitejs/plugin-vue&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="nf"&gt;defineConfig&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="nf"&gt;vue&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsdom&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;h3&gt;
  
  
  ESLint integration
&lt;/h3&gt;

&lt;p&gt;If you're using ESLint from earlier in the series, you should also add its Vitest plugin:&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 &lt;span class="nt"&gt;--dev&lt;/span&gt; eslint-plugin-vitest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, modify your &lt;code&gt;.eslintrc.cjs&lt;/code&gt; file to add the plugin:&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;// .eslintrc.cjs&lt;/span&gt;

&lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scripts
&lt;/h3&gt;

&lt;p&gt;Add the following script to your project:&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vitest"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&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;
  
  
  Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating tests
&lt;/h3&gt;

&lt;p&gt;At this point, you should use a learning resource such as &lt;a href="https://www.youtube.com/watch?v=cM_AeQHzlGg" rel="noopener noreferrer"&gt;Testing with Vitest&lt;/a&gt; to get started.&lt;/p&gt;

&lt;p&gt;A test may look something like this:&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;// tests/HelloWorld.spec.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vue/test-utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;HelloWorld&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/HelloWorld.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HelloWorld&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;is a Vue instance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HelloWorld&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeTruthy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running tests
&lt;/h3&gt;

&lt;p&gt;To run your unit tests, use &lt;code&gt;yarn test&lt;/code&gt;.&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="nv"&gt;$ &lt;/span&gt;yarn &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; yarn run v1.22.5
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$ &lt;/span&gt;vitest
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;  DEV  v0.26.3 ~/Documents/GitHub/nuxt-app
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;  ✓ tests/HelloWorld.spec.ts &lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;  Test Files  1 passed &lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;       Tests  1 passed &lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;    Start at  23:19:54
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;    Duration  1.78s &lt;span class="o"&gt;(&lt;/span&gt;transform 538ms, setup 1ms, collect 154ms, tests 20ms&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;  PASS  Waiting &lt;span class="k"&gt;for &lt;/span&gt;file changes...
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;        press h to show &lt;span class="nb"&gt;help&lt;/span&gt;, press q to quit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All done!&lt;/p&gt;

&lt;p&gt;Now you can start shipping new features in peace 😉&lt;/p&gt;




&lt;p&gt;Hey, guys! Thank you for reading. I hope that you enjoyed this.&lt;/p&gt;

&lt;p&gt;Keep up to date with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://lloyd.cx/" rel="noopener noreferrer"&gt;https://lloyd.cx/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/lloydtao/" rel="noopener noreferrer"&gt;https://twitter.com/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/lloydtao/" rel="noopener noreferrer"&gt;https://github.com/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/lloydtao/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nuxt</category>
      <category>nuxt3</category>
      <category>vitest</category>
      <category>testing</category>
    </item>
    <item>
      <title>Adding Pinia to Nuxt 3 🍍 (2023)</title>
      <dc:creator>Lewis Lloyd</dc:creator>
      <pubDate>Sun, 01 Jan 2023 23:42:55 +0000</pubDate>
      <link>https://dev.to/tao/adding-pinia-to-nuxt-3-2023-3l77</link>
      <guid>https://dev.to/tao/adding-pinia-to-nuxt-3-2023-3l77</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this post, we'll introduce Pinia, a powerful package for managing your Nuxt app's state in a single place.&lt;/p&gt;

&lt;p&gt;Whether you're new to state management solutions or experienced with libraries such as Vuex and Redux, Pinia is definitely worth checking out.&lt;/p&gt;

&lt;h2&gt;
  
  
  State management
&lt;/h2&gt;

&lt;p&gt;If you've ever found yourself aimlessly trying to manage state through props and events, then the idea of a store may sound appealing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manage an app's state from a single, centralised store&lt;/li&gt;
&lt;li&gt;Update and retrieve data through simple actions and getters&lt;/li&gt;
&lt;li&gt;Subscribe to changes to achieve deep reactivity without much work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This helps to make changes to the app's state predictable and more consistent.&lt;/p&gt;

&lt;p&gt;For example, we can store a counter, and then increment it from anywhere by using its store:&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%2F1cf2kfethplnmjmvv3oj.gif" 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%2F1cf2kfethplnmjmvv3oj.gif" alt="Demo of counter component"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pinia
&lt;/h3&gt;

&lt;p&gt;Pinia is a state management library for Vue, with an officially-supported module for Nuxt 3 (&lt;code&gt;@pinia/nuxt&lt;/code&gt;). It's also the recommended solution for Vue and Nuxt projects.&lt;/p&gt;

&lt;p&gt;Don't just take it from me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Pinia is de facto Vuex 5!"&lt;/p&gt;

&lt;p&gt;— &lt;em&gt;Evan You, creator of Vue&lt;/em&gt; (&lt;a href="https://twitter.com/youyuxi/status/1463429442076745730" rel="noopener noreferrer"&gt;source&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What makes it useful for Vue and Nuxt applications?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deep reactivity by default&lt;/li&gt;
&lt;li&gt;No explicit mutations (all changes are implicit mutations)&lt;/li&gt;
&lt;li&gt;Analogous with Options API:

&lt;ul&gt;
&lt;li&gt;Actions (equivalent of &lt;code&gt;methods&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Getters (equivalent of &lt;code&gt;computed&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Official documentation for using Pinia with Nuxt can be found &lt;a href="https://nuxt.com/modules/pinia" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Install the package:&lt;/p&gt;

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

yarn add @pinia/nuxt


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

&lt;/div&gt;

&lt;p&gt;Add the module to your Nuxt configuration:&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;// nuxt.config.ts&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@pinia/nuxt&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;h2&gt;
  
  
  Creating a store
&lt;/h2&gt;

&lt;p&gt;Stores are created in a &lt;code&gt;stores/&lt;/code&gt; directory, and defined by using Pinia's &lt;code&gt;defineStore&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;In this example, we have created a store (&lt;code&gt;useCounterStore&lt;/code&gt;) and given the store a name (&lt;code&gt;counter&lt;/code&gt;). We have then defined our &lt;code&gt;state&lt;/code&gt; property (&lt;code&gt;count&lt;/code&gt;) with an initial value.&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;// stores/counter.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pinia&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useCounterStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;count&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="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;It's as simple as that!&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the store
&lt;/h2&gt;

&lt;p&gt;Pinia offers a few ways to access the store and maintain reactivity.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Store instance
&lt;/h3&gt;

&lt;p&gt;In your component's &lt;code&gt;setup()&lt;/code&gt;, import the store's &lt;code&gt;useStore()&lt;/code&gt; method.&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;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCounterStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/stores/counter&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="nf"&gt;defineComponent&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;useCounterStore&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;You can now access state through the store instance:&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;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&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="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

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

&lt;/div&gt;
&lt;h3&gt;
  
  
  2. Computed properties
&lt;/h3&gt;

&lt;p&gt;To write cleaner code, you may wish to grab specific properties. However, destructuring the store will break reactivity.&lt;/p&gt;

&lt;p&gt;Instead, we can use a computed property to achieve reactivity:&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;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineComponent&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="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCounterStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// ❌ Bad (unreactive):&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;

    &lt;span class="c1"&gt;// ✔️ Good:&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&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="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&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="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

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

&lt;/div&gt;
&lt;h3&gt;
  
  
  3. Extract via storeToRefs()
&lt;/h3&gt;

&lt;p&gt;You can destructure properties from the store while keeping reactivity through the use of &lt;code&gt;storeToRefs()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This will create a ref for each reactive property.&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;// components/MyCounter.vue&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;storeToRefs&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pinia&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCounterStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/stores/counter&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="nf"&gt;defineComponent&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="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCounterStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// ❌ Bad (unreactive):&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;

    &lt;span class="c1"&gt;// ✔️ Good:&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;storeToRefs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&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;count&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&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="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Actions
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Adding an action
&lt;/h3&gt;

&lt;p&gt;Actions are the equivalent of &lt;code&gt;methods&lt;/code&gt; in components, defined in the store's &lt;code&gt;actions&lt;/code&gt; property.&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;// stores/counter.ts&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useCounterStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;count&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="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;increment&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;count&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Using an action
&lt;/h3&gt;

&lt;p&gt;In your component, extract the action from the store.&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;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineComponent&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="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCounterStore&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;increment&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&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="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="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;The action can easily be invoked, such as upon a button being clicked:&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;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&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;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;increment&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;/button&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="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Getters
&lt;/h2&gt;

&lt;p&gt;Getters are the equivalent of &lt;code&gt;computed&lt;/code&gt; in components, defined in the store's &lt;code&gt;getters&lt;/code&gt; property.&lt;/p&gt;
&lt;h3&gt;
  
  
  Adding a getter
&lt;/h3&gt;

&lt;p&gt;Pinia encourages the usage of the arrow function, using the state as the first parameter:&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;// stores/counter.ts&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useCounterStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;count&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="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;getters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;getCount&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;=&amp;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;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;increment&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;count&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Using a getter
&lt;/h3&gt;

&lt;p&gt;Similarly to state properties, getters need to be accessed in a way that maintains reactivity.&lt;/p&gt;

&lt;p&gt;For instance, you could access it through the store instance:&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;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineComponent&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="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCounterStore&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;store&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCount&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&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="sr"&gt;/template&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;Or, by using a computed property:&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;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineComponent&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="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCounterStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// ❌ Bad (unreactive):&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;getCount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;

    &lt;span class="c1"&gt;// ✔️ Good:&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCount&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="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCount&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;getCount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;getCount&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&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="sr"&gt;/template&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;Or, by using &lt;code&gt;storeToRefs()&lt;/code&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;// components/MyCounter.vue&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;storeToRefs&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pinia&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCounterStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/stores/counter&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="nf"&gt;defineComponent&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="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCounterStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// ❌ Bad (unreactive):&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;getCount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;

    &lt;span class="c1"&gt;// ✔️ Good:&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;getCount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;storeToRefs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&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;getCount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;getCount&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&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="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

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

&lt;/div&gt;
&lt;h2&gt;
  
  
  A complete component
&lt;/h2&gt;

&lt;p&gt;Since we've discussed actions and getters separately, here is a code snippet that combines both in the style that I recommend:&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;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCounterStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/stores/counter&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="nf"&gt;defineComponent&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="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCounterStore&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;getCount&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="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCount&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;increment&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;store&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;getCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// components/MyCounter.vue&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;getCount&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&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;button&lt;/span&gt; &lt;span class="kd"&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;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;increment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Increment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&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="sr"&gt;/template&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;This code has been implemented at &lt;a href="https://github.com/lloydtao/nuxt-3-starter/" rel="noopener noreferrer"&gt;lloydtao/nuxt-3-starter/&lt;/a&gt;:&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%2F1cf2kfethplnmjmvv3oj.gif" 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%2F1cf2kfethplnmjmvv3oj.gif" alt="Demo of counter component"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How do you think your developer experience will be improved? 😉&lt;/p&gt;




&lt;p&gt;Hey, guys! Thank you for reading. I hope that you enjoyed this.&lt;/p&gt;

&lt;p&gt;Keep up to date with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://lloyd.cx/" rel="noopener noreferrer"&gt;https://lloyd.cx/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/lloydtao/" rel="noopener noreferrer"&gt;https://twitter.com/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/lloydtao/" rel="noopener noreferrer"&gt;https://github.com/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/lloydtao/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nuxt</category>
      <category>nuxt3</category>
      <category>pinia</category>
    </item>
    <item>
      <title>Adding Tailwind CSS to Nuxt 3 🍃 (2023)</title>
      <dc:creator>Lewis Lloyd</dc:creator>
      <pubDate>Sun, 01 Jan 2023 23:42:01 +0000</pubDate>
      <link>https://dev.to/tao/adding-tailwind-css-to-nuxt-3-2023-1eo7</link>
      <guid>https://dev.to/tao/adding-tailwind-css-to-nuxt-3-2023-1eo7</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this post, we'll introduce Nuxt Tailwind, a package for the Tailwind CSS library.&lt;/p&gt;

&lt;p&gt;Tailwind is a powerful tool for rapidly styling modern web applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utility-first CSS
&lt;/h2&gt;

&lt;p&gt;Utility-first CSS is a design approach that uses pre-defined classes to style HTML elements. We refer to these classes as &lt;strong&gt;utilities&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One of the main advantages of utility-first CSS is that it allows you to style elements quickly without coupling them to custom CSS through stylesheets. This approach can be difficult to maintain when an app grows bigger.&lt;/p&gt;

&lt;p&gt;You may argue that this will lead to code repetition, but when combined with component-based web frameworks (e.g. React, Vue), repetition is minimised while still keeping elements decoupled from stylesheets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tailwind
&lt;/h3&gt;

&lt;p&gt;Tailwind isn't just a fantastic way of writing CSS; it's also great to build with, due to a variety of development features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy configuration of built-in utilities&lt;/li&gt;
&lt;li&gt;Just-in-time compiler to avoid build times entirely&lt;/li&gt;
&lt;li&gt;Many great plugins available (typography, forms, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Official documentation for using Tailwind with Nuxt can be found &lt;a href="https://nuxt.com/modules/tailwindcss" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Install the package:&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 &lt;span class="nt"&gt;--dev&lt;/span&gt; @nuxtjs/tailwindcss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the module to your Nuxt configuration:&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;// nuxt.config.ts&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nuxtjs/tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just like that, you can now start adding Tailwind classes to your Nuxt components!&lt;/p&gt;

&lt;h2&gt;
  
  
  Classes
&lt;/h2&gt;

&lt;p&gt;To get started, add some of Tailwind's in-built utilities to an element's &lt;code&gt;class&lt;/code&gt; attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;NuxtLink&lt;/span&gt;
    &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"font-semibold text-gray-50 hover:text-gray-400 duration-100"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Home
  &lt;span class="nt"&gt;&amp;lt;/NuxtLink&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;New to Tailwind? Your best bet is to check out the &lt;a href="https://tailwindcss.com/docs/utility-first" rel="noopener noreferrer"&gt;Tailwind docs&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Create a &lt;code&gt;tailwind.config.js&lt;/code&gt; file at the root of your project to configure the default theme.&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="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;screens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;640px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;md&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;768px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1024px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;xl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1280px&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;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;linkedin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#0A66C2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;lighter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#378fe9&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;darker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#004182&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="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="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tailwindcss/typography&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;h2&gt;
  
  
  Viewer
&lt;/h2&gt;

&lt;p&gt;Nuxt Tailwind exposes a &lt;code&gt;/_tailwind/&lt;/code&gt; route in development where your Tailwind configuration is rendered as a library.&lt;/p&gt;

&lt;p&gt;May your web apps become colourful and flashy 😉&lt;/p&gt;




&lt;p&gt;Hey, guys! Thank you for reading. I hope that you enjoyed this.&lt;/p&gt;

&lt;p&gt;Keep up to date with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://lloyd.cx/" rel="noopener noreferrer"&gt;https://lloyd.cx/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/lloydtao/" rel="noopener noreferrer"&gt;https://twitter.com/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/lloydtao/" rel="noopener noreferrer"&gt;https://github.com/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/lloydtao/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nuxt</category>
      <category>nuxt3</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Adding ESLint and Prettier to Nuxt 3 ✨ (2024)</title>
      <dc:creator>Lewis Lloyd</dc:creator>
      <pubDate>Sun, 01 Jan 2023 23:37:40 +0000</pubDate>
      <link>https://dev.to/tao/adding-eslint-and-prettier-to-nuxt-3-2023-5bg</link>
      <guid>https://dev.to/tao/adding-eslint-and-prettier-to-nuxt-3-2023-5bg</guid>
      <description>&lt;p&gt;🎉 Update (April 2024): This tutorial now uses the &lt;code&gt;@nuxt/eslint&lt;/code&gt; module.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this post, we'll introduce ESLint and Prettier for automatic code style formatting in your Nuxt 3 project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ESLint&lt;/strong&gt; is a linter that helps to enforce code quality through standards and patterns, such as flagging unused variables, disallowing globals, and requiring Error objects as Promise rejection reasons.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prettier&lt;/strong&gt; is a formatter that helps in tidying up documents, such as maximum line length, mixed spaces and tabs, keyword spacing, and comma style.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By using these tools together, we can spend more of our development time on our actual code, instead of nitpicking a file's indenting, casing and bracket placement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Packages
&lt;/h3&gt;

&lt;p&gt;Install 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;&lt;span class="c"&gt;# ESLint&lt;/span&gt;
yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; @nuxt/eslint eslint typescript

&lt;span class="c"&gt;# Prettier&lt;/span&gt;
yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; eslint-plugin-prettier eslint-config-prettier prettier
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;Add the &lt;code&gt;@nuxt/eslint&lt;/code&gt; module to your Nuxt configuration:&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;// nuxt.config.ts&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;devtools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nuxt/eslint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;yarn dev&lt;/code&gt; to generate an initial ESLint configuration file (&lt;code&gt;eslint.config.mjs&lt;/code&gt;), which will look like this:&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;// eslint.config.mjs&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;withNuxt&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;./.nuxt/eslint.config.mjs&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="nf"&gt;withNuxt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If you already have a flat configuration file for ESLint that you would like to use, it can be passed as an argument to &lt;code&gt;withNuxt()&lt;/code&gt;.&lt;br&gt;
You can explore more configuration options here: &lt;a href="https://eslint.nuxt.com/packages/module" rel="noopener noreferrer"&gt;https://eslint.nuxt.com/packages/module&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Scripts
&lt;/h3&gt;

&lt;p&gt;Add the following scripts to your &lt;code&gt;package.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&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;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yarn lint:eslint &amp;amp;&amp;amp; yarn lint:prettier"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint:eslint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eslint ."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint:prettier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prettier . --check"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lintfix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eslint . --fix &amp;amp;&amp;amp; prettier --write --list-different ."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&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;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;To check for errors, use &lt;code&gt;yarn lint&lt;/code&gt;. This won't effect any changes, and may be useful in a code review or CI pipeline.&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="nv"&gt;$ &lt;/span&gt;yarn lint

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; yarn run v1.22.5
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$ &lt;/span&gt;yarn lint:eslint &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn lint:prettier
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$ &lt;/span&gt;eslint &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$ &lt;/span&gt;prettier &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--check&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; Checking formatting...
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;warn] app.vue
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;warn] Code style issues found &lt;span class="k"&gt;in &lt;/span&gt;the above file. Run Prettier to fix.
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; error Command failed with &lt;span class="nb"&gt;exit &lt;/span&gt;code 1.
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; info Visit https://yarnpkg.com/en/docs/cli/run &lt;span class="k"&gt;for &lt;/span&gt;documentation about this command.
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; error Command failed with &lt;span class="nb"&gt;exit &lt;/span&gt;code 1.
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; info Visit https://yarnpkg.com/en/docs/cli/run &lt;span class="k"&gt;for &lt;/span&gt;documentation about this command.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To fix errors, use &lt;code&gt;yarn lintfix&lt;/code&gt;. This will save any formatting changes.&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="nv"&gt;$ &lt;/span&gt;yarn lintfix

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; yarn run v1.22.5
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$ &lt;/span&gt;prettier &lt;span class="nt"&gt;--write&lt;/span&gt; &lt;span class="nt"&gt;--list-different&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; eslint &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--fix&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; app.vue
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; Done &lt;span class="k"&gt;in &lt;/span&gt;2.59s.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After using &lt;code&gt;yarn lintfix&lt;/code&gt;, invoking &lt;code&gt;yarn lint&lt;/code&gt; should be successful.&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="nv"&gt;$ &lt;/span&gt;yarn lint

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; yarn run v1.22.5
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$ &lt;/span&gt;yarn lint:eslint &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn lint:prettier
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$ &lt;/span&gt;eslint &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$ &lt;/span&gt;prettier &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--check&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; Checking formatting...
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; All matched files use Prettier code style!
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; Done &lt;span class="k"&gt;in &lt;/span&gt;3.07s.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All done!&lt;/p&gt;

&lt;p&gt;You can hopefully now avoid the nitpicking arguments 😉&lt;/p&gt;




&lt;p&gt;Hey, guys! Thank you for reading. I hope that you enjoyed this.&lt;/p&gt;

&lt;p&gt;Keep up to date with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://lloyd.cx/" rel="noopener noreferrer"&gt;https://lloyd.cx/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/lloydtao/" rel="noopener noreferrer"&gt;https://twitter.com/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/lloydtao/" rel="noopener noreferrer"&gt;https://github.com/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/lloydtao/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nuxt</category>
      <category>nuxt3</category>
      <category>eslint</category>
      <category>prettier</category>
    </item>
    <item>
      <title>Why do we love server-side rendering again? 🤯</title>
      <dc:creator>Lewis Lloyd</dc:creator>
      <pubDate>Wed, 28 Dec 2022 13:44:26 +0000</pubDate>
      <link>https://dev.to/tao/why-do-we-love-server-side-rendering-again-23mm</link>
      <guid>https://dev.to/tao/why-do-we-love-server-side-rendering-again-23mm</guid>
      <description>&lt;p&gt;Why is everybody talking about server-side rendering again?&lt;/p&gt;

&lt;p&gt;In order to understand the current trends, let’s have a look at the history of rendering on the web.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  History of web rendering
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2000 - 2012
&lt;/h3&gt;

&lt;p&gt;From 2000 to 2012, if you were interacting with a feature-rich web page, it was almost certainly dynamically rendered by a backend web server. The page would then be served to the client as a static HTML file. &lt;/p&gt;

&lt;p&gt;Backend market share was dominated by PHP (1995) and Ruby (1996), with other contenders such as &lt;a href="http://asp.net/" rel="noopener noreferrer"&gt;ASP.NET&lt;/a&gt; (2002) and Spring (2003) joining the scene over the years.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  2012 - 2020
&lt;/h3&gt;

&lt;p&gt;The following decade saw the prominent rise of the &lt;strong&gt;single-page application&lt;/strong&gt; (SPA). &lt;/p&gt;

&lt;p&gt;This method involves rendering HTML in the user's browser, aiming to provide a desktop-like experience. Popular SPA frameworks include AngularJS (2010), React (2013), Vue.js (2014) and Angular 2+ (2016).&lt;/p&gt;

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

&lt;p&gt;Features such as JavaScript-based routing could control and maintain state across pages, though it had the downside of long initial load times and poor SEO. Performance issues were also prevalent due to the heavy nature of SPAs, especially on lighter clients such as mobile phones. &lt;/p&gt;

&lt;p&gt;Even with the trade-offs, the SPA was beloved and adopted by stakeholders and developers alike, and marked a historic switch to &lt;strong&gt;client-side rendering&lt;/strong&gt; (CSR). &lt;/p&gt;

&lt;p&gt;This effectively popularised the term “server-side rendering”, which had never seen mainstream usage as there was no need to differentiate it from CSR.&lt;/p&gt;

&lt;h2&gt;
  
  
  The return of SSR
&lt;/h2&gt;

&lt;p&gt;These developments in web rendering posed a key question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can we utilise the fast initial load times of SSR while keeping the interactivity and dynamicity of SPAs, all while keeping the application lightweight?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Client-side hydration
&lt;/h3&gt;

&lt;p&gt;The current best practise is to serve a &lt;strong&gt;pre-rendered&lt;/strong&gt; page to the client, and then add application state and interactivity through a process called &lt;strong&gt;hydration&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Since the page is initially rendered by the server, it benefits from a quick load time, and takes rendering load off of the client. In the hydration process, a JavaScript bundle will attach event listeners to the DOM and make it fully interactive. This bundle is comparatively small compared to an SPA, which further keeps the app light and performant.&lt;/p&gt;

&lt;p&gt;React and Vue each have an SSR counterpart, known as &lt;strong&gt;Next.js&lt;/strong&gt; (2016) and &lt;strong&gt;Nuxt.js&lt;/strong&gt; (2016) respectively. The popularity of these tools began to rise in 2020.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Static site generation
&lt;/h3&gt;

&lt;p&gt;If we restrict all dynamicity to hydrated components, we can take SSR a step further and pre-render the entire application. This is known as static site generation (SSG), and often used in &lt;a href="https://jamstack.org/" rel="noopener noreferrer"&gt;JAMStack&lt;/a&gt; applications.&lt;/p&gt;

&lt;p&gt;Advanced SSG tools may even collect and transform data as they build the application (e.g. Markdown, CSV, JSON). This makes it useful for content that changes infrequently, such as blogs and documentation, as further API calls do not need to be made by the client.&lt;/p&gt;

&lt;p&gt;All-in-all, this removes the need for a web server. The files can be shipped to any static hosting provider (e.g. Amazon S3, GitHub Pages) and served through a CDN to benefit from even lower latency and load times.&lt;/p&gt;

&lt;h2&gt;
  
  
  The horseshoe
&lt;/h2&gt;

&lt;p&gt;In summary, web rendering has jumped from fully server-side (~1995 to 2010) to fully client-side rendered (~2010 to 2016), and then settled somewhere around mainly server-side rendered with client-side rendering for interactivity (~2016 onwards). &lt;/p&gt;

&lt;p&gt;So, while it has not necessarily &lt;em&gt;fully&lt;/em&gt; horseshoed back to server-side rendering, we’ve definitely taken a tremendous leap in each direction.&lt;/p&gt;

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

&lt;p&gt;Which other technologies do you think could make a comeback? 😉&lt;/p&gt;




&lt;p&gt;Hey, guys! Thank you for reading. I hope that you enjoyed this.&lt;/p&gt;

&lt;p&gt;Keep up to date with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://lloyd.cx/" rel="noopener noreferrer"&gt;https://lloyd.cx/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/lloydtao/" rel="noopener noreferrer"&gt;https://twitter.com/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/lloydtao/" rel="noopener noreferrer"&gt;https://github.com/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/lloydtao/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/lloydtao/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>reactnative</category>
      <category>learning</category>
      <category>discuss</category>
    </item>
    <item>
      <title>1. Two Sum</title>
      <dc:creator>Lewis Lloyd</dc:creator>
      <pubDate>Mon, 24 Oct 2022 13:32:08 +0000</pubDate>
      <link>https://dev.to/tao/1-two-sum-2goi</link>
      <guid>https://dev.to/tao/1-two-sum-2goi</guid>
      <description>&lt;h2&gt;
  
  
  Python
&lt;/h2&gt;

&lt;p&gt;Solution walkthrough: &lt;a href="https://twitter.com/lloydtao/status/1584288569622790145"&gt;https://twitter.com/lloydtao/status/1584288569622790145&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🥇 Hash table - O(n)
&lt;/h3&gt;

&lt;p&gt;Method: Take each number and check if its complement has been seen before. If not, add it to the list of known complements along with its index.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time complexity: O(n)&lt;/li&gt;
&lt;li&gt;Space complexity: O(n)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;twoSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Take each number and check if its complement has been seen before. If not,
        add it to the list of known complements along with its index.

        Args:
            nums (List[int]): Input array of integers
            target (int): Target integer

        Returns:
            List[int]: Indices of the two integers that sum to target
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="c1"&gt;# Initialise hash map to store known integers
&lt;/span&gt;        &lt;span class="n"&gt;complements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="c1"&gt;# Iterate through the list
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="c1"&gt;# Check if the current number's complement has been seen before
&lt;/span&gt;            &lt;span class="n"&gt;complement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;complement&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;complements&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="n"&gt;complements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;complement&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="c1"&gt;# Add the current number to the list of known complements
&lt;/span&gt;            &lt;span class="n"&gt;complements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🥈 Check pairs - O(n²)
&lt;/h3&gt;

&lt;p&gt;Method: Take each pair of numbers and see if they add up to the target.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time complexity: O(n²)&lt;/li&gt;
&lt;li&gt;Space complexity: O(1)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;twoSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Take each pair of numbers and see if they add up to the target.

        Args:
            nums (List[int]): Input array of integers
            target (int): Target integer

        Returns:
            List[int]: Indices of the two integers that sum to target
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="c1"&gt;# Get length of input array
&lt;/span&gt;        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Iterate over all pairs (i,j)
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="c1"&gt;# Check if this pair equals the target
&lt;/span&gt;                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&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="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>leetcode</category>
      <category>algorithms</category>
      <category>python</category>
    </item>
    <item>
      <title>KeepChat - Managed Chat API with Adaptive Hate Speech Filtering</title>
      <dc:creator>Lewis Lloyd</dc:creator>
      <pubDate>Tue, 09 Aug 2022 01:27:00 +0000</pubDate>
      <link>https://dev.to/tao/keepchat-managed-chat-api-with-adaptive-hate-speech-filtering-2o0l</link>
      <guid>https://dev.to/tao/keepchat-managed-chat-api-with-adaptive-hate-speech-filtering-2o0l</guid>
      <description>&lt;h2&gt;
  
  
  Project
&lt;/h2&gt;

&lt;p&gt;KeepChat is an in-game chat service with superpowers, making the chat space friendly for everyone. Our vision is to keep chat safe and inclusive, without requiring constant attention from moderators.&lt;/p&gt;

&lt;p&gt;At a high level, KeepChat consists of a three-tier architecture.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fsnlpvjozcshfgkzuydqy.png" class="article-body-image-wrapper"&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%2Fsnlpvjozcshfgkzuydqy.png" alt="KeepChat architecture" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the core of the system is the &lt;strong&gt;chat API&lt;/strong&gt;, which handles the business logic of the chat rooms. This includes storing messages, processing new messages from users, and processing flags.&lt;/p&gt;

&lt;p&gt;When a new message is processed, the chat API asks the &lt;strong&gt;training and screening API&lt;/strong&gt; whether the message should be filtered. The AI responds with a &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt;, and the backend will filter the message accordingly before storing it.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fqgnteyb28xdlc6gqv46u.png" class="article-body-image-wrapper"&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%2Fqgnteyb28xdlc6gqv46u.png" alt="KeepChat admin panel" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a flag is processed, the chat API tells the AI to add the flagged message to its bank of harmful messages, and then &lt;strong&gt;re-train&lt;/strong&gt; on this data. We envision expanding on this by requiring a certain number of flags or total user sociability score in order to add the message to the training data.&lt;/p&gt;

&lt;p&gt;In order to demonstrate this functionality, a frontend &lt;strong&gt;consumer application&lt;/strong&gt; communicates with the backend by using its chat endpoints.&lt;/p&gt;

&lt;p&gt;This demonstrates the plug-and-play nature of the application; integrating KeepChat into an existing application is incredibly simple, as screening messages and re-training on flagged messages is built-in to the service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teamwork
&lt;/h2&gt;

&lt;p&gt;By splitting the project into the architecture mentioned prior, we were able to divide our team effectively. This involved giving individual team members ownership over some part of the system, and then exposing each part through a REST API, which kept the system loosely coupled.&lt;/p&gt;

&lt;p&gt;The end result was a high development velocity within the team.&lt;/p&gt;

&lt;p&gt;We leveraged Git and GitHub in order to distribute code between team members. It's important to prevent code-breaking changes from being pushed in a time-critical project, as these can block an entire team while the bug is fixed.&lt;/p&gt;

&lt;p&gt;Therefore, any code changes went through a pull request, and we leveraged GitHub Actions in order to run quick code quality checks before accepting a PR.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2F31zhb27qs7w73sy5ul55.png" class="article-body-image-wrapper"&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%2F31zhb27qs7w73sy5ul55.png" alt="KeepChat pull requests" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;We didn't bring home the bacon this time. Interestingly, the winner of our challenge also built a chat service with adaptive filtering, including the ability to re-train on reported messages.&lt;/p&gt;

&lt;p&gt;However, they managed to deploy their system to Google Cloud Platform, and provided a link to use their application. Considering the product-focused nature of the hackathon, we should have aimed to put our application online.&lt;/p&gt;

&lt;p&gt;Results aside, I would definitely call this weekend a success. We managed to effectively execute on an identical product scope to the challenge winners, which validates our project on both the technical and product level.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Flhsh40jrvog60wxtg5w4.png" class="article-body-image-wrapper"&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%2Flhsh40jrvog60wxtg5w4.png" alt="KeepChat team photo" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go KeepChat!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Increasing Pull Request Velocity with Acceptance Criteria</title>
      <dc:creator>Lewis Lloyd</dc:creator>
      <pubDate>Thu, 07 Oct 2021 14:59:12 +0000</pubDate>
      <link>https://dev.to/tao/increasing-pull-request-velocity-with-acceptance-criteria-33db</link>
      <guid>https://dev.to/tao/increasing-pull-request-velocity-with-acceptance-criteria-33db</guid>
      <description>&lt;h2&gt;
  
  
  Pull requests
&lt;/h2&gt;

&lt;p&gt;In software engineering, a &lt;strong&gt;pull request&lt;/strong&gt; is the process in which a contributor asks a repository owner to merge their changes into the main codebase. &lt;/p&gt;

&lt;p&gt;The PR is important, as it acts as a crucial safety buffer when developing software. It gives a chance for both manual validation (e.g. code reviews) and automatic checks (e.g. unit tests) to take place, as well as discussions between the repository's maintainers.&lt;/p&gt;

&lt;p&gt;Once the code has been approved, it can be assumed safe to merge in, and will eventually become part of the next release. &lt;/p&gt;

&lt;p&gt;This safeguard should result in the main branch of code remaining in a production-ready state, all of the time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reviewing a PR
&lt;/h2&gt;

&lt;p&gt;When looking at a pull request, the reviewer is addressing two concerns:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is the code of a high quality?&lt;/li&gt;
&lt;li&gt;Does this implementation satisfy the feature's requirements? &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first criterium is, for the most part, a matter of opinion. We can attempt to standardise code quality through the use of linters and code coverage tools, but the final say falls to the reviewer.&lt;/p&gt;

&lt;p&gt;The second is much more significant. A failure to meet requirements may result in a bad product, which affects the user experience. In the interest of business objectives, this is something that we absolutely need to minimise.&lt;/p&gt;

&lt;p&gt;For distributed software teams, this poses a unique challenge.&lt;/p&gt;

&lt;h2&gt;
  
  
  A lack of context
&lt;/h2&gt;

&lt;p&gt;Typically, the reviewer of a pull request will not have had any involvement in the specification, design or implementation of the feature.&lt;/p&gt;

&lt;p&gt;As a matter of fact, software teams may find it beneficial for the reviewer to be completely out-of-the-loop. Their opinion is more likely to be unbiased if they haven't contributed to the delivery of the work item.&lt;/p&gt;

&lt;p&gt;This creates a problem. The reviewer needs to know what they're looking for, but they don't have much information. If they approve of an unsatisfactory implementation, is it really fair to blame them? The responsibility should clearly be elsewhere.&lt;/p&gt;

&lt;p&gt;Context of &lt;strong&gt;what the implementation is&lt;/strong&gt; needs to be communicated, so that a reviewer can conduct an unbiased review yet remain an effective gatekeeper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Acceptance criteria
&lt;/h2&gt;

&lt;p&gt;In our team, we have found success in writing manual acceptance criteria. &lt;/p&gt;

&lt;p&gt;This is a formalised checklist, verified by a human, which is marked alongside a code review.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2F0fi19cy8qzybxo4gryxl.png" class="article-body-image-wrapper"&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%2F0fi19cy8qzybxo4gryxl.png" alt="Acceptance criteria table within a pull request" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The checklist contains unambiguous steps to follow. This includes any required test data, as well as the expected result of the test. &lt;/p&gt;

&lt;p&gt;Why has this been effective?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can test the feature with much more &lt;strong&gt;clarity&lt;/strong&gt; on which behaviours we're testing. This results in faster reviews.&lt;/li&gt;
&lt;li&gt;We have &lt;strong&gt;certainty&lt;/strong&gt; that satisfying the acceptance criteria will satisfy the work item's requirements. Unsatisfactory code is less likely to be released.&lt;/li&gt;
&lt;li&gt;The responsibility of identifying (but not testing) behaviours falls on the contributor, who has the most &lt;strong&gt;context&lt;/strong&gt; on what is being implemented. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Screenshots
&lt;/h2&gt;

&lt;p&gt;For the sake of visibility, I like to supplement the review with screenshots at each test. &lt;/p&gt;

&lt;p&gt;After all, the success of the review ties into the success of the implementation. So, the contributor may appreciate seeing their hard work validated!&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fvbvr9m5uk02ep1g72x1j.png" class="article-body-image-wrapper"&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%2Fvbvr9m5uk02ep1g72x1j.png" alt="Screenshots of application to prove validated acceptance criteria" width="800" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Weaknesses
&lt;/h2&gt;

&lt;p&gt;It's a good time to note that acceptance criteria aren't a fool-proof solution to code validation.&lt;/p&gt;

&lt;p&gt;There is a requirement for the contributor to write a sensible checklist. This means covering the full scope of the feature, including edge cases, without having such a volume of tests that checking them becomes a laborious process.&lt;/p&gt;

&lt;p&gt;Therefore, you should still endeavour to validate all behaviours of your code through unit and integration tests. The acceptance criteria can be thought of as the formalisation of a separate, equally-important process, and not as a replacement. &lt;/p&gt;

&lt;p&gt;Work smarter, not harder. 😉&lt;/p&gt;




&lt;p&gt;Hey, guys! Thank you for reading. I hope that you enjoyed this.&lt;/p&gt;

&lt;p&gt;Keep up to date with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/tao/"&gt;https://dev.to/tao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/LloydTao"&gt;https://twitter.com/LloydTao&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/LloydTao"&gt;https://github.com/LloydTao&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/LloydTao/"&gt;https://www.linkedin.com/in/LloydTao/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Catch you around!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>testing</category>
      <category>github</category>
    </item>
    <item>
      <title>Design Validation</title>
      <dc:creator>Lewis Lloyd</dc:creator>
      <pubDate>Mon, 03 May 2021 01:26:02 +0000</pubDate>
      <link>https://dev.to/tao/design-validation-1313</link>
      <guid>https://dev.to/tao/design-validation-1313</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Software teams have a broad range of skill levels.&lt;/p&gt;

&lt;p&gt;This can be due to familiarity with the tools, a push for mentorship from engineering managers, or just general software engineering .&lt;/p&gt;

&lt;p&gt;In short, we shouldn't expect, nor assume, a level playing field across the team.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2F4yxz8pmu3agrd3nws6vb.png" class="article-body-image-wrapper"&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%2F4yxz8pmu3agrd3nws6vb.png" alt="A team constructing a web page design together" width="800" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the journey to give team members independence, you may find running out-of-scope in implementation. &lt;/p&gt;

&lt;p&gt;This can lead to a range of issues, including undesired functionality and conflict with other work items. Product owners put a lot of effort into keeping the backlog well-defined, and we need to stick to what's required!  &lt;/p&gt;

&lt;p&gt;Further, these issues will almost always be identified &lt;strong&gt;after&lt;/strong&gt; implementation, when time and development costs have already been spent.&lt;/p&gt;

&lt;p&gt;We need a way to keep our team members on the right path, while still promoting autonomy through asynchronous development practises.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enriching the Agile Lifecycle
&lt;/h3&gt;

&lt;p&gt;I've found that a good solution is the inclusion of just a single, extra step in the agile process.&lt;/p&gt;

&lt;p&gt;You're probably familiar with the &lt;strong&gt;design document&lt;/strong&gt;. Before implementation starts, the developer whips up an outline of how they intend for the work item to be to completed.&lt;/p&gt;

&lt;p&gt;This is nicely expanded upon by &lt;a href="https://reqexperts.com/resources/requirements-articles/articles-what-is-the-difference/"&gt;reqexperts.com&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Design Specification should state how the design will meet the requirements. Design is not a one-to-one response to requirements. Design requires discipline knowledge and integration of disciplines in most cases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At this stage, a senior team member can approve of the documented strategy, &lt;em&gt;before&lt;/em&gt; a week or two is spent on the implementation. &lt;/p&gt;

&lt;p&gt;More often than not, a quick read will result in an all-clear. However, if there's an issue, then specific changes can be requested.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fu91rtb1x2bls6nkszdr0.png" class="article-body-image-wrapper"&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%2Fu91rtb1x2bls6nkszdr0.png" alt="Senior developer looking through tasks" width="800" height="750"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, your organisation may implement agile in a different way. &lt;/p&gt;

&lt;p&gt;What's valuable is the core idea of documenting and validating a feature's design &lt;strong&gt;before&lt;/strong&gt; its implementation.&lt;/p&gt;

&lt;p&gt;I've provided the &lt;a href="https://docs.google.com/document/d/1Lxd5JkrKguPrbO6hXFENf5UPMe7jaPXScKa3AQYVsNc/"&gt;template&lt;/a&gt; that I use, and an &lt;a href="https://docs.google.com/document/d/1UDV1kNEByRWje3oj7fgkYYkWUo5MYbKLewU245aLEGg/"&gt;example&lt;/a&gt; of a completed document.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Junior Agile Lifecycle
&lt;/h3&gt;

&lt;p&gt;We've now identified this extra step. &lt;/p&gt;

&lt;p&gt;Using this, we can outline our &lt;strong&gt;junior-friendly agile lifecycle&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Concept:&lt;/strong&gt; Stakeholder discusses feature request with Product Owner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Requirements:&lt;/strong&gt; Product Owner documents feature requirements, and adds work item to backlog.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design:&lt;/strong&gt; Developer picks up work item, and documents their implementation strategy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design validation:&lt;/strong&gt; Design document is reviewed and approved by Senior Developer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation:&lt;/strong&gt; Developer implements work item based on documented design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluation:&lt;/strong&gt; Feature branch is reviewed, tested and merged.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hopefully, this results in a great, cohesive team!&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fu8829wceqig2o6j0fxzo.png" class="article-body-image-wrapper"&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%2Fu8829wceqig2o6j0fxzo.png" alt="A team playing with tools together" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Hey, guys! Thank you for reading. I hope that you enjoyed this.&lt;/p&gt;

&lt;p&gt;Keep up to date with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/tao/"&gt;https://dev.to/tao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/LloydTao"&gt;https://twitter.com/LloydTao&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/LloydTao"&gt;https://github.com/LloydTao&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/LloydTao/"&gt;https://www.linkedin.com/in/LloydTao/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>agile</category>
      <category>leadership</category>
      <category>devops</category>
    </item>
    <item>
      <title>Host React/Vue with Continuous Deployment, for Free!</title>
      <dc:creator>Lewis Lloyd</dc:creator>
      <pubDate>Wed, 12 Aug 2020 21:36:13 +0000</pubDate>
      <link>https://dev.to/tao/host-react-vue-with-continuous-deployment-for-free-2jl8</link>
      <guid>https://dev.to/tao/host-react-vue-with-continuous-deployment-for-free-2jl8</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Have you ever built web applications that you’d love to show off online, but don’t want to spend hours configuring and deploying it? &lt;/p&gt;

&lt;p&gt;Do you have a blog, splash page or series of portfolio showcase projects, but don’t want to pay money to host them for display?&lt;/p&gt;

&lt;p&gt;This guide will show you fully-featured web projects, for free!&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fi%2Fau93h70az8wqr2c3t1u7.png" class="article-body-image-wrapper"&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%2Fi%2Fau93h70az8wqr2c3t1u7.png" alt="Example React/Vue Project for Portfolio" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s the solution.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’ve created a collection of template repositories on GitHub that makes hosting and continuously deploying React and Vue projects &lt;em&gt;free&lt;/em&gt;, &lt;em&gt;automatic&lt;/em&gt; and &lt;em&gt;incredibly simple&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Additionally, it’s super easy to plug in a custom domain, and I've included installation instructions including all of the required A and CNAME host records for your domain provider.&lt;/p&gt;

&lt;p&gt;You can view the repositories here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vue: &lt;a href="https://github.com/LloydTao/vue-template.github.io"&gt;https://github.com/LloydTao/vue-template.github.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nuxt: &lt;a href="https://github.com/LloydTao/nuxt-template.github.io"&gt;https://github.com/LloydTao/nuxt-template.github.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;React: &lt;a href="https://github.com/LloydTao/react-template.github.io"&gt;https://github.com/LloydTao/react-template.github.io&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these is hosted separately, for free:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vue: &lt;a href="https://vue.lloyd.cx/"&gt;https://vue.lloyd.cx/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nuxt: &lt;a href="https://nuxt.lloyd.cx/"&gt;https://nuxt.lloyd.cx/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;React: &lt;a href="https://react.lloyd.cx/"&gt;https://react.lloyd.cx/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How it Works
&lt;/h3&gt;

&lt;p&gt;We’ll be taking advantage of GitHub Pages in order to host our sites.&lt;/p&gt;

&lt;p&gt;Pages is a feature of GitHub that can serve static web files for a repository, typically for docs or a wiki. &lt;em&gt;We’ll&lt;/em&gt; be using it to serve a compiled React/Vue project. &lt;/p&gt;

&lt;p&gt;Read more: &lt;a href="https://docs.github.com/en/github/working-with-github-pages"&gt;https://docs.github.com/en/github/working-with-github-pages&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I should note here that this won’t host an app that relies on Node. You’ll need a proper web server for that.&lt;/p&gt;

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

&lt;p&gt;It can be set up in minutes, and has a few nice features out-of-the-box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The repository contains a GitHub Actions workflow to automatically build and deploy any pushed changes. No messing around with external pipelines (i.e. Travis CI), and a private repo can still get ~2000 deployments per month. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="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%2Fi%2Fgrgc0b8a1aynlhwrlxcy.png" class="article-body-image-wrapper"&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%2Fi%2Fgrgc0b8a1aynlhwrlxcy.png" alt="GitHub Actions for Deployment to GitHub Pages" width="587" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The repository contains a CNAME file, along with easy instructions for pointing your domain to the site using your provider’s DNS host records.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="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%2Fi%2Fx4x75n365cecaan2cgic.png" class="article-body-image-wrapper"&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%2Fi%2Fx4x75n365cecaan2cgic.png" alt="Namecheap DNS CNAME and A Host Records" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The README also contains instructions for launching &lt;em&gt;unlimited&lt;/em&gt; static sites, each to its own subdomain. You can now publish a blog, or separate out your portfolio’s projects into repos under the same domain, all for free. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="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%2Fi%2Fqrqekkjetz3x9rbfle7n.png" class="article-body-image-wrapper"&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%2Fi%2Fqrqekkjetz3x9rbfle7n.png" alt="CNAME Subdomain for Separate GitHub Pages Repo" width="669" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All instructions are in the repository’s README, but let’s get started below!&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;Get started in minutes with these instructions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a repository from this template (include all branches).&lt;/li&gt;
&lt;li&gt;Rename your repository to &lt;code&gt;&amp;lt;username&amp;gt;.github.io&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Make sure that GitHub Pages uses the build branch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The branch can be selected at &lt;code&gt;Settings -&amp;gt; Options -&amp;gt; GitHub Pages -&amp;gt; Source&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;This is real simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The master branch contains a React/Vue project.&lt;/li&gt;
&lt;li&gt;The build branch will contain the compiled React/Vue application.&lt;/li&gt;
&lt;li&gt;When you push to master, a GitHub Action compiles the updated project into build.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="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%2Fi%2F2leb512bdca5378jq8to.png" class="article-body-image-wrapper"&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%2Fi%2F2leb512bdca5378jq8to.png" alt="Example Build and Deploy after Push to Master" width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Development
&lt;/h3&gt;

&lt;p&gt;Any commits pushed or merged into master will trigger the build action.&lt;/p&gt;

&lt;p&gt;These changes will be reflected on your GitHub Pages site after around 60 seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain Names
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Apex Domain&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, set your domain name within the GitHub repository.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the CNAME file, replace example.com with your domain.&lt;/li&gt;
&lt;li&gt;This can also be done in &lt;code&gt;Settings -&amp;gt; Options -&amp;gt; GitHub Pages -&amp;gt; Source&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="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%2Fi%2Fqrqekkjetz3x9rbfle7n.png" class="article-body-image-wrapper"&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%2Fi%2Fqrqekkjetz3x9rbfle7n.png" alt="CNAME Subdomain for Separate GitHub Pages Repo" width="669" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Second, configure your DNS host records with your domain provider.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an A record for host "@" pointing to 185.199.108.153.&lt;/li&gt;
&lt;li&gt;Create an A record for host "@" pointing to 185.199.109.153.&lt;/li&gt;
&lt;li&gt;Create an A record for host "@" pointing to 185.199.110.153.&lt;/li&gt;
&lt;li&gt;Create an A record for host "@" pointing to 185.199.111.153.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Subdomains&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can configure a subdomain, such as &lt;code&gt;www.[example.com]&lt;/code&gt;, in your DNS host records.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a CNAME record for host "www" pointing to &lt;code&gt;&amp;lt;username&amp;gt;.github.io&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Infinite Hosting
&lt;/h3&gt;

&lt;p&gt;The awesome power of this is that you can have a repository for each and every subdomain.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a repository from this template with any name (include all branches).&lt;/li&gt;
&lt;li&gt;Enable GitHub Pages for it (&lt;code&gt;Settings -&amp;gt; Options -&amp;gt; GitHub Pages -&amp;gt; Source&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;In the CNAME file, replace &lt;code&gt;example.com&lt;/code&gt; with your apex and subdomain (i.e. &lt;code&gt;blog.[example.com]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;With your domain provider, create a CNAME record for host "[blog]" pointing to &lt;code&gt;&amp;lt;username&amp;gt;.github.io&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is how I achieved each of these, for free:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vue: &lt;a href="https://vue.lloyd.cx/"&gt;https://vue.lloyd.cx/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nuxt: &lt;a href="https://nuxt.lloyd.cx/"&gt;https://nuxt.lloyd.cx/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;React: &lt;a href="https://react.lloyd.cx/"&gt;https://react.lloyd.cx/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What's not to love? 😉&lt;/p&gt;




&lt;p&gt;Hey, guys! Thank you for reading. I hope that you enjoyed this.&lt;/p&gt;

&lt;p&gt;Keep up to date with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/tao/"&gt;https://dev.to/tao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/LloydTao"&gt;https://twitter.com/LloydTao&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/LloydTao"&gt;https://github.com/LloydTao&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/LloydTao/"&gt;https://www.linkedin.com/in/LloydTao/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Catch you around!&lt;/p&gt;

</description>
      <category>react</category>
      <category>vue</category>
      <category>github</category>
    </item>
    <item>
      <title>The Case for Comma-Leading Lists</title>
      <dc:creator>Lewis Lloyd</dc:creator>
      <pubDate>Sat, 13 Jun 2020 17:57:36 +0000</pubDate>
      <link>https://dev.to/tao/the-case-for-comma-leading-lists-3n49</link>
      <guid>https://dev.to/tao/the-case-for-comma-leading-lists-3n49</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Comma-leading lists are an objectively better presentation style.&lt;/p&gt;

&lt;p&gt;They make &lt;strong&gt;logical sense&lt;/strong&gt;; the next value on the list is dependant on the comma, and so, they should be kept together.&lt;/p&gt;

&lt;p&gt;The style may look alien at first, but give it a test drive and you'll be surprised at how quickly it starts to look normal.&lt;/p&gt;

&lt;p&gt;For now, let's have a look at the benefits.&lt;/p&gt;




&lt;h2&gt;
  
  
  Justification
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. No Merge Conflicts
&lt;/h3&gt;

&lt;p&gt;When adding a new value to a list with trailing commas, you're making 2 additions and 1 deletion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1TArMyxv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/LloydTao/dev.to-posts/master/general/comma-leading-lists/trailing-diff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1TArMyxv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/LloydTao/dev.to-posts/master/general/comma-leading-lists/trailing-diff.png" alt="Comma-Trailing List Diff" width="397" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will give you a &lt;strong&gt;merge conflict&lt;/strong&gt; just because someone else adds a value on a different branch.&lt;/p&gt;

&lt;p&gt;By using the comma-leading style, you make 1 addition and 0 deletions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ecnChVJC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/LloydTao/dev.to-posts/master/general/comma-leading-lists/leading-diff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ecnChVJC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/LloydTao/dev.to-posts/master/general/comma-leading-lists/leading-diff.png" alt="Comma-Leading List Diff" width="381" height="119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These commits play ball with each other, without needing any conflict resolution.&lt;/p&gt;

&lt;p&gt;"&lt;em&gt;Ah, but I've used a dangling comma&lt;/em&gt;," you say? Allow me to continue.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Dangling Commas Bad
&lt;/h3&gt;

&lt;p&gt;It's true that using a trailing comma after the final value will prevent conflicts, but it's dumb for two reasons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Language Inconsistency&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQL&lt;/strong&gt; doesn't support them. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lgm6MuRH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/LloydTao/dev.to-posts/master/general/comma-leading-lists/leading-sql.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lgm6MuRH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/LloydTao/dev.to-posts/master/general/comma-leading-lists/leading-sql.png" alt="Comma-Leading JSON" width="409" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;JSON standard&lt;/strong&gt; and &lt;strong&gt;Pre-ES5 JavaScript&lt;/strong&gt; don't support them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--66XhmO40--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/LloydTao/dev.to-posts/master/general/comma-leading-lists/leading-json.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--66XhmO40--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/LloydTao/dev.to-posts/master/general/comma-leading-lists/leading-json.png" alt="Comma-Leading JSON" width="210" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's better to stick to a style that works across more languages, especially for a multi-lingual codebase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Redundant Logic&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There's not a second element. It's unnecessary context, so why justify it?&lt;/p&gt;

&lt;p&gt;And, if an interpreter &lt;em&gt;ever&lt;/em&gt; decides to stick a &lt;code&gt;None&lt;/code&gt; in there, good luck.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Better Presentation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Separating Context&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the comma-leading style, the logic stays on the left, and the data stays on the right.&lt;/p&gt;

&lt;p&gt;This makes it quicker and easier to scan when looking through code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Rm3ehlCE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/LloydTao/dev.to-posts/master/general/comma-leading-lists/presentation.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rm3ehlCE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/LloydTao/dev.to-posts/master/general/comma-leading-lists/presentation.png" alt="Better Presentation" width="199" height="94"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will also allow you to quickly identify logic errors, such as missing commas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yLWYr5Xq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/LloydTao/dev.to-posts/master/general/comma-leading-lists/leaked-globals.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yLWYr5Xq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/LloydTao/dev.to-posts/master/general/comma-leading-lists/leaked-globals.png" alt="Leaking Globals" width="444" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Saving Whitespace&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you indent after the opening bracket, you're adding extra columns of whitespace on the left-hand side.&lt;/p&gt;

&lt;p&gt;Placing the commas on the left keeps the code neat and narrow. Neat!&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Comma-leading lists are easier for source control, more compatible across languages, and much faster to read since they keep data separate from the list's logic.&lt;/p&gt;

&lt;p&gt;Do the world a favour and switch to a better standard of data structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;animals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;"ant"&lt;/span&gt;
          &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"bat"&lt;/span&gt;
          &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"cat"&lt;/span&gt;
          &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"dog"&lt;/span&gt;
          &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's not to love? 😉&lt;/p&gt;




&lt;p&gt;Hey, guys! Thank you for reading. I hope that you enjoyed this.&lt;/p&gt;

&lt;p&gt;Keep up to date with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/tao/"&gt;https://dev.to/tao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/LloydTao"&gt;https://twitter.com/LloydTao&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/LloydTao"&gt;https://github.com/LloydTao&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/LloydTao/"&gt;https://www.linkedin.com/in/LloydTao/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Catch you around!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Your Intro to Stripe: Online Payments Processing</title>
      <dc:creator>Lewis Lloyd</dc:creator>
      <pubDate>Fri, 05 Jun 2020 18:00:07 +0000</pubDate>
      <link>https://dev.to/tao/your-intro-to-stripe-online-payments-processing-4amb</link>
      <guid>https://dev.to/tao/your-intro-to-stripe-online-payments-processing-4amb</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Stripe is an online payments processor.&lt;/p&gt;

&lt;p&gt;It's incredible useful for almost any internet commerce; from online stores to subscriptions, and from user-driven marketplaces to crowdfunding.&lt;/p&gt;

&lt;p&gt;This guide will briefly overview Stripe and its API, and give examples on how to integrate it with Django.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you're using a different framework, it should be easily adaptable!&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;p&gt;Stripe is &lt;strong&gt;elegant&lt;/strong&gt;. It abstracts most of the payments process. You don't need to worry about passing card details around and processing it yourself.&lt;/p&gt;

&lt;p&gt;Stripe is &lt;strong&gt;robust&lt;/strong&gt;. It can send dummy payments with test cards before completing a purchase flow.&lt;/p&gt;

&lt;p&gt;Stripe is &lt;strong&gt;secure&lt;/strong&gt;. AES-256 encryption is built in, with decryption keys stored separately.&lt;/p&gt;

&lt;p&gt;Stripe is &lt;strong&gt;compliant&lt;/strong&gt;. This includes PCI, PSD2, SCA and SSAE18/SOC certifications.&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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F000-Stripe-Compliant.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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F000-Stripe-Compliant.png" alt="Stripe Compliance Certifications"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Fees
&lt;/h3&gt;

&lt;p&gt;Stripe &lt;strong&gt;Payments&lt;/strong&gt; charge 1.4% + 20p for European cards and 2.9% + 20p for non-European cards.&lt;/p&gt;

&lt;p&gt;Stripe &lt;strong&gt;Billing&lt;/strong&gt;, used for recurring payments, charges 0.5%.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extensions
&lt;/h3&gt;

&lt;p&gt;Stripe has a host of additional features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Stripe &lt;strong&gt;Connect&lt;/strong&gt; - dedicated dashboard for sellers on your marketplace, with a monthly fee per account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stripe &lt;strong&gt;Radar&lt;/strong&gt; -  machine learning fraud protection.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stripe &lt;strong&gt;Sigma&lt;/strong&gt; - SQL-powered business reports, with dozens of templates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stripe &lt;strong&gt;Atlas&lt;/strong&gt; - launch a start-up (LLC, bank account, stock issuing) for a one-time fee.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll be taking advantage of &lt;a href="https://stripe.com/docs/payments/checkout" rel="noopener noreferrer"&gt;Stripe Checkout&lt;/a&gt; for quick and compliant integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;Our tasks at hand are essentially:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a Stripe account, and grab your API keys.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install the Stripe API for the backend (Python: &lt;code&gt;$ pip install stripe&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add Stripe to the frontend (we're using &lt;code&gt;checkout.js&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We're done! View processed payments on your Stripe account.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Creating a Stripe Account
&lt;/h3&gt;

&lt;p&gt;Head to &lt;a href="https://dashboard.stripe.com/register" rel="noopener noreferrer"&gt;https://dashboard.stripe.com/register&lt;/a&gt; to create an account.&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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F001-Stripe-Account.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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F001-Stripe-Account.png" alt="Registering a Stripe Account"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember to verify your account.&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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F002-Stripe-Verify.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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F002-Stripe-Verify.png" alt="Verifying a Stripe Account"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, grab your API keys. You'll need both.&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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F003-Stripe-Key.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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F003-Stripe-Key.png" alt="Getting a Stripe API Key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing the Stripe API
&lt;/h3&gt;

&lt;p&gt;Let's set up the backend. This is where the private API key will live.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make sure you've set up your project, virtual environment and requirements. &lt;a href="https://dev.to/tao/your-intro-to-django-2020-3a01"&gt;Here's a Django guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Add Stripe to your &lt;code&gt;requirements.txt&lt;/code&gt; for pip. You'll probably want the latest version.&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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F004-Django-Requirements.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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F004-Django-Requirements.png" alt="Adding Stripe to Requirements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install your packages with &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stripe Setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the settings, make sure you've added Stripe to your &lt;code&gt;INSTALLED_APPS&lt;/code&gt; and defined the keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stripe&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;STRIPE_PUBLISHABLE_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pk_test_notmykeynotmykeynotmykeynotmykeynotmykeynotmykeynotmykey&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="n"&gt;STRIPE_SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sk_test_notmykeynotmykeynotmykeynotmykeynotmykeynotmykeynotmykey&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you've set up your project, import &lt;code&gt;stripe&lt;/code&gt; and define &lt;code&gt;stripe.api_key&lt;/code&gt; in your views.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.shortcuts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;

&lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STRIPE_SECRET_KEY&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now get started with some views and templates!&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Stripe to the Frontend
&lt;/h3&gt;

&lt;p&gt;Using Stripe Checkout, we can create a payment form (and handle it) incredibly quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Product Page&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We'll make a very simple view, with our API key added to the context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TemplateView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;template_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_context_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get_context_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STRIPE_PUBLISHABLE_KEY&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our template will be include a form, as well as a script based on &lt;code&gt;checkout.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Purchase hat:&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"{% url 'payments-charge' %}"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  {% csrf_token %}
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://checkout.stripe.com/checkout.js"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stripe-button"&lt;/span&gt;
          &lt;span class="na"&gt;data-key=&lt;/span&gt;&lt;span class="s"&gt;"{{ key }}"&lt;/span&gt;
          &lt;span class="na"&gt;data-description=&lt;/span&gt;&lt;span class="s"&gt;"You are purchasing: Hat."&lt;/span&gt;
          &lt;span class="na"&gt;data-amount=&lt;/span&gt;&lt;span class="s"&gt;"100"&lt;/span&gt;
          &lt;span class="na"&gt;data-currency=&lt;/span&gt;&lt;span class="s"&gt;"GBP"&lt;/span&gt;
          &lt;span class="na"&gt;data-locale=&lt;/span&gt;&lt;span class="s"&gt;"auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stripe will validate the payment form. The result looks like:&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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F002-Stripe-Form.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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F002-Stripe-Form.png" alt="Example Stripe Form"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Payment View&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You'll need a view that uses &lt;code&gt;stripe.Charge.create()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You'll notice that the values are hard-coded. You need to enforce them server-side, otherwise the client can just edit the values in the Stripe form.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChargeView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TemplateView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;charge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Charge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;currency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;gbp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hat purchase.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stripeToken&lt;/span&gt;&lt;span class="sh"&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="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;charge.html&lt;/span&gt;&lt;span class="sh"&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 for the template, it doesn't need anything. All functionality is handled in the &lt;code&gt;post&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Thank you for your payment!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll likely want to pass some context data in order to personalise it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can try out our form with a &lt;a href="https://stripe.com/docs/testing#cards" rel="noopener noreferrer"&gt;test card&lt;/a&gt;.&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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F005-Stripe-Payment.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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F005-Stripe-Payment.png" alt="Stripe Payment Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can now see the payment on the dashboard.&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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F006-Stripe-Dashboard.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%2Fraw.githubusercontent.com%2FLloydTao%2Fdev.to-posts%2Fmaster%2Fyour-intro-to%2Fstripe%2F006-Stripe-Dashboard.png" alt="Stripe Dashboard Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Super easy, right? You can now begin to explore the big, wide world of internet commerce!&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What We Covered
&lt;/h3&gt;

&lt;p&gt;In this post, we had a look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Creating a Stripe account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Getting our API keys.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adding Stripe to our Django backend.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creating views and templates for our frontend.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handling the post request using &lt;code&gt;stripe.Charge.create()&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Viewing payments on the dashboard.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What We Missed
&lt;/h3&gt;

&lt;p&gt;There's a whole bunch of stuff to do after payment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;How do I get the money? &lt;a href="https://stripe.com/docs/payouts" rel="noopener noreferrer"&gt;Receive payouts&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do I react to a payment? &lt;a href="https://stripe.com/docs/payments/handling-payment-events" rel="noopener noreferrer"&gt;Handle webhook events&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do I send receipts? &lt;a href="https://stripe.com/docs/receipts" rel="noopener noreferrer"&gt;Send email receipts&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A payment was declined. &lt;a href="https://stripe.com/docs/declines" rel="noopener noreferrer"&gt;Deal with declines&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My customer wants a refund. &lt;a href="https://stripe.com/docs/refunds" rel="noopener noreferrer"&gt;Issue refunds&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What about fraudulent payments? &lt;a href="https://stripe.com/docs/disputes" rel="noopener noreferrer"&gt;Manage disputes and fraud&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As well as the pages above, there's also API docs, such as the &lt;a href="https://stripe.com/docs/api/refunds" rel="noopener noreferrer"&gt;API: Refunds&lt;/a&gt; page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;p&gt;Payments are tricky business, and you don't want to head in the wrong way.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Check out the &lt;a href="https://pypi.org/project/dj-stripe/" rel="noopener noreferrer"&gt;dj-stripe&lt;/a&gt; package, and its &lt;a href="https://dj-stripe.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;Django + Stripe Made Easy&lt;/a&gt; docs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Also, consider some &lt;a href="https://www.reddit.com/r/django/comments/gt21py/stripe_with_django_are_you_using_just_stripe_or/" rel="noopener noreferrer"&gt;Reddit opinions&lt;/a&gt; on using &lt;code&gt;dj-stripe&lt;/code&gt; over the Stripe API&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check out &lt;a href="https://www.saaspegasus.com/guides/django-stripe-integrate/#upcoming-working-with-subscriptions-in-your-django-application" rel="noopener noreferrer"&gt;Create a Subscription SaaS Application with Django and Stripe&lt;/a&gt; by &lt;em&gt;SaaS Pegasus&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check out &lt;a href="https://mycodestories.com/blog/stripe_django_payments/" rel="noopener noreferrer"&gt;another brilliant post&lt;/a&gt; on using Django with Stripe.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Django subreddit (&lt;a href="https://www.reddit.com/r/django/" rel="noopener noreferrer"&gt;r/django&lt;/a&gt;) is an awesome, active and high-quality community.&lt;/p&gt;




&lt;p&gt;Hey, guys! Thank you for reading. I hope that you enjoyed this.&lt;/p&gt;

&lt;p&gt;Keep up to date with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/tao/"&gt;https://dev.to/tao/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/LloydTao" rel="noopener noreferrer"&gt;https://twitter.com/LloydTao&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/LloydTao" rel="noopener noreferrer"&gt;https://github.com/LloydTao&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/LloydTao/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/LloydTao/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Catch you around!&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
    </item>
  </channel>
</rss>
