Skip to content
Advertisement

Cannot read property ‘$options’ of undefined making external js file for head options

I need to set up global head in Nuxt for my app, which some subpages will overwrite. Those global head needs to contain translated data.

I created seoHead.js file with code:

import Vue from "vue";

export const $t = (sign) => Vue.prototype.$nuxt.$options.i18n.t(sign);

export default {
  title: $t("seoGlobal.title"),
  meta: [
    { charset: "utf-8" },
    { name: "viewport", content: "width=device-width, initial-scale=1" },
    {
      hid: "description",
      name: "description",
      content: $t("seoGlobal.description"),
    },
    {
      hid: "ogSiteName",
      name: "og:site_name",
      content: "Test Page",
    },
    {
      hid: "ogTitle",
      name: "og:title",
      content: $t("seoGlobal.ogTitle"),
    },
    (...)
  ],
};

I import and use this data in my index.vue and other pages like this:

import seoHead from "~/constants/seoHead";

export default {
  head() {
    const metaI18n = this.$nuxtI18nSeo();
    const currentPath = process.env.LP_URL + this.$router.currentRoute.fullPath;
    return {
      ...seoHead,
      meta: [
        {
          hid: "ogLocale",
          name: "og:locale",
          content: metaI18n.meta[0].content,
        },
        {
          hid: "ogLocaleAlternate",
          name: "og:locale:alternate",
          content: metaI18n.meta[1].content,
        },
        {
          hid: "ogUrl",
          name: "og:url",
          content: currentPath,
        },
      ],
    };
  },
(...)

Unfortunately, I am facing Cannot read property '$options' of undefined error. It’s strange for me, because I already used export const $t = (sign) => Vue.prototype.$nuxt.$options.i18n.t(sign); code in another js file. Anyone know why this error appears? You know the best way to translate global head options?

Advertisement

Answer

As discussed in the comments, there seems to be a timing issue with the Nuxt lifecycle and your component: at the time your component seoHead.js is imported, Nuxt has not yet injected its $nuxt object into Vue. So an easy workaround would be to delay the execution of your $t function (which accesses $nuxt):

  1. Change your component to export a function which returns the object, instead of directly exporting the object:
export default function() {
  return {
    title: $t("seoGlobal.title"),
    // ...
  }
}
  1. In index.vue, change your head function to call seoHead when spreading it:
return {
  ...seoHead(),
  // ...

This way, the code which accesses $nuxt will be executed later — not when seoHead is imported, but only when the head function is executed. At this time, the Nuxt lifecycle hopefully has finished its startup work and the required object is in place.


As I said, this is merely a workaround; if you would be calling head immediately in index.vue, the same error would appear. So unless you find out a proper way to integrate into the Nuxt lifecycle, I suggest to also put a safeguard into your translation function:

const $t = (sign) => Vue.prototype.$nuxt 
  ? Vue.prototype.$nuxt.$options.i18n.t(sign)
  : sign

This will return the i18n key if the required infrastructure is not yet in place. Not great, but better than an exception 😉

Alternatively you might be able to directly import your i18n functionality, without going through Nuxt at all; this way you wouldn’t have any dependency on the infrastructure at all — much better.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement