DEV Community

Vue Mastery team for Vue Mastery

Posted on • Originally published at vuemastery.com on

Supercharge your code with VueMacros

Supercharge your code w/ the magic of macros

Written by Timi Omoyeni

When writing code, there are certain things we do over and over again that can be a pain and hard to reuse. That’s where macros come in handy. What is a macro? Think of them as a shortcut or pattern that tells the computer how to replace one thing with another. Macros can help us make our code shorter and easier to write.

In JavaScript, macros aren’t built-in like in some other languages. However, we have techniques and special libraries at our disposal to achieve similar benefits. One such library is Vue Macros, which allows us to perform advanced operations with Vue.js, making coding easier and more efficient.

In this article, we’ll take a look at VueMacros for enhancing Vue.js development. We’ll cover installation & configuration, different macro types, and their benefits. By the end, you’ll have a solid understanding of integrating Vue Macros to streamline your Vue.js projects.

Getting Started with VueMacros

VueMacros is a library that implements proposals or ideas that are yet to be officially implemented by Vue. This means it will explore and extend more features and syntax sugar to Vue. This library was created by and is currently maintained by Kevin Deng, a member of the Vue core team. He also contributes to and supports other open-source projects like unplugin and unplugin-vue-components. Using VueMacros requires basic knowledge of Vue, as it plugs into existing Vue code and syntax. It also requires a minimum Node.js version of 16.14.0 or higher and Vue ≥ 2.7 or Vue ≥ 3.0.

Installation & Configuration

Before we can start using any of the available macros in VueMacros, we need to install it in our project. Depending on your preference, this can be done using either npm, pnpm, or yarn.

Yarn

yarn add -D unplugin-vue-macros
Enter fullscreen mode Exit fullscreen mode

After installation, the next step required is to configure our project to use it. There is more than one way to set up a Vue project, and as such, the configuration process would vary depending on the bundler (Vite, Webpack, Vue CLI, etc.) used.

Bundler Integration

By default, VueMacros comes with first-class support for Vite and Rollup, but it also attempts to make the process of integrating with the bundlers seamless.

For this article, we’re going to use Vite as our preferred bundler, but the process for other bundlers is similar and also straightforward.

By default, this is what a vite.config.js file looks like;

vite.config.js

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  test: {
    environment: "happy-dom",
  },
});
Enter fullscreen mode Exit fullscreen mode

In order for us to use the library, we need to import the library and update our plugin configuration. So we’ll update the file to this:

vite.config.js

import { defineConfig } from "vite";
import VueMacros from "unplugin-vue-macros/vite";
import Vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
      },
    }),
  ],
});
Enter fullscreen mode Exit fullscreen mode

Here, we import the VueMacros library into our config file. If we look closely, we can see that it is specifically the Vite version of this library, and this is because it is the only version of the library that will work with a Vite-powered app.

After importing, we add it to the list of plugins and then pass in an object that contains the plugins property. This property accepts an object of plugins, which we pass in the Vue plugin that we also imported into the config file.

If your project is built with TypeScript, additional configuration is necessary in order for things to run smoothly.

tsconfig.json

{
  "compilerOptions": {
    // ...
    "types": ["unplugin-vue-macros/macros-global" /* ... */]
  }
}
Enter fullscreen mode Exit fullscreen mode

Nuxt Integration

If you’re using Nuxt, you can also take advantage of VueMacros. To start with VueMacros in Nuxt, the first step would be installing the library.

Yarn

yarn add -D @vue-macros/nuxt
Enter fullscreen mode Exit fullscreen mode

Once this installation is complete, the next step is to add the library to the list of modules in the nuxt.config.ts file:

nuxt.config.ts

export default {
  modules: [
    '@vue-macros/nuxt',
  ],
}
Enter fullscreen mode Exit fullscreen mode

By default, most macros are enabled and readily available for use in your project after installation, except for a few.

Types of Macros

All the macros that are available in this library have been categorized into three categories based on their availability. These categories are;

  1. Implemented by Vue 3.3.
  2. Stable macros.
  3. Experimental macros.

Implemented by Vue 3.3

