<?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: Alireza Jahandideh</title>
    <description>The latest articles on DEV Community by Alireza Jahandideh (@youhan).</description>
    <link>https://dev.to/youhan</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%2F134061%2F0da5a889-781c-4063-903f-8e656ce18146.jpg</url>
      <title>DEV Community: Alireza Jahandideh</title>
      <link>https://dev.to/youhan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/youhan"/>
    <language>en</language>
    <item>
      <title>Create a custom toggle input for Vue FormKit using Headless UI</title>
      <dc:creator>Alireza Jahandideh</dc:creator>
      <pubDate>Thu, 13 Jul 2023 19:34:00 +0000</pubDate>
      <link>https://dev.to/youhan/create-a-custom-toggle-input-for-vue-formkit-using-headless-ui-2po7</link>
      <guid>https://dev.to/youhan/create-a-custom-toggle-input-for-vue-formkit-using-headless-ui-2po7</guid>
      <description>&lt;p&gt;Formkit is an awesome library when it comes to going beyond simple login forms. If you are not familiar with it yet, go to their website and see what you can do with it. In this post I am going to share how I build a custom toggle input for FormKit. This is just an experiment that I did with FormKit and this is in no way a production code.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is FormKit?
&lt;/h2&gt;

&lt;p&gt;FormKit is a library that helps you build complex forms in Vue. It is built on top of Vue 3 and uses the composition API. It is very easy to use and has a lot of features. You can check out &lt;a href="https://formkit.com/"&gt;Formkit Website&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why would you need a custom toggle input?
&lt;/h2&gt;

&lt;p&gt;In fact FormKit already has a toggle input and it is great. I just wanted to try to create a custom toggle input using Headless UI and FormKit for the sake of doing it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Component
&lt;/h2&gt;

&lt;p&gt;Everything you need to know about creating custom input for FormKit is documented here: &lt;a href="https://formkit.com/essentials/custom-inputs"&gt;Custom Inputs&lt;/a&gt;. Here is what I ended up with:&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;script &lt;/span&gt;&lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defineProps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;label&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;HeadlessSwitchGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;HeadlessSwitch&lt;/span&gt;
        &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;
        &lt;span class="na"&gt;:name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;
        &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"value ? 'bg-blue-600' : 'bg-gray-200 dark:bg-zinc-700'"&lt;/span&gt;
        &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"relative inline-flex h-6 w-11 items-center rounded-full"&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sr-only"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ label }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt;
          &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"value ? 'translate-x-6' : 'translate-x-1'"&lt;/span&gt;
          &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"inline-block h-4 w-4 transform rounded-full bg-white transition"&lt;/span&gt;
        &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/HeadlessSwitch&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;HeadlessSwitchLabel&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ml-4 text-sm text-zinc-700 dark:text-zinc-200"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ label }}&lt;span class="nt"&gt;&amp;lt;/HeadlessSwitchLabel&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/HeadlessSwitchGroup&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This is just a Headless UI toggle with a custom label which goes in front of the toggle. I used a &lt;code&gt;v-model&lt;/code&gt; to for 2 way binding of &lt;code&gt;value&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;FormKit provides this component with &lt;code&gt;prop.context&lt;/code&gt; and you can get &lt;code&gt;context._value&lt;/code&gt; and when you want to update the value you need to call &lt;code&gt;context.node.input(value)&lt;/code&gt;. So I figured I can write a computed property with getter and setter to achieve that.&lt;/p&gt;

