21

It seems that Vue Meta has been upgraded to handle Vue.js 3 with a new npm package called vue-3-meta

Before Vue.js 3, it was easy to use vue-meta by adding it to the Vue instance:

import Vue from 'vue'
import VueMeta from 'vue-meta'
 
Vue.use(VueMeta, {
  // optional pluginOptions
  refreshOnceOnNavigation: true
})

However in Vue.js 3, there is no Vue instance; and instead you create the app by running createApp like such:

const app = createApp(App);
const router = createVueRouter();

app.use(router);
// need to make app use Vue-Meta here

I cannot find any documentation for vue-3-meta. import VueMeta from 'vue-meta' no longer works.

How do I import the vue-3-meta plugin properly and use it with app like in prior versions?

oguz ismail
  • 1
  • 16
  • 47
  • 69
volume one
  • 6,800
  • 13
  • 67
  • 146
  • 2
    Thank you @Eldar. But I still don't understand where `metaManager` is coming from in `app.use(metaManager)`. Where is `metaManager` in App.vue? – volume one Feb 16 '21 at 17:04
  • 1
    For those coming here, I ended up not using vue-meta and used https://github.com/vueuse/head instead which works much better IMO. – volume one Jul 06 '21 at 13:57
  • Yeah, vueuse/head seems to be the proper successor. It is used in Nuxt 3. – cambunctious Dec 21 '22 at 00:00

3 Answers3

60

Disclaimer: vue-meta v3 is still in alpha!