This includes features that were introduced with the announcement of Vue 3.3, and there are currently three of them, which include:

  1. defineOptions : This macro allows declaring component options directly in without requiring a separate <script> block.</li> <li><strong>defineSlots</strong> : As the name implies, this macro declares expected slots and their respective expected slot props.</li> <li><strong>shortEmits</strong> : This macro was created to simplify the definition of emits. While this feature was introduced in Vue 3.3, the VueMacros library also offers support for function-style declaration, which is unavailable in the official version.</li> </ol> <h3> <a name="stable-macros" href="#stable-macros" class="anchor"> </a> Stable Macros </h3> <p>Stables macros includes macros that are already stable and often do not require extra configuration before usage. Examples of stable macros include:</p> <ol> <li><strong>defineModels</strong> : This is one of the most used macros in the VueMacros library. It helps abstract the process of two-way data binding between a parent and child component by eliminating the use of props and emits.</li> <li><strong>definePropsRefs:</strong> This macro returns <strong>refs</strong> from defineProps instead of a reactive object. Unlike defineProps, which does not support destructuring without losing reactivity, this macro can be destructured and still remain reactive.</li> <li><strong>shortVmodel</strong> : This macro helps map the v-model to a shorter form (::, $, and *).</li> </ol> <h3> <a name="experimental-macros" href="#experimental-macros" class="anchor"> </a> Experimental Macros </h3> <p>The macros in this category are all experimental features that <em>should not</em> be used in production, but can definitely be experimented with in playground projects. A few of them include:</p> <ol> <li><strong>defineProp</strong></li> <li><strong>defineEmit</strong></li> <li><strong>setupComponent</strong></li> </ol> <h3> <a name="tour-of-macros" href="#tour-of-macros" class="anchor"> </a> Tour of Macros </h3> <p>Now that we have seen a breakdown of macros available in this library, let’s take a look at how some of them work and when to use them.</p> <h3> <a name="defineoptions" href="#defineoptions" class="anchor"> </a> defineOptions </h3> <p>The defineOptions macro allows developers that prefer the composition API and <script setup> to take advantage of some of the properties and configurations available in the options API.</p> <p>In order to use this macro, we need to import the package into our vite.config.ts</p> <p><strong>vite.config.ts</strong><br> </p> <div class="highlight"><pre class="highlight jsx"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">defineConfig</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">vite</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">VueMacros</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">unplugin-vue-macros/vite</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">DefineOptions</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">unplugin-vue-define-options/vite</span><span class="dl">"</span><span class="p">;</span> <span class="c1">// import defineOptions</span> <span class="k">import</span> <span class="nx">Vue</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@vitejs/plugin-vue</span><span class="dl">"</span><span class="p">;</span> <span class="c1">// https://vitejs.dev/config/</span> <span class="k">export</span> <span class="k">default</span> <span class="nf">defineConfig</span><span class="p">({</span> <span class="na">plugins</span><span class="p">:</span> <span class="p">[</span> <span class="nc">DefineOptions</span><span class="p">()</span> <span class="c1">//add to the list of plugins</span> <span class="p">],</span> <span class="p">});</span> </code></pre></div> <p></p> <p>When working with TypeScript, we also need to add configuration for this macro to tsconfig.json in order for it to work.</p> <p><strong>tsconfig.json</strong><br> </p> <div class="highlight"><pre class="highlight json"><code><span class="nl">"compilerOptions"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="err">//</span><span class="w"> </span><span class="err">...</span><span class="w"> </span><span class="nl">"types"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"unplugin-vue-define-options/macros-global"</span><span class="w"> </span><span class="err">/*</span><span class="w"> </span><span class="err">...</span><span class="w"> </span><span class="err">*/</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div> <p></p> <p>Here, we import the defineOptions package into our vite.config.ts file and add it to the list of plugins that our application is making use of. Since we’re using TypeScript, we also add the macro to the types property in our tsconfig.json file.</p> <p>After doing this, we can use the defineOptions macro in any of our components. It accepts values like name, inheritAttrs, etc.<br> </p> <div class="highlight"><pre class="highlight html"><code><span class="nt">&lt;script </span><span class="na">setup</span> <span class="na">lang=</span><span class="s">'ts'</span><span class="nt">&gt;</span> <span class="nf">defineOptions</span><span class="p">({</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">SearchComp</span><span class="dl">"</span><span class="p">,</span> <span class="p">});</span> <span class="nt">&lt;/script&gt;</span> </code></pre></div> <p></p> <p>In this example, we make use of the name property to assign a name to our component. This comes in handy when we do not want to assign the same name of the component file as the component name when viewing from the Vue Devtools.</p> <p><img src="https://cdn-images-1.medium.com/max/423/0*fQqOS0DhsZs9k2jy"/></p> <h3> <a name="definepropsrefs" href="#definepropsrefs" class="anchor"> </a> definePropsRefs </h3> <p>By default, we have access to the defineProps macro in Vue 3, and it works like this:<br> </p> <div class="highlight"><pre class="highlight html"><code><span class="nt">&lt;script </span><span class="na">setup</span> <span class="na">lang=</span><span class="s">"ts"</span><span class="nt">&gt;</span> <span class="nf">defineProps</span><span class="p">([</span><span class="dl">'</span><span class="s1">modelValue</span><span class="dl">'</span><span class="p">])</span> <span class="nt">&lt;/script&gt;</span> <span class="nt">&lt;template&gt;</span> <span class="nt">&lt;section</span> <span class="na">class=</span><span class="s">"search search--expanded"</span><span class="nt">&gt;</span> <span class="nt">&lt;transition</span> <span class="na">name=</span><span class="s">"fade-transform"</span> <span class="na">mode=</span><span class="s">"out-in"</span><span class="nt">&gt;</span> <span class="nt">&lt;form</span> <span class="err">@</span><span class="na">submit.prevent=</span><span class="s">""</span><span class="nt">&gt;</span> <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"search"</span> <span class="na">name=</span><span class="s">"search"</span> <span class="na">id=</span><span class="s">"search"</span> <span class="na">:value=</span><span class="s">"modelValue"</span> <span class="na">placeholder=</span><span class="s">"Search ..."</span> <span class="na">ref=</span><span class="s">"searchInput"</span> <span class="err">@</span><span class="na">input=</span><span class="s">"$emit('update:modelValue', $event.target.value)"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;/form&gt;</span> <span class="nt">&lt;/transition&gt;</span> <span class="nt">&lt;/section&gt;</span> <span class="nt">&lt;/template&gt;</span> </code></pre></div> <p></p> <p>But one of the challenges we constantly face with defineProps is that restructuring props usually leads to the prop losing its reactivity.<br> </p> <div class="highlight"><pre class="highlight jsx"><code><span class="kd">const</span> <span class="p">{</span><span class="nx">modelValue</span><span class="p">,</span> <span class="nx">count</span><span class="p">}</span> <span class="o">=</span> <span class="nf">defineProps</span><span class="p">([</span><span class="dl">'</span><span class="s1">modelValue</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">count</span><span class="dl">'</span><span class="p">])</span> <span class="c1">// loses reactivity</span> </code></pre></div> <p></p> <p>And the only way around this is usually to assign a variable to all the props in the component and then wrap the prop around a computed property:<br> </p> <div class="highlight"><pre class="highlight jsx"><code><span class="kd">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nf">defineProps</span><span class="p">([</span><span class="dl">'</span><span class="s1">modelValue</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">count</span><span class="dl">'</span><span class="p">])</span> <span class="kd">const</span> <span class="nx">modelValue</span> <span class="o">=</span> <span class="nf">computed</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="nx">props</span><span class="p">.</span><span class="nx">modelValue</span><span class="p">)</span> </code></pre></div> <p></p> <p>With the definePropsRefs macro, we can successfully destructure props while still retaining reactivity. This is because it returns refs from defineProps instead of a reactive object.<br> </p> <div class="highlight"><pre class="highlight jsx"><code><span class="kd">const</span> <span class="p">{</span> <span class="nx">modelValue</span><span class="p">,</span> <span class="nx">count</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">definePropsRefs</span><span class="o">&lt;</span><span class="p">{</span> <span class="na">modelValue</span><span class="p">:</span> <span class="nx">string</span> <span class="na">count</span><span class="p">:</span> <span class="nx">number</span> <span class="p">}</span><span class="o">&gt;</span><span class="p">()</span> </code></pre></div> <p></p> <p>With this, we can access any of our props by directly attaching a .value at the end of each prop with their values constantly reacting to changes from the source.</p> <h3> <a name="defineslots" href="#defineslots" class="anchor"> </a> defineSlots </h3> <p>This macro makes it possible to declare expected slots and their respective expected slot props.<br> </p> <div class="highlight"><pre class="highlight html"><code><span class="nt">&lt;script </span><span class="na">setup</span> <span class="na">lang=</span><span class="s">"ts"</span><span class="nt">&gt;</span> <span class="nx">defineSlots</span><span class="o">&lt;</span><span class="p">{</span> <span class="c1">// slot name</span> <span class="na">title</span><span class="p">:</span> <span class="p">{</span> <span class="c1">// scoped slot</span> <span class="na">foo</span><span class="p">:</span> <span class="dl">'</span><span class="s1">bar</span><span class="dl">'</span> <span class="o">|</span> <span class="nx">boolean</span> <span class="p">}</span> <span class="p">}</span><span class="o">&gt;</span><span class="p">()</span> <span class="nt">&lt;/script&gt;</span> </code></pre></div> <p></p> <p>This is also similar to the type property we have when defining props.<br> </p> <div class="highlight"><pre class="highlight jsx"><code><span class="nf">defineProps</span><span class="p">({</span> <span class="na">title</span><span class="p">:</span> <span class="p">{</span> <span class="na">type</span><span class="p">:</span> <span class="p">[</span><span class="nb">Boolean</span> <span class="o">|</span> <span class="nb">String</span><span class="p">],</span> <span class="p">},</span> <span class="p">});</span> </code></pre></div> <p></p> <h3> <a name="definemodels" href="#definemodels" class="anchor"> </a> defineModels </h3> <p>When working with a parent and child component, where the child component utilizes two-way data binding with v-model and the parent component also needs to access and modify this value, the recommended approach has traditionally involved utilizing props to receive the default value from the parent component.</p> <p>Additionally, custom events are used to notify the parent component of any changes that occur within the child component.</p> <p>An example where this applies would be a custom search component:</p> <p><strong>search.vue</strong><br> </p> <div class="highlight"><pre class="highlight html"><code><span class="nt">&lt;script </span><span class="na">setup</span> <span class="na">lang=</span><span class="s">"ts"</span><span class="nt">&gt;</span> <span class="nf">defineEmits</span><span class="p">([</span><span class="dl">"</span><span class="s2">update:modelValue</span><span class="dl">"</span><span class="p">]);</span> <span class="nf">defineProps</span><span class="p">([</span><span class="dl">"</span><span class="s2">modelValue</span><span class="dl">"</span><span class="p">]);</span> <span class="kd">const</span> <span class="nx">vFocus</span> <span class="o">=</span> <span class="p">{</span> <span class="na">mounted</span><span class="p">:</span> <span class="p">(</span><span class="nx">el</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">el</span><span class="p">.</span><span class="nf">focus</span><span class="p">(),</span> <span class="p">};</span> <span class="nt">&lt;/script&gt;</span> <span class="nt">&lt;template&gt;</span> <span class="nt">&lt;section</span> <span class="na">class=</span><span class="s">"search search--expanded"</span><span class="nt">&gt;</span> <span class="nt">&lt;transition</span> <span class="na">name=</span><span class="s">"fade-transform"</span> <span class="na">mode=</span><span class="s">"out-in"</span><span class="nt">&gt;</span> <span class="nt">&lt;form</span> <span class="err">@</span><span class="na">submit.prevent=</span><span class="s">""</span><span class="nt">&gt;</span> <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"search"</span> <span class="na">name=</span><span class="s">"search"</span> <span class="na">id=</span><span class="s">"search"</span> <span class="na">:value=</span><span class="s">"modelValue"</span> <span class="na">placeholder=</span><span class="s">"Search ..."</span> <span class="na">ref=</span><span class="s">"searchInput"</span> <span class="na">v-focus</span> <span class="err">@</span><span class="na">input=</span><span class="s">"$emit('update:modelValue', $event.target.value)"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;/form&gt;</span> <span class="nt">&lt;/transition&gt;</span> <span class="nt">&lt;/section&gt;</span> <span class="nt">&lt;/template&gt;</span> <span class="nt">&lt;style </span><span class="na">lang=</span><span class="s">"scss"</span> <span class="na">scoped</span><span class="nt">&gt;</span> <span class="nc">.search</span> <span class="p">{</span> <span class="nl">transition</span><span class="p">:</span> <span class="n">width</span> <span class="m">300ms</span> <span class="n">ease-in-out</span><span class="p">;</span> <span class="err">&amp;--expanded</span> <span class="err">{</span> <span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span> <span class="nl">max-width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span> <span class="err">@media</span> <span class="err">(</span><span class="nl">min-width</span><span class="p">:</span> <span class="m">768px</span><span class="p">)</span> <span class="err">{</span> <span class="n">width</span><span class="p">:</span> <span class="m">370px</span><span class="p">;</span> <span class="p">}</span> <span class="err">}</span> <span class="o">&amp;</span><span class="nt">__form</span> <span class="p">{</span> <span class="nl">flex-basis</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span> <span class="nl">display</span><span class="p">:</span> <span class="nb">block</span><span class="p">;</span> <span class="p">}</span> <span class="o">&amp;</span><span class="nt">__button</span> <span class="p">{</span> <span class="nl">color</span><span class="p">:</span> <span class="m">#4c5b90</span><span class="p">;</span> <span class="nl">font-size</span><span class="p">:</span> <span class="m">15px</span><span class="p">;</span> <span class="nl">padding</span><span class="p">:</span> <span class="m">8px</span> <span class="m">14px</span><span class="p">;</span> <span class="nl">border-radius</span><span class="p">:</span> <span class="m">4px</span><span class="p">;</span> <span class="err">&amp;:hover</span> <span class="err">{</span> <span class="nl">background</span><span class="p">:</span> <span class="nb">transparent</span><span class="p">;</span> <span class="nl">cursor</span><span class="p">:</span> <span class="nb">pointer</span><span class="p">;</span> <span class="p">}</span> <span class="err">}</span> <span class="o">&amp;</span><span class="nt">__input</span> <span class="p">{</span> <span class="nl">border</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="m">#dde1e9</span><span class="p">;</span> <span class="p">}</span> <span class="err">}</span> <span class="nt">&lt;/style&gt;</span> </code></pre></div> <p></p> <p>Here, we have a modelValue prop that accepts a string (if it applies) that sets the default value in the input field. We also have a vFocus <a href="https://vuejs.org/guide/reusability/custom-directives.html">custom directive</a> that automatically focuses the user’s input in the search box.</p> <p>We need a way to inform the parent component whenever there is a change in value inside the input field, and for this, we use the native @input event present in every input field. In this native input event, we emit an update:modelValue event, which passes the updated value to the parent component.</p> <p>After this, we import the <search /> component into the parent component, where we can see and interact with it.</p> <p><strong>Parent.vue</strong><br> </p> <div class="highlight"><pre class="highlight html"><code><span class="nt">&lt;script </span><span class="na">setup</span><span class="nt">&gt;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">ref</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">vue</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">search</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./components/search.vue</span><span class="dl">"</span><span class="p">;</span><span class="kd">const</span> <span class="nx">searchValue</span> <span class="o">=</span> <span class="nf">ref</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span> <span class="nt">&lt;/script&gt;</span> <span class="nt">&lt;template&gt;</span> <span class="nt">&lt;form&gt;</span> <span class="nt">&lt;search</span> <span class="na">v-model=</span><span class="s">"searchValue"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;p&gt;</span>{{ searchValue }}<span class="nt">&lt;/p&gt;</span> <span class="nt">&lt;/form&gt;</span> <span class="nt">&lt;/template&gt;</span> <span class="nt">&lt;style&gt;</span> <span class="nf">#app</span> <span class="p">{</span> <span class="nl">font-family</span><span class="p">:</span> <span class="n">Avenir</span><span class="p">,</span> <span class="n">Helvetica</span><span class="p">,</span> <span class="n">Arial</span><span class="p">,</span> <span class="nb">sans-serif</span><span class="p">;</span> <span class="nl">-webkit-font-smoothing</span><span class="p">:</span> <span class="n">antialiased</span><span class="p">;</span> <span class="nl">-moz-osx-font-smoothing</span><span class="p">:</span> <span class="n">grayscale</span><span class="p">;</span> <span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="nl">color</span><span class="p">:</span> <span class="m">#2c3e50</span><span class="p">;</span> <span class="nl">margin-top</span><span class="p">:</span> <span class="m">60px</span><span class="p">;</span> <span class="p">}</span> <span class="nt">&lt;/style&gt;</span> </code></pre></div> <p></p> <p>This method works as intended, but it can definitely be cleaner and shorter. This is what led to the introduction of the defineModels macro. The defineModels macro was created to handle the declaring and mutation of v-model props without the need to emit custom events or create props for the sole purpose of communicating updates made to a variable between a parent and child component.</p> <h3> <a name="definemodels-vs-definemodel" href="#definemodels-vs-definemodel" class="anchor"> </a> defineModels vs defineModel </h3> <p>It is important to note that defineModels is quite different from defineModel, which was introduced in <a href="https://blog.vuejs.org/posts/vue-3-3#typed-slots-with-defineslots">Vue 3.3.</a></p> <p><img src="https://cdn-images-1.medium.com/max/613/0*Wx2-hM3RofCgTwmO"/></p> <p>Here, we can see the <a href="https://blog.vuejs.org/posts/volar-a-new-beginning">Vue.js VS Code Volar extension</a> showing a warning indicating the existence of thedefineModel. This macro does the same job as defineModels but the difference is that defineModels is available to Vue 3, Nuxt 3, and Vue 2 users provided they have the VueMacros library installed in their project, while users have to upgrade to Vue 3.3 to enjoy defineModel</p> <h3> <a name="configuration" href="#configuration" class="anchor"> </a> Configuration </h3> <p>In order to take advantage of this macro, you first need to install @vueuse/core in your project. This can be done using either npm or yarn;</p> <p><strong>yarn</strong><br> </p> <div class="highlight"><pre class="highlight plaintext"><code>yarn add @vueuse/core </code></pre></div> <p></p> <p>After this installation, we can now refactor our existing search.vue component to use the defineModels macro.</p> <p><strong>search.vue</strong><br> </p> <div class="highlight"><pre class="highlight html"><code><span class="nt">&lt;script </span><span class="na">setup</span> <span class="na">lang=</span><span class="s">"ts"</span><span class="nt">&gt;</span> <span class="kd">const</span> <span class="p">{</span> <span class="nx">modelValue</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">defineModels</span><span class="o">&lt;</span><span class="p">{</span> <span class="c1">// added here</span> <span class="na">modelValue</span><span class="p">:</span> <span class="nx">string</span><span class="p">;</span> <span class="p">}</span><span class="o">&gt;</span><span class="p">();</span> <span class="kd">const</span> <span class="nx">vFocus</span> <span class="o">=</span> <span class="p">{</span> <span class="na">mounted</span><span class="p">:</span> <span class="p">(</span><span class="nx">el</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">el</span><span class="p">.</span><span class="nf">focus</span><span class="p">(),</span> <span class="p">};</span> <span class="nt">&lt;/script&gt;</span> <span class="nt">&lt;template&gt;</span> <span class="nt">&lt;section</span> <span class="na">class=</span><span class="s">"search search--expanded"</span><span class="nt">&gt;</span> <span class="nt">&lt;transition</span> <span class="na">name=</span><span class="s">"fade-transform"</span> <span class="na">mode=</span><span class="s">"out-in"</span><span class="nt">&gt;</span> <span class="nt">&lt;form</span> <span class="err">@</span><span class="na">submit.prevent=</span><span class="s">""</span><span class="nt">&gt;</span> <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"search"</span> <span class="na">name=</span><span class="s">"search"</span> <span class="na">id=</span><span class="s">"search"</span> <span class="na">:value=</span><span class="s">"modelValue"</span> <span class="na">placeholder=</span><span class="s">"Search ..."</span> <span class="na">ref=</span><span class="s">"searchInput"</span> <span class="na">v-focus</span> <span class="err">@</span><span class="na">input=</span><span class="s">"$emit('update:modelValue', $event.target.value)"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;/form&gt;</span> <span class="nt">&lt;/transition&gt;</span> <span class="nt">&lt;/section&gt;</span> <span class="nt">&lt;/template&gt;</span> <span class="nt">&lt;style </span><span class="na">lang=</span><span class="s">"scss"</span> <span class="na">scoped</span><span class="nt">&gt;</span> <span class="o">...</span> <span class="nt">&lt;/style&gt;</span> </code></pre></div> <p></p> <p>Here, we create a modelValue that is defined using the defineModels macro. This value replaces both the modelValue prop and the update:modelValue event that we’re used to, thereby helping us achieve the same functionality but with fewer lines of code.</p> <p>Behind the scenes, this macro is helping us create both props and custom events, which we have been doing ourselves.</p> <h3> <a name="summing-it-all-up" href="#summing-it-all-up" class="anchor"> </a> Summing it all up </h3> <p>Now that you understand the usefulness of macros, you can experiment with integrating them into your applications (when appropriate) to leverage their abilities to handle complex tasks, reducing the burden on your development process.</p> <p><em>Originally published at</em> <a href="https://www.vuemastery.com/blog/supercharge-your-code-with-vuemacros"><em>https://www.vuemastery.com</em></a> <em>on June 28, 2023.</em></p> <hr>

Top comments (0)