&lt;p&gt;The last part is to register your component with FormKit as a custom input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// formkit.config.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;DefaultConfigOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createInput&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@formkit/vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;FormKitToggle&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;~/components/FormKit/FormKitToggle.vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DefaultConfigOptions&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;inputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;mytoggle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;createInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FormKitToggle&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="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Now you can use your custom toggle input like this:&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;FormKit&lt;/span&gt;
  &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"mytoggle"&lt;/span&gt;
  &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="na"&gt;rest&lt;/span&gt; &lt;span class="na"&gt;of&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>vue</category>
      <category>formkit</category>
      <category>headlessui</category>
    </item>
    <item>
      <title>Shopify theme and Webpack code-splitting</title>
      <dc:creator>Alireza Jahandideh</dc:creator>
      <pubDate>Mon, 30 Aug 2021 14:08:23 +0000</pubDate>
      <link>https://dev.to/youhan/shopify-theme-and-webpack-code-splitting-3b1p</link>
      <guid>https://dev.to/youhan/shopify-theme-and-webpack-code-splitting-3b1p</guid>
      <description>&lt;p&gt;In this post, I want to share how to leverage code splitting for your Shopify theme. There is a minor issue to implement it as you would typically do in a Webpack project which I will share a solution for it. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is code-splitting, and why you may want to do it?
&lt;/h2&gt;

&lt;p&gt;If you don't know what code-splitting is, then, in short, it is a way to deliver the least amount of JS to the browser on page load and let the loaded JS decide when to download the other parts of the code. It makes your website faster to load fists, but the user pays the cost of downloads later in the journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  How is it done with Webpack?
&lt;/h2&gt;

&lt;p&gt;Basically, all bundling tools are capable of code splitting. You can see a report about it here: &lt;a href="https://bundlers.tooling.report/code-splitting/"&gt;https://bundlers.tooling.report/code-splitting/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Webpack there are multiple ways to achieve code-splitting, for the sake of an example you may split lodash like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{...})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To read more, start here: &lt;a href="https://webpack.js.org/guides/code-splitting/#dynamic-imports"&gt;https://webpack.js.org/guides/code-splitting/#dynamic-imports&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After building, you will get two bundled JS files: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;index.bundle.js&lt;/li&gt;
&lt;li&gt;vendors-node_modules_lodash_lodash_js.bundle.js&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You only include &lt;code&gt;index.bundle.js&lt;/code&gt; into your Shopify theme. For example, in the &lt;code&gt;head&lt;/code&gt; of &lt;code&gt;/layouts/theme.liquid&lt;/code&gt; and then the inde.bundle.js will load the other bundles (if needed) afterwards.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight liquid"&gt;&lt;code&gt;&amp;lt;script src="&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'index.bundle.js'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;asset_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;" defer&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;The problem is Shopify serves your theme assets from a CDN that has a different domain. Also, the URL structure is not what Webpack would figure out by itself. Assuming your shop URL is &lt;code&gt;myshop.com&lt;/code&gt;, you may see your &lt;code&gt;index.bundle.js&lt;/code&gt; is loading from &lt;code&gt;https://cdn.shopify.com/s/files/1/1844/8937/t/273/assets/index.bundle.js&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;Webpack provides an option to define the publicPath &lt;a href="https://webpack.js.org/guides/public-path/#on-the-fly"&gt;on the fly&lt;/a&gt;. We can specify the path in the first line of our JS src like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// keep this before your imports&lt;/span&gt;
&lt;span class="nx"&gt;__webpack_public_path__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assetsPath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the value of the &lt;code&gt;assetsPath&lt;/code&gt; can be assigned in your &lt;code&gt;/layouts/theme.liquid&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight liquid"&gt;&lt;code&gt;&amp;lt;script type="application/javascript"&amp;gt;
  window.assetsPath = "&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'index.bundle.js'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;asset_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;".split("index.bundle.js")[0]
&amp;lt;/script&amp;gt;
&amp;lt;script src="&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'index.bundle.js'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;asset_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;" defer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there you have it, code-splitting in your Shopify theme to improve your speed scores and make your client happier.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>shopify</category>
      <category>theme</category>
      <category>webpack</category>
      <category>codesplitting</category>
    </item>
    <item>
      <title>Startups: Should it feel like working for free?</title>
      <dc:creator>Alireza Jahandideh</dc:creator>
      <pubDate>Fri, 30 Oct 2020 02:44:24 +0000</pubDate>
      <link>https://dev.to/youhan/startups-should-it-feel-like-working-for-free-3cig</link>
      <guid>https://dev.to/youhan/startups-should-it-feel-like-working-for-free-3cig</guid>
      <description>&lt;p&gt;Recently I have been asked to join an exciting startup as one of the core developers. I was thinking it is a good opportunity to stop working for other people and start my own. It is just a weekend project until we make an MVP so that they could present it and find investors.&lt;/p&gt;

&lt;p&gt;They say we can't pay you for your work now because we don't have money but record your time and that will be your investment into the company. Later on, when we get to register our business, your share of business will be calculated based on the hours you spend.&lt;/p&gt;

&lt;p&gt;A couple weeks are passed and I realized 10 other people are joined the project from developers to marketing advisors.&lt;/p&gt;

&lt;p&gt;Despite what I hoped for, there has been no group meeting to talk about the progress, business plans, market research, strategies, etc. Maybe I am wrong, but I think at this early point everyone should be involved in planning. &lt;/p&gt;

&lt;p&gt;I am a developer, but when I join as a core member it means I am a founder. The idea is not mine but the implementation will be mine. I expect to contribute to making decisions so to feel like this project is my own, but rather, I am receiving memo like updates about what has been done, who has joined, even a handout of my deliverables!&lt;/p&gt;

&lt;p&gt;At this point I feel like I am being considered to work as a developer for new employers and for free!&lt;/p&gt;

&lt;p&gt;Based on your experience, do you think this is normal? I suspect they just want someone to develop their ideas not a co-founder. What do you think?&lt;/p&gt;

&lt;p&gt;Thanks&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>startup</category>
      <category>career</category>
      <category>experience</category>
    </item>
    <item>
      <title>Shopify theme + Vuejs + Custom Elements: Part 2</title>
      <dc:creator>Alireza Jahandideh</dc:creator>
      <pubDate>Sun, 25 Oct 2020 15:36:55 +0000</pubDate>
      <link>https://dev.to/youhan/shopify-theme-vuejs-custom-elements-part-2-4k3p</link>
      <guid>https://dev.to/youhan/shopify-theme-vuejs-custom-elements-part-2-4k3p</guid>
      <description>&lt;p&gt;Continuing on the idea presented at &lt;a href="https://dev.to/youhan/shopify-theme-vuejs-custom-elements-3bnl"&gt;part 1&lt;/a&gt; on this series, in this post, I am going to extend on that. I am going to describe the theme directory structure and how it builds into a Shopify theme.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/Youhan/shopify-vuejs-theme" rel="noopener noreferrer"&gt;https://github.com/Youhan/shopify-vuejs-theme&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Directory structure
&lt;/h2&gt;

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

&lt;span class="nb"&gt;.&lt;/span&gt;
├── dist
└── src
    ├── assets
    ├── config
    ├── layout
    ├── locales
    ├── scripts
    │   ├── account.js
    │   ├── cart.js
    │   ├── collection.js
    │   ├── home.js
    │   ├── layout.js
    │   ├── product.js
    │   └── search.js
    ├── sections
    ├── snippets
    ├── styles
    ├── templates
    └── vue
        ├── components
        │   ├── custom-element
        │   └── global
        ├── entry
        │   ├── account
        │   │   ├── components
        │   │   └── custom-elements
        │   ├── cart
        │   │   ├── components
        │   │   └── custom-elements
        │   ├── collection
        │   │   ├── components
        │   │   └── custom-elements
        │   ├── home
        │   │   ├── components
        │   │   └── custom-elements
        │   ├── layout
        │   │   ├── components
        │   │   └── custom-elements
        │   ├── product
        │   │   ├── components
        │   │   └── custom-elements
        │   └── search
        │       ├── components
        │       └── custom-elements
        ├── filters
        ├── plugins
        ├── store
        └── utils


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;assets, config, layout, locales, sections, snippets, templates&lt;/code&gt; directories need to be copied directly to the &lt;code&gt;dist&lt;/code&gt; folder as they are standard Shopify directories. We use &lt;code&gt;styles&lt;/code&gt; to store our CSS files and &lt;code&gt;scripts&lt;/code&gt; for our JavaScript files. &lt;code&gt;vue&lt;/code&gt; folder contains the Vue apps.&lt;/p&gt;

