<?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: Matthew Blewitt</title>
    <description>The latest articles on DEV Community by Matthew Blewitt (@matthewblewitt).</description>
    <link>https://dev.to/matthewblewitt</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%2F156646%2F1eea843e-3755-48d8-992c-00ae26618388.jpg</url>
      <title>DEV Community: Matthew Blewitt</title>
      <link>https://dev.to/matthewblewitt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matthewblewitt"/>
    <language>en</language>
    <item>
      <title>Build a static generated blog with Nuxt v2.13.0 and @nuxt/content</title>
      <dc:creator>Matthew Blewitt</dc:creator>
      <pubDate>Thu, 25 Jun 2020 14:36:46 +0000</pubDate>
      <link>https://dev.to/matthewblewitt/build-a-static-generated-blog-with-nuxt-v2-13-0-and-nuxt-content-387p</link>
      <guid>https://dev.to/matthewblewitt/build-a-static-generated-blog-with-nuxt-v2-13-0-and-nuxt-content-387p</guid>
      <description>&lt;p&gt;Nuxt &lt;code&gt;v2.13.0&lt;/code&gt; just dropped and in this version they've made it even easier to generate a fully static website. In this &lt;a href="https://nuxtjs.org/blog/going-full-static"&gt;blog post: Going full static&lt;/a&gt;, they detail the updates and importantly the new command to generate the site as static html: &lt;code&gt;nuxt export&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can combine this new functionality with &lt;code&gt;@nuxt/content&lt;/code&gt;, a &lt;a href="https://content.nuxtjs.org/"&gt;new module&lt;/a&gt; that acts as a Git-based Headless CMS. These are some of the features you get out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Syntax highlighting to code blocks in markdown files using PrismJS.&lt;/li&gt;
&lt;li&gt;Markdown, CSV, YAML, JSON(5)&lt;/li&gt;
&lt;li&gt;Vue components in Markdown&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Let's get started. Run the create nuxt project command and select universal mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-nuxt-app nuxt-blog-starter
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once complete &lt;code&gt;cd&lt;/code&gt; in the newly created folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @nuxt/content
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up config
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;nuxt.config&lt;/code&gt; file we to add the &lt;code&gt;@nuxt/content&lt;/code&gt; module and set the site to &lt;code&gt;target: "static"&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default {
  ...
  target: "static",
  mode: "universal",
  ...
  modules: ["@nuxt/content"],
  content: {
    markdown: {
      prism: {
        theme: false,
      },
    },
  }
  ...
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Add the first post
&lt;/h3&gt;

&lt;p&gt;Create a content folder in the root directory with the following structure and add your markdown file. The folder name will determine the url of the post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nuxt-blog-starter/
  components/
  pages/
  content/
    posts/
      my-first-blog-post/
        index.md
        img/
          image.jpg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Add the Markdown file with the YAML header format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
title: Praesent sed neque efficitur
description: Aliquam ultrices ex eget leo tincidunt
date: 2020-10-10
image: index.jpg
tags:
  - test
  - another
---

Ut ut justo arcu. Praesent sed neque efficitur,
venenatis diam mollis, lobortis erat. Praesent eget
imperdiet odio, tincidunt eleifend mauris. Sed luctus lacinia auctor.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Building the views
&lt;/h2&gt;

&lt;p&gt;We're going to build 3 views:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single post - &lt;code&gt;/pages/posts/_slug.vue&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Post lists - &lt;code&gt;/pages/index.vue&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tags lists - &lt;code&gt;/pages/tags/_slug.vue&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create the single vue
&lt;/h3&gt;

&lt;p&gt;To view a single post we need to create a dynamic route page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nuxt-blog-starter/
  pages/
    posts/
      _.slug.vue
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class="post"&amp;gt;
    &amp;lt;h1&amp;gt;{{ post.title }}&amp;lt;/h1&amp;gt;
    &amp;lt;p class="lead"&amp;gt;{{ post.description }}&amp;lt;/p&amp;gt;
    &amp;lt;nuxt-content :document="post" /&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;
&amp;lt;script&amp;gt;
export default {
  async asyncData({ params, error, $content }) {
    try {
      const postPath = `/posts/${params.slug}`;
      const [post] = await $content("posts", { deep: true })
        .where({ dir: postPath })
        .fetch();
      return { post };
    } catch (err) {
      error({
        statusCode: 404,
        message: "Page could not be found",
      });
    }
  },
  head() {
    return {
      title: this.post.title,
      meta: [
        {
          hid: "description",
          name: "description",
          content: this.post.description,
        },
      ],
      link: [
        {
          rel: "canonical",
          href: "https://nuxt-blog.com/" + this.post.dir,
        },
      ],
    };
  },
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now if you run &lt;code&gt;npm run dev&lt;/code&gt; and go to &lt;code&gt;http://localhost:3000/posts/my-first-blog-post&lt;/code&gt; you will see the post you created.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the post list page
&lt;/h2&gt;

&lt;p&gt;Let's create the index of the blog and list all the posts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nuxt-blog-starter/
  pages/
    index.vue
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class="posts"&amp;gt;
    &amp;lt;h1&amp;gt;Posts&amp;lt;/h1&amp;gt;
    &amp;lt;div v-for="post in posts" :key="post.dir"&amp;gt;
      &amp;lt;h3 class="heading"&amp;gt;{{ post.title }}&amp;lt;/h3&amp;gt;
      &amp;lt;p&amp;gt;{{ post.description }}&amp;lt;/p&amp;gt;
      &amp;lt;p class="tags"&amp;gt;
        &amp;lt;span v-for="tag in post.tags" :key="tag" class="tag"&amp;gt;
          &amp;lt;nuxt-link :to="`/tags/${tag}`"&amp;gt;{{ tag }}&amp;lt;/nuxt-link&amp;gt;
          &amp;amp;nbsp;
        &amp;lt;/span&amp;gt;
      &amp;lt;/p&amp;gt;
      &amp;lt;nuxt-link :to="post.dir"&amp;gt;Read more&amp;lt;/nuxt-link&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;
&amp;lt;script&amp;gt;
export default {
  async asyncData({ params, error, $content }) {
    try {
      const posts = await $content("posts", { deep: true }).fetch();
      return { posts };
    } catch (err) {
      error({
        statusCode: 404,
        message: "Page could not be found",
      });
    }
  },
  head() {
    return {
      title: "Nuxt blog",
      meta: [
        {
          hid: "description",
          name: "description",
          content: "Cool nuxt blog",
        },
      ],
      link: [
        {
          rel: "canonical",
          href: "https://nuxt-blog.com/",
        },
      ],
    };
  },
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating the tags view
&lt;/h3&gt;

&lt;p&gt;Finally let's create the tags lists page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nuxt-blog-starter/
  pages/
    tags/
      _.slug.vue
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class="posts"&amp;gt;
    &amp;lt;h1&amp;gt;Tags: {{ $route.params.slug }}&amp;lt;/h1&amp;gt;
    &amp;lt;div v-for="post in posts" :key="post.dir"&amp;gt;
      &amp;lt;h3 class="heading"&amp;gt;{{ post.title }}&amp;lt;/h3&amp;gt;
      &amp;lt;p&amp;gt;{{ post.description }}&amp;lt;/p&amp;gt;
      &amp;lt;p class="tags"&amp;gt;
        &amp;lt;span v-for="tag in post.tags" :key="tag" class="tag"&amp;gt;
          &amp;lt;nuxt-link :to="`/tags/${tag}`"&amp;gt;{{ tag }}&amp;lt;/nuxt-link&amp;gt;
          &amp;amp;nbsp;
        &amp;lt;/span&amp;gt;
      &amp;lt;/p&amp;gt;
      &amp;lt;nuxt-link :to="post.dir"&amp;gt;Read more&amp;lt;/nuxt-link&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;
&amp;lt;script&amp;gt;
export default {
  async asyncData({ params, error, $content }) {
    try {
      const posts = await $content("posts", { deep: true })
        .where({ tags: { $contains: params.slug } })
        .fetch();
      return { posts };
    } catch (err) {
      error({
        statusCode: 404,
        message: "Page could not be found",
      });
    }
  },
  head() {
    return {
      title: "Tags",
      meta: [
        {
          hid: "description",
          name: "description",
          content: "Cool nuxt blog tags",
        },
      ],
      link: [
        {
          rel: "canonical",
          href: "https://nuxt-blog.com/tags",
        },
      ],
    };
  },
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting up Prism.js
&lt;/h2&gt;

&lt;p&gt;Prism comes along with &lt;code&gt;@nuxt/content&lt;/code&gt; but it renders server-side. If we want to use plugins such as line numbers we need to have it render in the client. To do this create a plugin called prism:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Prism from "prismjs";

// Include a theme:
import "prismjs/themes/prism-tomorrow.css";

// Include the toolbar plugin: (optional)
import "prismjs/plugins/toolbar/prism-toolbar";
import "prismjs/plugins/toolbar/prism-toolbar.css";

// Include the line numbers plugin: (optional)
import "prismjs/plugins/line-numbers/prism-line-numbers";
import "prismjs/plugins/line-numbers/prism-line-numbers.css";

// Include the line highlight plugin: (optional)
import "prismjs/plugins/line-highlight/prism-line-highlight";
import "prismjs/plugins/line-highlight/prism-line-highlight.css";

// Include some other plugins: (optional)
import "prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard";
import "prismjs/plugins/highlight-keywords/prism-highlight-keywords";
import "prismjs/plugins/show-language/prism-show-language";

// Include additional languages
import "prismjs/components/prism-bash.js";

// Set vue SFC to markdown
Prism.languages.vue = Prism.languages.markup;

export default Prism;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Import the prism plugin and call &lt;code&gt;Prism.highlightAll();&lt;/code&gt; in mounted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class="post"&amp;gt;
    &amp;lt;h1&amp;gt;{{ post.title }}&amp;lt;/h1&amp;gt;
    &amp;lt;p class="lead"&amp;gt;{{ post.description }}&amp;lt;/p&amp;gt;
    &amp;lt;nuxt-content :document="post" /&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;
&amp;lt;script&amp;gt;
import Prism from "~/plugins/prism";
export default {
  async asyncData({ params, error, $content }) {
    try {
      const postPath = `/posts/${params.slug}`;
      const [post] = await $content("posts", { deep: true })
        .where({ dir: postPath })
        .fetch();
      return { post };
    } catch (err) {
      error({
        statusCode: 404,
        message: "Page could not be found",
      });
    }
  },
  mounted() {
    Prism.highlightAll();
  },
  head() {
    return {
      title: this.post.title,
      meta: [
        {
          hid: "description",
          name: "description",
          content: this.post.description,
        },
      ],
      link: [
        {
          rel: "canonical",
          href: "https://nuxt-blog.com/" + this.post.dir,
        },
      ],
    };
  },
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Dealing with images
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@nuxt/content&lt;/code&gt; &lt;a href="https://github.com/nuxt/content/issues/106"&gt;doesn't support images in the markdown yet&lt;/a&gt;. The suggested way around this is to use a Vue component and require the images with webpack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class="img"&amp;gt;
    &amp;lt;img :src="imgSrc()" :alt="alt" /&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
export default {
  props: {
    src: {
      type: String,
      required: true,
    },
    alt: {
      type: String,
      required: true,
    },
  },
  methods: {
    imgSrc() {
      try {
        const { post } = this.$parent;
        return require(`~/content${post.dir}/img/${this.src}`);
      } catch (error) {
        return null;
      }
    },
  },
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;N.B.&lt;/strong&gt; &lt;code&gt;@nuxt/content&lt;/code&gt; requires Vue components used in markdown to use &lt;code&gt;&amp;lt;v-img src="index.jpg" alt="Index"&amp;gt;&amp;lt;/v-img&amp;gt;&lt;/code&gt; format.&lt;/p&gt;

&lt;p&gt;Using images this way creates a warning error in the console but it doesn't affect the build &lt;code&gt;¯\_(ツ)_/¯&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
title: Praesent sed neque efficitur
description: Aliquam ultrices ex eget leo tincidunt
date: 2020-10-10
image: index.jpg
tags:
  - test
  - another
---
&amp;lt;v-img src="index.jpg" alt="Index"&amp;gt;&amp;lt;/v-img&amp;gt;
Ut ut justo arcu. Praesent sed neque efficitur,
venenatis diam mollis, lobortis erat. Praesent eget
imperdiet odio, tincidunt eleifend mauris. Sed luctus lacinia auctor.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that we've built this component we can add a featured image to the single view&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;div class="post-header"&amp;gt;
      &amp;lt;h1 class="h1 post-h1"&amp;gt;{{ post.title }}&amp;lt;/h1&amp;gt;
      &amp;lt;p v-if="post.description" class="excerpt"&amp;gt;
        {{ post.description }}
      &amp;lt;/p&amp;gt;
      &amp;lt;div class="post-details"&amp;gt;
        &amp;lt;div class="tags"&amp;gt;
          &amp;lt;span v-for="(tag, i) in post.tags" :key="i" class="tag"&amp;gt;
            &amp;lt;nuxt-link :to="'/tags/' + tag"&amp;gt;#{{ tag }}&amp;lt;/nuxt-link&amp;gt;
          &amp;lt;/span&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class="date"&amp;gt;{{ post.date | date }}&amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;v-img
        v-if="post.image"
        class="post-img"
        :src="post.image"
        :alt="post.title"
      &amp;gt;&amp;lt;/v-img&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;nuxt-content :document="post" /&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;
&amp;lt;script&amp;gt;
import VImg from "~/components/VImg";

export default {
  components: {
    VImg
  },
  async asyncData({ params, error, $content }) {
    try {
      const postPath = `/posts/${params.slug}`;
      const [post] = await $content("posts", { deep: true })
        .where({ dir: postPath })
        .fetch();
      return { post };
    } catch (err) {
      error({
        statusCode: 404,
        message: "Page could not be found"
      });
    }
  },
  mounted() {
    Prism.highlightAll();
  },
  head() {
    return {
      title: this.post.title,
      meta: [
        {
          hid: "description",
          name: "description",
          content: this.post.description
        }
      ],
      link: [
        {
          rel: "canonical",
          href: "https://matthewblewitt.com/posts/" + this.post.slug
        }
      ]
    };
  }
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Generating the static files
&lt;/h2&gt;

&lt;p&gt;We've created our view and now we can generate our static files in &lt;code&gt;dist/&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;nuxt build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; nuxt &lt;span class="nb"&gt;export&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can also run those static files directly by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;nuxt serve
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The blog is now ready to be uploaded to your static hosting of choice on &lt;a href="https://nuxtjs.org/faq/netlify-deployment/"&gt;Netflify&lt;/a&gt; or an S3 bucket. I've uploaded a basic version of this onto &lt;a href="https://github.com/matthewblewitt/nuxt-static-generated-blog"&gt;Github https://github.com/matthewblewitt/nuxt-static-generated-blog&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Originally posted on &lt;a href="https://matthewblewitt.com"&gt;https://matthewblewitt.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>vue</category>
    </item>
    <item>
      <title>Reuse component functionality with the Vue wrapper component pattern</title>
      <dc:creator>Matthew Blewitt</dc:creator>
      <pubDate>Sat, 13 Jun 2020 09:09:52 +0000</pubDate>
      <link>https://dev.to/matthewblewitt/vue-wrapper-component-30jg</link>
      <guid>https://dev.to/matthewblewitt/vue-wrapper-component-30jg</guid>
      <description>&lt;p&gt;When building Vue components I often need to create a component that has similar functionality to an existing base component. I want to re-use the base component and extend it to create a new one.  A good pattern for this is the wrapper component.&lt;/p&gt;

&lt;p&gt;Think of a &lt;code&gt;BaseButton.vue&lt;/code&gt;. It takes some props and emits some events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;button
    :class="`btn btn-${theme}`"
    :disabled="disabled"
    @click="handleClick"
  &amp;gt;
    &amp;lt;slot /&amp;gt;
  &amp;lt;/button&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
export default {
  name: "BaseButton",
  props: {
    theme: {
      type: String,
      default: "info",
      validator: val =&amp;gt;
        [
          "info",
          "success",
          "error"
        ].indexOf(val) !== -1
    },
    disabled: {
      type: Boolean,
      default: false
    }
  }
  methods: {
    handleClick() {
      this.$emit("click");
    }
  }
};
&amp;lt;/script&amp;gt;

&amp;lt;style scoped&amp;gt;
.btn {
  outline: none;
  border: none;
  color: white;
}
.btn-info {
  background: blue;
}
.btn-success {
  background: green;
}
.btn-error {
  background: red;
}
&amp;lt;/style&amp;gt;

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



&lt;p&gt;I now have a need to build a button that shows a loading state with some text and disables the button when passed a prop of &lt;code&gt;loading&lt;/code&gt;. I could cram this new functionality into the BaseButton, but a much cleaner solution is to use a wrapper component pattern. Let's create a &lt;code&gt;LoadingButton.vue&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;BaseButton v-bind="{ ...$props, ...$attrs }" v-on="$listeners"&amp;gt;
    &amp;lt;template v-if="loading"&amp;gt;Loading...&amp;lt;/template&amp;gt;
    &amp;lt;slot v-else /&amp;gt;
  &amp;lt;/BaseButton&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import BaseButton from "~/components/BaseButton";
export default {
  components: {
    BaseButon
  },
  props: {
    ...BaseButton.props,
    loading: {
      type: Boolean,
      default: false
    }
  }
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A couple of this are happening here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pass all the components instance details down to the base components via &lt;code&gt;$props&lt;/code&gt;, &lt;code&gt;$attr&lt;/code&gt;, &lt;code&gt;$listeners&lt;/code&gt;. &lt;a href="https://vuejs.org/v2/api/#vm-attrs"&gt;See more Vue in the docs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;BaseButton.props&lt;/code&gt; to maintain the same props passed down but add additional &lt;code&gt;loading&lt;/code&gt; prop to create the new functionality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A great little pattern for component reusability 🔥&lt;/p&gt;

&lt;p&gt;Originally posted on &lt;a href="https://matthewblewitt.com/posts/vue-wrapper-component"&gt;https://matthewblewitt.com/posts/vue-wrapper-component&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>components</category>
      <category>designpatterns</category>
    </item>
  </channel>
</rss>
