【Nuxt3】トラブりそうなモジュールとその対策メモ

シェアする:

この記事をおすすめしたい人

  • よく分からないままNuxt v3へ移行した人
  • v3にしたら動かないモジュールがあって困ってる人
  • つまりオレ

Nuxt v3の調査、モジュール編です。

使ってるモジュールでv3にしたら挙動がおかしかったものと、対策なんかを考えてみます。

@nuxtjs/i18n

多言語化するためのi18nモジュールです。

まず名前の問題

名前と対応バージョンがこんな↓感じになってますたぶん。

  • nuxt-i18n v6 (Nuxt2)
  • @nuxtjs/i18n v7 (Nuxt2)
  • @nuxtjs/i18n v8 (Nuxt3)

古いi18nを使っていた場合はモジュールの名前が変わっています。 インストールの時もnuxt.configに設定する時も名前が変わるので注意。

設定場所が変わった?

えー、かなり頭を悩ませた部分です。 これについてはバージョンアップで変わった部分があるっぽいので、それは後半に書き足します。

Nuxt3対応のi18nでは設定できる箇所が3つあるようです。

  • nuxt.config.ts
  • i18n.config.ts
  • createI18n

やっかいなのがそれぞれでどうも挙動が違うんですよね…。

nuxt.config.ts

i18n公式のInstallationにnuxt.config.tsで設定できるよとあります。 v2と同じ書き方です。

ところがですね、ここでこんな↓風にmessagesを定義すると


  i18n: {
    locales: ['ja', 'en'],
    defaultLocale: 'ja',
    messages: {
      ja: {
        b1: 'あ',
      },
      en: {
        b1: 'a',
      },
    },
  },

起動後に中身が空になっていました。

v2の時はこんな↓風にvueI18nの中になっていたのでそれで定義すると別のエラーがでます。


  i18n: {
    locales: ['ja', 'en'],
    defaultLocale: 'ja',
    vueI18n: {
      messages: {
        ja: {
          b1: 'あ',
        },
        en: {
          b1: 'a',
        },
      },
    },
  },

v3では「vueI18n」は外部の設定ファイルのパスを定義する文字列になっているのでそのせいかなーと。

この現象が特定のバージョンのバグなのか、仕様なのかがちょっと分からなくて、とりあえず僕が試したバージョンでは動きませんでしたよと。

i18n.config.ts

i18n公式のUsageに書いてある方法です。

まずnuxt.configでこの↓ように定義します。


  i18n: {
    vueI18n: './i18n.config.ts',
  },

プロジェクトルートに「i18n.config.ts」がある場合は上記設定はなくてもいいみたいです。 自動インポートされました。

i18n.config.tsはこの↓ように書きます。


export default defineI18nConfig(() => ({
  locales: ['ja', 'en'],
  defaultLocale: 'ja',
  messages: {
    ja: {
      b1: 'あ',
    },
    en: {
      b1: 'a',
    },
  }
}))

これで起動するとmessagesはちゃんと定義できていますが、locales、defaultLocaleが未定義状態でした。

createI18n

pluginsフォルダに設定ファイルを置いて、createI18nを使う方法です。

pluginsにテキトーな名前でファイルを置き、こんな↓中身にします。


import { createI18n } from 'vue-i18n'

export default defineNuxtPlugin(nuxtApp => {
  const i18n = createI18n({
    locales: ['ja', 'en'],
    defaultLocale: 'ja',
    messages: {
      ja: {
        b1: 'あ',
      },
      en: {
        b1: 'a',
      },
    }
  })
  
  nuxtApp.vueApp.use(i18n)
})

これで登録するとウワーっとこんな↓警告がでます。


[Vue warn]: Component "i18n-t" has already been registered in target app.

テストの時は警告は出るけどちゃんと登録できてた気がしたんですが、今みるとどれも設定できてなかったです。 これはVue用なんだろうか。

以上から、基本的な設定はnuxt.config.tsで行い、messagesだけはi18n.config.tsで定義するのが正解なのかなと。 他にも妙な挙動をするやつがいたら適宜どちらかへ移動。

挙動的に安定していない感じがするので、使用環境に応じて柔軟に対応するのがいいのかもしれない。

Ver.9くらいからの変更

上のやり方で@nuxtjs/i18nのVer.8.5.3まではうまくいっていたんですが、新プロジェクトではVer.9.1.1がインストールされて、また挙動が違うかったのでメモしておきます。

色々ためしたところ基本的には変更はなくて、メインはnuxt.config.ts、messagesだけi18n.config.tsというのは変わっていなかったです。

ところがnuxt.config.tsのこの部分↓がデフォルトで設定されなくなったようでmessagesが未定義でした。


    i18n: {
      vueI18n: './i18n.config.ts',
    },
  

上のコードをnuxt.config.tsに明示してやればちゃんとmessagesがi18n.config.tsからインポートされました。

この変更?バグ?はきっちりVer.9から起きたわけじゃなくて、Ver.8の最新版でも同様の症状でした。

switchLocalePathのバグ?

switchLocalePathは、現在のページの別言語ページのパスを出力する関数です。 これがですね、例えば「/」に対して英語版(en)なら「/en/」と出力してほしいんですが、「/」になっていました。

これもi18nのVer.9系でのバグかと思って、ちゃんと動いてたVer.8.5.3をインストールしてみたんですが状況が変わらず…

どういうこっちゃ。