&lt;p&gt;For each Shopify template file, we may need to build a javascript file that brings us the Webpack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Webpack Setup
&lt;/h2&gt;

&lt;p&gt;What we need to is consider all &lt;code&gt;.js&lt;/code&gt; files in the &lt;code&gt;scripts&lt;/code&gt; directory as an entry point and output the built file in &lt;code&gt;src/assets/&lt;/code&gt; directory. &lt;code&gt;getEntries&lt;/code&gt; function accepts a path and returns an array of entry names.&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;webpackJS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/scripts/*.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/assets&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[name].js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Then we need a rule for &lt;code&gt;.vue&lt;/code&gt; files and &lt;code&gt;.js&lt;/code&gt; files. The below rule will find all .vue files and loads them using &lt;code&gt;vue-loader&lt;/code&gt; plugin.&lt;/p&gt;

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


&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;vue$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue-loader&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="c1"&gt;// any other package that we need to build&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;For JavaScript files, we add a rule to build them using babel&lt;/p&gt;

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

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;js$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;babel-loader&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;node_modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Then we include the vue-loader and extract CSS plugins.&lt;/p&gt;

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

&lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VueLoaderPlugin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;

  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MiniCssExtractPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[name].css&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;The complete file can be found here. &lt;a href="https://github.com/Youhan/shopify-vuejs-theme/blob/master/webpack.config.js" rel="noopener noreferrer"&gt;webpack.config.js&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Vue
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;vue/components&lt;/code&gt; contains the global components and global custom elements. For each entry point, we can add a directory that will contain all private components and private custom elements to itself. And it also contains an &lt;code&gt;index.js&lt;/code&gt; to create and register custom elements using Vue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Custom elements using Vuex store
&lt;/h2&gt;

&lt;p&gt;Let's create two components.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an add to cart button&lt;/li&gt;
&lt;li&gt;a cart counter in the header&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also need to keep the count of cart items in a persistent place so that it would not reset when you navigate to another page. In the image below you can see whenever we click on the add to cart button, the &lt;code&gt;window.localStorage&lt;/code&gt; API is called to persist the value.&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%2Fi%2Fmutalun8rj67hkdez8ie.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%2Fi%2Fmutalun8rj67hkdez8ie.gif" alt="Shopify vue vuex"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Vue Entry
&lt;/h3&gt;

&lt;p&gt;First, we include the &lt;code&gt;src/vue/entry/layout/index.js&lt;/code&gt; in &lt;code&gt;src/scripts/layout.js&lt;/code&gt; file&lt;/p&gt;

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

&lt;span class="c1"&gt;// load vue&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@vue/entry/layout/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;src/vue/entry/layout/index.js&lt;/code&gt; file will look like below:&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vuex&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vuex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@vue/store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;document-register-element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * import a list of custom elements / web components
 * =================================================================*/&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;customElements&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./custom-elements/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * import all needed vue components as global components
 * =================================================================*/&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Setup Vuex
 * =================================================================*/&lt;/span&gt;
&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Vuex&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;vuexStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vuex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Store&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="cm"&gt;/**
 * Register Custom Elements
 * =================================================================*/&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vuexStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;customElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ignoredElements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Vue Components
&lt;/h3&gt;

&lt;p&gt;To include all regular vue components we need to include all global components that will be share across all entry points. These components are mainly layout related components (if any).&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;src/vue/entry/layout/components/index.js&lt;/code&gt; we include global and private components&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Register global components
 * =================================================================*/&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requireGlobalComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../../components/global/&lt;/span&gt;&lt;span class="dl"&gt;"&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="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;vue$/&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;RegisterComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requireGlobalComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Register local components
 * =================================================================*/&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requireComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;vue$/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;RegisterComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requireComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;RegisterComponents&lt;/code&gt; function is just looping over what is passed by &lt;code&gt;require.context()&lt;/code&gt; and registers them using &lt;code&gt;Vue.component()&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;upperFirst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;camelCase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@vue/utils/Helpers.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RegisterComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requireComponents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;requireComponents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// get component config&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;componentConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;requireComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// get pascal-case name of the component&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;componentName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;upperFirst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;camelCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\.\/&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.\w&lt;/span&gt;&lt;span class="sr"&gt;+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// register the component Globally&lt;/span&gt;
    &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;componentName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;componentConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;componentConfig&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;
  
  
  Vue Custom Elements
&lt;/h3&gt;

&lt;p&gt;Now that we have all Vue components registered, let's see how we register the custom elements.&lt;/p&gt;

&lt;p&gt;We have two custom elements that we want to use in our Liquid files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add to cart button&lt;/li&gt;
&lt;li&gt;cart counter (in the header)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside &lt;code&gt;src/vue/entry/layout/custom-elements/index.js&lt;/code&gt; file, we import the globally available custom elements as a list which is exported by &lt;code&gt;vue/components/layout.js&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// Layout specific&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;layoutElements&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@vue/components/layout.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;layoutElements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// any local custom element here&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;vue/components/layout.js&lt;/code&gt; file itself is just a list of imports, like so:&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ExampleAddToCart&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@vue/components/custom-element/ExampleAddToCart.vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ExampleCartCounter&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@vue/components/custom-element/ExampleCartCounter.vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme-add-to-cart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExampleAddToCart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme-cart-counter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExampleCartCounter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;In this case we don't have any local custom element, so it is just to import the global (layout) custom elements.&lt;/p&gt;

&lt;p&gt;At this point our 2 custom elements can be used in Liquid files. Let's see how they look like&lt;/p&gt;

&lt;h3&gt;
  
  
  Add to cart button
&lt;/h3&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;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center justify-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"font-heading text-lg mb-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Example Add to cart Button&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt;
      &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-brand-500 text-white px-4 py-2 rounded hover:bg-brand-700 transition duration-200"&lt;/span&gt;
      &lt;span class="na"&gt;v-on:click=&lt;/span&gt;&lt;span class="s"&gt;"addOne"&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Click to simulate Add to cart
    &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;You have {{ count }} items in your cart.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;You can also reload this page or navigate to other pages&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mapMutations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mapState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vuex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;mapState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cart&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;mapMutations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cart&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addOne&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Here we are using &lt;code&gt;mapMutations&lt;/code&gt; to provide this component with a way to mutate the store state and &lt;code&gt;mapState&lt;/code&gt; to get the state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cart Counter
&lt;/h3&gt;

&lt;p&gt;This component is just displaying the state.&lt;/p&gt;


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

&lt;p&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;({{ count }})&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mapState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vuex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;mapState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cart&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;&lt;br&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Summary&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;You can find the complete code I put on &lt;a href="https://github.com/Youhan/shopify-vuejs-theme" rel="noopener noreferrer"&gt;https://github.com/Youhan/shopify-vuejs-theme&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for each Shopify template file we build a Javascript file&lt;/li&gt;
&lt;li&gt;each Javascript file can/may include Vue custom elements&lt;/li&gt;
&lt;li&gt;each Webpack entry point is responsible to bundle regular js files and also can include a number of custom elements.&lt;/li&gt;
&lt;li&gt;some custom elements can be shared as global custom elements&lt;/li&gt;
&lt;li&gt;other custom elements are local to each entry point and are only bundled in one of the js files.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Originally published at &lt;a href="https://ajahandideh.com/shopify-theme-vuejs-custom-elements-part-2/" rel="noopener noreferrer"&gt;my personal blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>customelements</category>
      <category>shopify</category>
    </item>
    <item>
      <title>Shopify theme + Vuejs + Custom Elements</title>
      <dc:creator>Alireza Jahandideh</dc:creator>
      <pubDate>Sun, 11 Oct 2020 03:10:06 +0000</pubDate>
      <link>https://dev.to/youhan/shopify-theme-vuejs-custom-elements-3bnl</link>
      <guid>https://dev.to/youhan/shopify-theme-vuejs-custom-elements-3bnl</guid>
      <description>&lt;p&gt;This is a 2 part post&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;part 1: Idea (current)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/youhan/shopify-theme-vuejs-custom-elements-part-2-4k3p"&gt;part 2: implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Utilizing the power of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components"&gt;Web Components&lt;/a&gt; it is now possible to create framework-agnostic complex UIs using your favourite JavaScript framework. Recently, I used &lt;a href="https://github.com/karol-f/vue-custom-element"&gt;vue-custom-element&lt;/a&gt; to build a Shopify theme. In this article which is my first ever personal blog post, I am going to explain the idea and the challenges I faced implementing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;That's mainly my personal preference to experience developing with Vuejs and moving the edges of its applications. Turns out you end up with a theme that is more flexible than a conventional Shopify theme.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea
&lt;/h2&gt;

&lt;p&gt;Simply put, the idea is to use custom elements in Liquid template files and pass data to them as &lt;code&gt;props&lt;/code&gt; and &lt;code&gt;slot&lt;/code&gt;s. For example, the following would be a custom element that accepts a Liquid object as the &lt;code&gt;orders&lt;/code&gt; prop.&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;my-orders&lt;/span&gt; &lt;span class="na"&gt;orders=&lt;/span&gt;&lt;span class="s"&gt;"{{-customer.orders | json-}}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-orders&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Liquid is not solid
&lt;/h3&gt;

&lt;p&gt;Shopify uses &lt;a href="https://shopify.github.io/liquid/"&gt;Liquid&lt;/a&gt; files which are like &lt;a href="https://laravel.com/docs/8.x/blade"&gt;Blade&lt;/a&gt; template files if you come from a Laravel world, but the difference is that Blade is designed for developers and Liquid seems to be more end user-oriented resulting in a set of less flexible API.&lt;/p&gt;

&lt;p&gt;Here is the minimal snippet to display cart items in &lt;code&gt;templates/cart.liquid&lt;/code&gt; file&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;table&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"responsive-table"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;colspan=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Product&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Price&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Quantity&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Total&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
    {% for item in cart.items %}
      &lt;span class="nt"&gt;&amp;lt;tr&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;
          {% if item.image != blank %}
          &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{ item.url | within: collections.all }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            {{ item | img_url: '240x240' | img_tag: item.title }}
          &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
          {% endif %}
        &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{ item.url }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ item.product.title }}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

          {% unless item.product.has_only_default_variant %}
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ item.variant.title }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
          {% endunless %}

          &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ item.vendor }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

          {%- assign property_size = item.properties | size -%}

          {% if property_size &amp;gt; 0 %}
            {% for p in item.properties %}
                {% unless p.last== blank %}
                    {{ p.first }}:
                    {% if p.last contains '/uploads/' %}
                        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{ p.last }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ p.last | split: '/' | last }}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                    {% else %}
                        {{ p.last }}
                    {% endif %}
                {% endunless %}
            {% endfor %}
        {% endif %}

          &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/cart/change?line={{ forloop.index }}&amp;amp;amp;quantity=0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;small&amp;gt;&lt;/span&gt;Remove&lt;span class="nt"&gt;&amp;lt;/small&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;data-label=&lt;/span&gt;&lt;span class="s"&gt;"{{ 'cart.label.price' | t }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            {% if item.original_line_price != item.line_price %}
                {{ item.price | money }} &lt;span class="nt"&gt;&amp;lt;s&amp;gt;&lt;/span&gt;{{ item.original_price | money }}&lt;span class="nt"&gt;&amp;lt;/s&amp;gt;&lt;/span&gt;
            {% else %}
                {{ item.price | money }}
            {% endif %}
        &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
            &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt;
            &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"updates[]"&lt;/span&gt;
            &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"updates_{{ item.key }}"&lt;/span&gt;
            &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"{{ item.quantity }}"&lt;/span&gt;
            &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
          &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;
          {{ item.line_price | money }}
        &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;

      {% endfor %}
    &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boring! I feel like in 2008! Also, it is static, when a user updates the quantity the page reloads, when they remove an item, the page reloads. To add a modern look and feel to it (AKA. better UX) the only way to go for is to add jQuery or JS code to the page that prevents the form submission, communicates to &lt;a href="https://shopify.dev/docs/themes/ajax-api/reference/cart"&gt;Cart API&lt;/a&gt; and manipulate the DOM.&lt;/p&gt;

&lt;p&gt;Another thing that I don't appreciate about Liquid is that it encourages to implement the logic alongside the view. That leads to unreadable and hard to maintain code. That is not the case in Balde, since you have the option to abstract away the logic to the controller which is not possible in Shopify.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Element
&lt;/h3&gt;

&lt;p&gt;Using Custom Elements it is possible to move all that into Vuejs to have some fun. In that sense, the &lt;code&gt;templates/cart.liquid&lt;/code&gt; would become.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{% if cart.item_count &amp;gt; 0 %}
  &lt;span class="nt"&gt;&amp;lt;cart-items&lt;/span&gt; &lt;span class="na"&gt;items:&lt;/span&gt;&lt;span class="err"&gt;'{{&lt;/span&gt;&lt;span class="na"&gt;-cart.items&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="na"&gt;json-&lt;/span&gt;&lt;span class="err"&gt;}}'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/cart-items&amp;gt;&lt;/span&gt;
{% else %}
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Cart is empty&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
{% endif %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Awesome! Now we can handle it using Vuejs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vue Components
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;CartItems.vue&lt;/code&gt; file can be registered as a Custom Element using the &lt;a href="https://github.com/karol-f/vue-custom-element"&gt;vue-custom-element&lt;/a&gt; package.&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;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;LineItem&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"line in cartItems"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"line.id"&lt;/span&gt; &lt;span class="na"&gt;:item=&lt;/span&gt;&lt;span class="s"&gt;"line"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/LineItem&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;props&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="s2"&gt;items&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;cartItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;created&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;cartItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parseJson&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;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we accept the &lt;code&gt;items&lt;/code&gt; as a prop and since it will be a JSON String, we need to use &lt;code&gt;JSON.parse&lt;/code&gt; to convert it to an Object.&lt;/p&gt;

&lt;h2&gt;
  
  
  State Management
&lt;/h2&gt;

&lt;p&gt;It would be nice to keep the cart items as an application state and make it accessible to all other components. Maybe we need to show a counter on the cart icon at the header. It could use our state and that will make it effortlessly reactive. When a user adds an item to the cart. We mutate the cart state and instantly our little counter gets updated.&lt;/p&gt;

&lt;p&gt;To do that we can use any state management library like &lt;a href="https://vuex.vuejs.org/"&gt;Vuex&lt;/a&gt;. We can create a Vuex instance and pass it to all registered Custom elements.&lt;/p&gt;

&lt;p&gt;But the problem is that this is not a SPA, Vuex store is an in-memory state, that is, whenever you navigate to another Shopify route the Vuex store data are destroyed. There is a simple solution to that. We can persist state in &lt;code&gt;window.LocalStorage&lt;/code&gt;. That way we hydrate the store from LocalStorage when Vuex is loaded.&lt;/p&gt;

&lt;p&gt;Aside from reactivity, another benefit to this is that it provides us with a significant little UX improvement. I have noticed many users open PDP pages in New Tab while browsing the product list. Then if you go to a product page and add one to your cart, the other tabs don't have any idea about the state. So, they need to refresh again which is not going to make your UX developer happy.&lt;/p&gt;

&lt;p&gt;Now since we are persisting the state, we can also listen to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;storage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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 mutate the state. Bingo! all open tabs will get updates if you add a product to the cart.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is next
&lt;/h3&gt;

&lt;p&gt;In &lt;a href="https://dev.to/youhan/shopify-theme-vuejs-custom-elements-part-2-4k3p"&gt;part 2&lt;/a&gt; I will explain the implementation and project structure in more detail.&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://ajahandideh.com/shopify-theme-vuejs-custom-elements-part-1-the-idea/"&gt;https://ajahandideh.com/shopify-theme-vuejs-custom-elements-part-1-the-idea/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>customelements</category>
      <category>shopify</category>
    </item>
  </channel>
</rss>
