環境(ローカル、テスト・STG・本番)毎に値(APIのURL等)が変わるのを、RailsのConfig Gemみたいに持てないかと、今回は日本語のみですが、言語ファイル(i18n)で共通化出来ないかも試したので、メモしておきます。

結論、cross-envは使わずに、publicRuntimeConfigを使用しました。
また、i18nは導入すれば、templateとexport内では問題なく使えます。
ただ、vee-validateのextend内ではundefinedになるので、configureで対応しました。

前回作った下記に導入して行きます。
vee-validateで入力チェックした上で、APIからの入力エラーも各項目に表示する

publicRuntimeConfigで環境毎に値を保持

SPA(Single Page Application)で作っているので、publicを使います。

nuxt.config.js に追加

import colors from 'vuetify/es5/util/colors'

+ const environment = process.env.NODE_ENV || 'development'
+ const config = require(`./config/${environment}.js`)

export default {
+   publicRuntimeConfig: config,

.vueファイルで$configやthis.$configで、development.jsやproduction.js内の値が参照出来ようになります。
.envで定義して、process.envで参照しても良いですが、DB接続情報やクレデンシャル(シークレットキー等)ではないので、こちらを採用しました。
また、cross-envはprocess.envで、.env以外のファイルを参照できるのが利点だと思います。
ただ、$configと明確に分けた方が取得元が分かりやすいので、今回は導入しませんでした。

  auth: {

    strategies: {
      local: {

        endpoints: {
-          login: { url: 'http://localhost:3000/users/auth/sign_in.json', method: 'post' },
+          login: { url: config.authSignInURL, method: 'post' },
-          logout: { url: 'http://localhost:3000/users/auth/sign_out.json', method: 'delete' },
+          logout: { url: config.authSignOutURL, method: 'delete' },
-          user: { url: 'http://localhost:3000/users/auth/validate_token.json', method: 'get' }
+          user: { url: config.authUserURL, method: 'get' }

ここでは$configが使えないので、requireしているconfigで参照。

config/development.js を作成

module.exports = {
  authSignInURL: 'http://localhost:3000/users/auth/sign_in.json',
  authSignOutURL: 'http://localhost:3000/users/auth/sign_out.json',
  authUserURL: 'http://localhost:3000/users/auth/validate_token.json',
  singUpUrl: 'http://localhost:3000/users/auth/sign_up.json',
  singUpConfirmSuccessUrl: 'http://localhost:5000/users/sign_in'
}

jsonでも出来ますが、jsで揃えたいし、コメントも書けるので、こちらを採用しました。

config/production.js,prod を作成
(サーバーは全てproductionモードにしたいので、これをコピーしてからbuildする想定)

module.exports = {
  authSignInURL: 'https://example.com/users/auth/sign_in.json',
  authSignOutURL: 'https://example.com/users/auth/sign_out.json',
  authUserURL: 'https://example.com/users/auth/validate_token.json',
  singUpUrl: 'https://example.com/users/auth/sign_up.json',
  singUpConfirmSuccessUrl: 'https://front.example.com/users/sign_in'
}

.gitignore に追加
(なので、Git管理外に)

config/production.js

pages/users/sign_up.vue を変更

  methods: {
    async signUp () {
-      await this.$axios.post('http://localhost:3000/users/auth/sign_up.json', {
+      await this.$axios.post(this.$config.singUpUrl, {
        name: this.name,
        email: this.email,
        password: this.password,
        password_confirmation: this.password_confirmation,
-        confirm_success_url: 'http://localhost:5000/users/sign_in'
+        confirm_success_url: this.$config.singUpConfirmSuccessUrl

publicRuntimeConfigで定義した値のが、this.$configで取得できます。


ここまでのコミット内容
https://dev.azure.com/nightonly/nuxt-app-origin/_git/nuxt-app-origin/commit/99b00c2e935afa546f483de7108cb6d36324aef5

i18n対応

$ yarn add @nuxtjs/i18n

nuxt.config.js に追加

  modules: [
+    '@nuxtjs/i18n',
    '@nuxtjs/axios',
    '@nuxtjs/auth',
    '@nuxtjs/toast',
    '@nuxtjs/pwa'
  ],

+  // I18n module configuration: https://i18n.nuxtjs.org/
+  i18n: {
+    locales: [
+      { code: 'ja', iso: 'ja', file: 'ja.js' }
+    ],
+    defaultLocale: 'ja',
+    lazy: true,
+    langDir: 'locales/'
+  },

今回は日本語しか使わないので、jaのみ定義しています。

locales/ja.js を作成

module.exports = {
  network: {
    failure: '通信に失敗しました。しばらく時間をあけてから、やり直してください。'
  },
  auth: {
    signed_out: 'ログアウトしました。',
    already_authenticated: '既にログインしています。',
    already_signed_out: '既にログアウトされています。'
  }
}

pages/users/sign_up.vue を変更
(sign_in.vue, sign_out.vueも同様に変更)

         <validation-provider v-slot="{ errors }" name="password_confirmation"
-            rules="required|confirmed:password">
+            rules="required|confirmed_password:password">

confirmedをconfirmed_passwordにして、ルール変えずに、後続で独自メッセージを設定しています。

- import { ValidationObserver, ValidationProvider, extend, setInteractionMode } from 'vee-validate'
+ import { ValidationObserver, ValidationProvider, extend, configure, localize } from 'vee-validate'
import { required, email, min, confirmed } from 'vee-validate/dist/rules'
import Message from '~/components/Message.vue'

- setInteractionMode('eager')

setInteractionModeはデフォルトeagerなので、消しちゃいました。

- extend('required', {
-   ...required,
-   message: '入力してください。'
- })
- extend('email', {
-   ...email,
-   message: '形式が正しくありません。'
- })
- extend('min', {
-   ...min,
-   message: '{length}文字以上で入力してください。'
- })
- extend('confirmed', {
-   ...confirmed,
-   message: 'パスワードと一致しません。'
- })
+ extend('required', required)
+ extend('email', email)
+ extend('min', min)
+ extend('confirmed_password', confirmed)

ルールはconfirmedで、メッセージはconfirmed_password(locales/validate.ja.jsで定義)

+ configure({ generateMessage: localize('ja', require('~/locales/validate.ja.js')) })

validate用の言語ファイルを作成して、設定しています。
messageに$tが使えなくてハマりましたが、こっちの方が1行で済むので良い。

message: this.$t(‘messages.required’)
> TypeError: Cannot read properties of undefined (reading ‘$t’)
message: $t(‘messages.required’)
> ReferenceError: $t is not defined

-      this.$toasted.info('既にログインしています。')
+      this.$toasted.info(this.$t('auth.already_authenticated'))
-            this.$toasted.error('通信に失敗しました。しばらく時間をあけてから、やり直してください。')
+            this.$toasted.error(this.$t('network.failure'))

nuxt.config.jsで設定した言語ファイル(locales/ja.js)を参照しています。

locales/validate.ja.js を作成

module.exports = {
  messages: {
    // confirmed: '致していません。', // "{_field_}が一致しません",
    confirmed_password: 'パスワードと一致していません。',
    email: '形式が正しくありません。', // "{_field_}は有効なメールアドレスではありません",
    min: '{length}文字以上で入力してください。', // "{_field_}は{length}文字以上でなければなりません",
    required: '入力してください。' // "{_field_}は必須項目です",
  }
}

extendで指定したキーに対して、メッセージを設定出来ます。
「パスワードと一致していません。」の「パスワード」が渡せるようになってなかったので、この方法にしました。


もっと共通化出来そうですが、可読性は今の方が良さそうに思えるので、一旦、保留にしました。

ここまでのコミット内容
https://dev.azure.com/nightonly/nuxt-app-origin/_git/nuxt-app-origin/commit/5278f6882745285c92f90b15d82b17f84fa3410a

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です