Crafting my Portfolio - Meta Tags for SEO
Tags: vue, nuxt, tailwindcss, portfolio
Published: 2022-11-30 08:58:02

> This is a Series of Posts where I'm sharing my journey (sort of) while I craft my Portfolio.

Writing this post reminds me of my days with WordPress. I still remember Rank Math was the new kid in the town and I decided to use it because its name sounded cool. Turned out it taught me a few things about SEO. Anyway, The whole game of SEO starts from **Meta Tags**. Without Meta Tags, there won't be enough information for search engine to act on, causing its visibility to drop. Moreover, say you shared your cool looking website on a social media platform or WhatsApp'd your friend. It's just going to be a link with nothing to say about it.

Now with Nuxt, The good thing is it comes with its inbuilt SEO system. It makes use of [vueue/head](https://github.com/vueuse/head) under the hood to provide an easy-to-access API for manipulating the Meta Tags and other SEO related information in head. More [here].(https://nuxt.com/docs/getting-started/seo-meta)

## Title
Now, the first thing I want to do is set a title for my site in Meta Tags. I want it to be like '<page-specified-title> | Hardeep Kumar' or just 'Hardeep Kumar' when there is no `<page-specified-title>`. To do this, I can use [`titleTemplate`](https://nuxt.com/docs/api/composables/use-head#meta). Which could be something like:

```ts
useHead({
  titleTemplate: (titleChunk) => {
    return titleChunk ? `${titleChunk} | Hardeep Kumar` : 'Hardeep Kumar';
  },
});
```

But there is a catch, `nuxt.config` does not allow functions in it. And it could be bother to mention this in every single page. Also, the later part is supposed to act like a Default or Fallback. Hmm.. Now what? Well, that where plugins system comes in. I can create a Plugin named `title` and add this logic there, which will be implemented on every page. Also, Nuxt devs mentioned this approach [here](https://github.com/nuxt/framework/issues/4984).

```zsh
npx nuxi add plugin title
```

```ts
export default defineNuxtPlugin(() => {
  useHead({
    titleTemplate: (titleChunk) => {
      return titleChunk ? `${titleChunk} | Hardeep Kumar` : 'Hardeep Kumar';
    },
  });
});
```

This will take care of Title.

## Find Meta Tags
Title is done, Next up I have to add other relevant Meta Tags to the Pages. But what are those tags going to be? Well One can certainly Google up the answer to that, but it will a bit of trouble to open many websites, write down various tags, then use them etc. To ease the process, I used a site named [metaSEO](https://metaseo.itsvg.in). (I once saw their site [https://gprm.itsvg.in](https://gprm.itsvg.in) in here.)

The process is quite straight forward. I first add my site address.

![site address](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6d3syg707ocya34kvg77.png)

Then I proceed to add needed Information. It also shows Preview Cards.

![preview cards](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0kpn56jiw57u6se0it2m.png)

And finally, press generate to get all the Meta Tags with data prefilled. And these are exactly the tags that I was looking for.

![tags](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dwsuwy5v3yvdo1gxydbl.png)

## Implement in Nuxt
With the Meta Tags at hand, next I have to implement in my Application. I'll divide few Tags as default, that will be set by default regardless of page. Like copyright... wait... It's just one tag...

Anyway, time to implement them. In various pages, I'll make use of `useHead` composable to set Meta's data. But yes the syntax of setting tags is a bit different, we can't just set tags in HTML format, It's JS(TS) we're writing here, it's going to be different.

```ts
# nuxt.config.ts
....
app: {
  head: {
    meta: [{ name: 'copyright', content: 'Hardeep Kumar' }],
  },
},
....
```

On Individual Page, Index Here. I also went ahead and add one more tag `og:image:alt` for embed image alt text.

```ts
<script lang="ts" setup>
useHead({
  meta: [
    {
      name: 'description',
      content:
        "Hi! I'm Hardeep Kumar, a Web Developer. I work with Django. Django REST Framework, FastAPI, Vue JS and Nuxt JS.",
    },
    {
      name: 'keywords',
      content:
        'Hardeep Kumar, wrench1815, portfolio, Hardeep, website, Web Developer, Nuxt Developer, Vue JS Developer, Django Developer, FastAPI Developer',
    },

    // open graph
    { property: 'og:type', content: 'website' },
    { property: 'og:url', content: 'https://hardeepkumar.in' },
    { property: 'og:title', content: 'Hardeep Kumar' },
    {
      property: 'og:description',
      content:
        "Hi! I'm Hardeep Kumar, a Web Developer. I work with Django. Django REST Framework, FastAPI, Vue JS and Nuxt JS.",
    },
    {
      property: 'og:image',
      content:
        'https://res.cloudinary.com/dnzbu6wqv/image/upload/v1669702340/myself/94FKLoemnSP7ikhmOunf--3--2fao5_4x_at5csh.jpg',
    },
    {
      property: 'og:image:alt',
      content: 'Hardeep Kumar AI generated art image',
    },

    // twitter
    { property: 'twitter:card', content: 'summary_large_image' },
    { property: 'twitter:url', content: 'https://hardeepkumar.in' },
    { property: 'twitter:title', content: 'Hardeep Kumar' },
    {
      property: 'twitter:description',
      content:
        "Hi! I'm Hardeep Kumar, a Web Developer. I work with Django. Django REST Framework, FastAPI, Vue JS and Nuxt JS.",
    },
    {
      property: 'twitter:image',
      content:
        'https://res.cloudinary.com/dnzbu6wqv/image/upload/v1669702340/myself/94FKLoemnSP7ikhmOunf--3--2fao5_4x_at5csh.jpg',
    },
  ],
});
</script>
```

Meta tags in Head of Index.

![Index Meta tags](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cxxwjirci1hn1srx9lan.png)

No Meta tags for about page except title and copyright. Title being set by plugin and copyright being set via `nuxt.config`.

![no about tags](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jzjcwdmbgi67z0iu42k9.png)

Now for About Page.

```ts
....
useHead({
  title: 'About',

  meta: [
    {
      name: 'description',
      content:
        "Hi! I'm Hardeep Kumar, a Web Developer. I work with Django. Django REST Framework, FastAPI, Vue JS and Nuxt JS.",
    },
    {
      name: 'keywords',
      content:
        'Hardeep Kumar, wrench1815, portfolio, Hardeep, website, Web Developer, Nuxt Developer, Vue JS Developer, Django Developer, FastAPI Developer',
    },

    // open graph
    { property: 'og:type', content: 'website' },
    { property: 'og:url', content: 'https://hardeepkumar.in' },
    { property: 'og:title', content: 'Hardeep Kumar' },
    {
      property: 'og:description',
      content:
        "Hi! I'm Hardeep Kumar, a Web Developer. I work with Django. Django REST Framework, FastAPI, Vue JS and Nuxt JS.",
    },
    {
      property: 'og:image',
      content:
        'https://res.cloudinary.com/dnzbu6wqv/image/upload/v1669702340/myself/94FKLoemnSP7ikhmOunf--3--2fao5_4x_at5csh.jpg',
    },
    {
      property: 'og:image:alt',
      content: 'Hardeep Kumar AI generated art image',
    },

    // twitter
    { property: 'twitter:card', content: 'summary_large_image' },
    { property: 'twitter:url', content: 'https://hardeepkumar.in' },
    { property: 'twitter:title', content: 'Hardeep Kumar' },
    {
      property: 'twitter:description',
      content:
        "Hi! I'm Hardeep Kumar, a Web Developer. I work with Django. Django REST Framework, FastAPI, Vue JS and Nuxt JS.",
    },
    {
      property: 'twitter:image',
      content:
        'https://res.cloudinary.com/dnzbu6wqv/image/upload/v1669702340/myself/94FKLoemnSP7ikhmOunf--3--2fao5_4x_at5csh.jpg',
    },
  ],
});
....
```

And now About also have its Meta data.

![Meta on About](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ep84lsofex01l64muzga.png)

---
# Update
## SEO Card Previews
~~The address being used is Preview deployment.~~

> Note: Twitter has disabled previews in https://cards-dev.twitter.com/validator for the time bieng.

**Twitter Card Preview**

![Twitter Card](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8eoc40vqikain3qe7fp.png)

**Facebook Card Preview**

![Facebook card](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f7h5119zprdqraozyzjq.png)

**Dev.to Embed preview**

I might need to do something about the image... maybe... or maybe not...
{% embed https://hardeepkumar.in %}

---
## Closing Thoughts
I like the setup so far. It's good for now, but can be improved. I could definitely add a composable to set the meta data by just passing an object with `content` values. Which I might do, but I still have to run a few tests on how it will behave and how the current setup is behaving on deploy. Or maybe I could have used [components](https://nuxt.com/docs/getting-started/seo-meta#components) instead.
Do tell me for any mistakes or improvements.

---
Cover Credits: [Stephen Phillips - Hostreviews.co.uk
](https://unsplash.com/@hostreviews)