This was the minimal implementation I needed to get started:

  1. Update vue-meta to v3 (in package.json)

    - "vue-meta": "^2.4.0",
    + "vue-meta": "^3.0.0-alpha.7",
    

    ...or with yarn:

    yarn add vue-meta@alpha
    
  2. Add metaManager to Vue app

    import { createMetaManager } from 'vue-meta'
    
    const app = createApp(App)
      .use(router)
      .use(store)
      .use(createMetaManager()) // add this line
    
    await router.isReady()
    app.mount('#app')
    
  3. Add <metainfo> to App.vue <template> (this is also where I set a "title template")

    <template>
      <metainfo>
        <template v-slot:title="{ content }">{{ content ? `${content} | SITE_NAME` : `SITE_NAME` }}</template>
      </metainfo>
      <header />
      <router-view />
      <footer />
    </template>
    
  4. Set default meta in App.vue <script>
    Vue 3 vanilla:

    import { useMeta } from 'vue-meta'
    
    export default {
      setup () {
        useMeta({
          title: '',
          htmlAttrs: { lang: 'en', amp: true }
        })
      }
    }
    

    or with vue-class-component:

    import { setup, Vue } from 'vue-class-component'
    import { useMeta } from 'vue-meta'
    
    export default class App extends Vue {
      meta = setup(() => useMeta({
        title: '',
        htmlAttrs: { lang: 'en', amp: true }
      })
    }
    
  5. Override meta in each component
    Vue 3 vanilla:

    import { useMeta } from 'vue-meta'
    
    export default {
      setup () {
        useMeta({ title: 'Some Page' })
      }
    }
    

    or with vue-class-component:

    import { computed } from '@vue/runtime-core'
    import { setup, Vue } from 'vue-class-component'
    import { useMeta } from 'vue-meta'
    
    export default class SomePage extends Vue {
      meta = setup(() => useMeta(
        computed(() => ({ title: this.something?.field ?? 'Default' })))
      )
    }
    

See also:

charles-allen
  • 3,891
  • 2
  • 23
  • 35
  • I have managed to understand this so far. My question is that do we now define meta information like in the version 2 **(e.g meta : [ { }, { }, ], scripts: [ ] etc )** or is this done another way. – NwaiwuIsidore May 24 '21 at 21:47
  • 1
    @Nwaiwulsidore - The type [`MetaSource` hasn't been written yet](https://github.com/nuxt/vue-meta/blob/next/src/types/index.ts), but there's 1 quite extensive example in Github; see: [App.ts](https://github.com/nuxt/vue-meta/blob/next/examples/vue-router/App.ts), [Child.ts](https://github.com/nuxt/vue-meta/blob/next/examples/vue-router/Child.ts) – charles-allen May 24 '21 at 22:50
  • Thanks for the link. I was able gain some understanding from the github links. Another issue I want to understand is the behaviour between parent and child. In the older vue-meta, metadata from a child is merged with that of the parent except "vmid" is used. In this version, it seems that they are automatically overridden when you specify them in the child. Am I wrong? – NwaiwuIsidore May 25 '21 at 16:55
  • @NwaiwuIsidore - I believe you are correct but I'm only using `v3` of `vue-meta` on a very simple project (so I can't confirm for certain). I haven't seen any ids in the examples; it looks like you just need to specify the same key. Seems v3 is smarter! – charles-allen May 25 '21 at 22:17
  • 1
    -. Thanks. It seems to be "smarter". I tried it out and it seems to work. "For now" – NwaiwuIsidore May 26 '21 at 07:27
  • 2
    How did you manage to figure all this out without any proper documentation? I cannot find this stuff documented anywhere! – volume one Jun 01 '21 at 10:56
  • 2
    @volumeone - Mostly from the vue-router example in the GitHub repo (make sure you're looking at the code in the "next" branch. A little from the README (again "next" branch) & from reading any issue that looked to be for Vue 3. I still struggle with computed meta + vue-class-component. – charles-allen Jun 01 '21 at 13:01
  • FYI - The ["two title" issue](https://github.com/nuxt/vue-meta/issues/667) has just been fixed in `vue-meta@3.0.0-alpha.7` :) – charles-allen Jun 01 '21 at 13:06
  • Hello there, thank you very much for this answer! Cheers ;) – Marco Jun 21 '21 at 19:53
  • Hi, anyone knows whether `titleTemplate` is supported? And if I want to access `this` context inside `titleTemplate`, is this possible? – bambooom Jun 09 '22 at 10:44
  • Looks like titleTemplate isn't supported/working for now as far I see. – Andrew Nov 28 '22 at 16:35
  • is this still a working example? tried it with vue-meta@next and it didn't work – Victor Ferreira Dec 05 '22 at 02:40
  • I haven't used `vue-meta` for some time. I've converted my answer to `community wiki` in case someone else wants to update it. – charles-allen Dec 05 '22 at 15:20
6

In addition to the previous answers, I also needed to add a transpileDependency in my vue.config.js, as I was using vue-cli:

module.exports = {
  transpileDependencies: ['vue-meta']
}

Else, I would get the error:

error  in ./node_modules/vue-meta/dist/vue-meta.esm-browser.min.js

Module parse failed: Unexpected token (8:7170)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

Thanks to this thread for pointing me to this: https://stackoverflow.com/a/65844988/3433137

ElectRocnic
  • 1,275
  • 1
  • 14
  • 25
  • 7
    I found a much better solution which was to drop vue-meta and use @vueuse/head https://github.com/vueuse/head – volume one Jul 06 '21 at 13:57
2

metaManager is a MetaManager instance created from createMetaManager() of vue-meta.

Based on the Vue 3 + Vue Router example for vue-meta, here's an example usage:

import { createApp } from 'vue'
import { createMetaManager, defaultConfig, resolveOption, useMeta } from 'vue-meta'

const decisionMaker5000000 = resolveOption((prevValue, context) => {
  const { uid = 0 } = context.vm || {}
  if (!prevValue || prevValue < uid) {
    return uid
  }
})

const metaManager = createMetaManager({
  ...defaultConfig,
  esi: {
    group: true,
    namespaced: true,
    attributes: ['src', 'test', 'text']
  }
}, decisionMaker5000000)

useMeta(
  {
    og: {
      something: 'test'
    }
  },
  metaManager
)

createApp(App).use(metaManager).mount('#app')
tony19
  • 125,647
  • 18
  • 229
  • 307