調べていると、vue-routerのバージョンによって正しくパスが出力されないらしく、海外ニキ達が議論してました。

ただ、ここにあるのはVer.4.3.1に問題があるらしくて、4.3.0を使ってねみたいな話だったんですが、自分の環境に入っていたのはVer.4.5.0。 こちらも正しく動いていたプロジェクトのVer.4.4.5をインストールすると…

あかんやん!!

ほな、i18nもVer.8.5.3に落として…

これもあかんやん!!

じゃー、nuxtもvueもバージョン合わせて…

どないなっとんねん!!

で、他に別プロジェクトと違うところを調べてたら、今回のプロジェクトはトップページだけの構成だったのでpagesフォルダを作らずにapp.vueで作業してたんですね。 どうもこれで内部的にパスが生成されてない?判定になってたのか、pagesフォルダにindex.vueを作ったら無事に動きました。 もろもろのモジュールを最新版にしてもちゃんと動きました。

i18nを使うならpagesフォルダは必須!

呼び出し側の変更

メインとなる$t()はv2と同じように使えました。 script側で特別な操作はいらないようです。


<template>
<h1>{{$t('title')}}</h1>
</template>

現在の言語の判定など、v2で「this.$i18n」でアクセスしていた部分はこの↓ような格好になります。


const { $i18n } = useNuxtApp()

if ( $i18n.locale == ja ) {
  
}

ただし、localeが普通の文字列ではなくref()?らしく、上の評価は日本語ページにいたとしてもfalseが返ります。 正しく動作させるにはこう↓書けばいいみたい。


const { $i18n } = useNuxtApp()

if ( $i18n.locale.value == ja ) {
  
}

その他、言語のスイッチ(switchLocalePath )や指定のページのパス取得(localePath)などはComposablesとして定義されているみたいで、ちょっと使い方が変わっています。 詳しくは公式を見てください。 ここは難しくないと思います。

設定の部分だけクリアすればそんなに難しくないと思います。

i18nを使っていたプロジェクトがAMPだったのでv3化を断念したため、上記のテスト以降の実践が止まっています。 別プロジェクトでi18nを使っているものがあるのでそちらでもうちょっと実践的なテストができれば追試しようと思います。

@nuxtjs/google-gtag

GoogleのGTAGやGA4のためのモジュールです。

うちではv2で「@nuxtjs/google-gtag」で、これだとv3でエラーが出たので、公式に習って「nuxt-gtag」にしたらエラーが出なくなりました。

i18nとは表記が逆に変化してますね。 単純にv3用にプロジェクトを分けたとかそんななのかな。

コンポーネント内での呼び出しは、v2で「this.$gtag」だったのがこんな↓感じでコンポーザブルを使うようになっています。


const { gtag } = useGtag()

@nuxtjs/amp

公式のv3にバリバリ紹介されていますが、これたぶんv3には対応してないです。 こんな↓エラーが出ます。


Cannot destructure property 'nuxt' of 'this' as it is undefined.

モジュールのソースを見たりけっこう細かく調べましたが、「vue-renderer:ssr:templateParams」とかv3には存在しないフックで処理されてるところがあるので、単純にエラーを潰しただけじゃ動かないと思います。 リリースノートを見ると2021年1月が最終更新なのでまぁしゃーない。

というわけで手動でAMP化できないか試した記事を紹介しておきます。

htmlタグにampを追加して、上のとは別のフックでAmp Optimeserに食わせて必須スクリプト関係をクリアした後にエラーを潰していきました。

以下のような問題はクリアしました。

  • amp-imgなどの専用タグでのエラー回避
  • head、bodyのゴミ掃除
  • amp-sidebarなどのためにbody直下への配置

ただ、CSSだけがフックではどうにもできなくて、未解決問題です。 最初からAMP ValidなCSSを書けば現状でもAMP化はできるかも。

これを自前でクリアできないならAMPプロジェクトはv3へ移行しない方がいいと思います。 そもそもNuxtでAMP書いてる人がどれほどいるか分からないけど。

@nuxtjs/pwa

AMPと同様のエラーが出ます。


Cannot destructure property 'nuxt' of 'this' as it is undefined.

こいつも2021年1月から更新が止まってるのでおそらくだめっぽ。

ただ、たぶんこいつがやってるのってmanifestとサービスワーカの出力だけだと思うので、AMPと違って移植はできそう。

優先度低いですがトライしておきます。

style-resources

SCSSとかの変数をグローバルで使えるようになるモジュールです。

検索するとこの手の記事はいっぱいでてくるんですが、公式がNuxt v3対応みたいな書き方してたのでそのまま動かしてみたのですが動かず…。

公式にも

Viteを使えばモジュールいらないよ!

って書いてたのでnuxt.configにこんな↓風にかけばいいよとあったのでそれに。


vite: {
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "@/css/_var.scss" as *;`,
      },
    },
  },
},

これでちゃんと動いたので、style-resourcesと、style-resourcesでしか使ってなかったsass-loaderが削除されました。

postcss-loader

postcssってよく分かってなくて、v2の頃にgridのautoprefixerのために入れてるつもりでした。

v3ではデフォルトでpostcssの設定項目があるのでこれも不要かな?

書きかけメモ

小規模プロジェクトからv3への移行をテスト中です。

メインのオレGAMEはタイトルによってけっこういろいろモジュール使ってるのでそっちで追加のテストをしようと思います。

よし、久々にやっとくか。

以上、WordPressからお届けしました!

シェアする: