Motomichi Works Blog

モトミチワークスブログです。その日学習したことについて書いている日記みたいなものです。

Nuxt.js 2.x + TypeScript 4.x その0006 アプリケーションのsrcを一階層深いところに格納する(srcDirの設定を変更する)

参考にさせていただいたページ

Nuxtのaliasプロパティについて

NuxtのrootDirについて

NuxtのsrcDirについて

TypeScriptのimportパスの解決について

tsconfig.json がプロジェクトのルート直下にない場合にtsconfig.jsonをextendする

今日の開発環境

  • Nuxt 2.14.12
  • TypeScript 4.2.3

appディレクトリを作成してsrcを格納する

公式ドキュメントでは「The srcDir Property - NuxtJS」のように、clientというディレクトリを作成して、その中に以下のディレクトリを移動させています。

  • assets/
  • components/
  • layouts/
  • middleware/
  • pages/
  • plugins/
  • static/
  • store/

私はappというディレクトリを作成して、その中にこれらを移動しました。
設定ファイル、node_modulesディレクトリ、testディレクトリとsrcの階層を分けることで見やすくなったりgrepしやすくなると思います。

nuxt.config.jsのsrcDirの設定を変更する

srcをappディレクトリに移動したので、以下の行を追記してsrcDirの設定を変更します。

srcDir: 'app/',

srcDirの設定については「The srcDir Property - NuxtJS」を参照してください。

また、今回の変更には関係しませんが、rootDirの設定について「The rootDir Property - NuxtJS」の方も見ておくと良いと思います。

コンポーネントをimportするときにエラーが出た

エラーの概要

以下のようにチルダを使ってimportしたときに

import myComponent from '~/path/to/my/component/index.vue'

以下のようなエラーが出ました。

TS2307: Cannot find module '~/path/to/your/component/index.vue' or its corresponding type declarations.

nuxt.config.jsの設定は変更していましたが、tsconfig.jsonの設定では違う場所を参照していることによるものです。

エラーの解決策

一つ目の解決策(相対パスでインポートする)

一つ目の解決策として相対パスでインポートする方法があります。
この方法が無難だと思います。

要は ~/ ではなく ../ を使用するということです。

TypeScript: Documentation - Module Resolution」には以下のように書いてあります。

A relative import is resolved relative to the importing file and cannot resolve to an ambient module declaration. You should use relative imports for your own modules that are guaranteed to maintain their relative location at runtime.

A non-relative import can be resolved relative to baseUrl, or through path mapping, which we’ll cover below. They can also resolve to ambient module declarations. Use non-relative paths when importing any of your external dependencies.

機械翻訳すると以下の通りでした。

相対インポートは、インポートファイルに関連して解決され、アンビエントモジュール宣言に解決できません。 実行時に相対位置を維持することが保証されている独自のモジュールには、相対インポートを使用する必要があります。

非相対インポートは、baseUrlに関連して、またはパスマッピングを介して解決できます。これについては以下で説明します。 また、アンビエントモジュール宣言に解決することもできます。 外部依存関係をインポートするときは、非相対パスを使用してください。

今回、私の場合は自分で作成した.vueファイルから、自分で作成した.vueファイルをimportしており、「実行時に相対位置を維持することが保証されている独自のモジュール」にあたるので、相対パスでインポートするのが無難そうではあります。

二つ目の解決策(tsconfig.jsonを編集する)

二つ目の解決策として、tsconfig.jsonのbaseUrlやpathsを編集する方法があります。

今回の例でいうと、tsconfig.jsonのpathsを以下のようにします。

    "paths": {
      "~/*": [
        "./app/*"
      ],
      "@/*": [
        "./*"
      ]
    },

これを行った場合に、後々どういう問題が起こりうるのか、それとも特に問題は起こらないのか今のところよく解ってないですが。

参考としてまず以下の記事と

そのリンク先である以下のissues

これらを読むと、TypeScriptのpathsはパスを解決しない。
パスの解決はTypeScriptの責務でなく、webpack.config.jsやnuxt.config.jsなどのaliasによって解決する。ということのようです。

なので今回の例でいうと、TypeScriptによってトランスパイルされたコードは~/のままであり、それはNuxt.jsによって適切なパスに置き換えられる。ということらしいですね。

おまけ

tsconfig.json がプロジェクトのルート直下にない場合にtsconfig.jsonをextendする

tsconfig.jsonをextendすることもできるらしいです。 - 【Cannot find module ... or its corresponding type declarations.】 tsconfig.json がプロジェクトのルート直下にない場合 - Qiita

Nuxt.js 2.x + TypeScript 4.x その0004 FontAwesomeの必要なアイコンだけ読み込んで使う

参考にさせていただいたページ

今日の開発環境

  • Nuxt 2.14.12
  • TypeScript 4.2.3

パッケージをインストールする

パッケージを4つインストールします。

yarn add nuxt-fontawesome @fortawesome/free-solid-svg-icons @fortawesome/fontawesome-svg-core @fortawesome/vue-fontawesome

nuxt.config.jsの編集

Freeに含まれている以下の2つのアイコンを例に説明します。

例えばfaSearchとfaSearchPlusの2つを使用したい場合は、nuxt.config.jsのmodulesの項目を以下のような感じに編集します。

  modules: [
    〜略〜
    [
      'nuxt-fontawesome',
      {
        component: 'fa',
        imports: [
          {
            set: '@fortawesome/free-solid-svg-icons',
            icons: ['faSearch', 'faSearchPlus'],
          },
        ],
      },
    ],
  ],

コンポーネントファイルの編集

先ほどnuxt.config.jsで列挙したアイコンを、使用したいコンポーネント内で以下のようにimportします。

import { faSearch, faSearchPlus } from '@fortawesome/free-solid-svg-icons'

importしたアイコンは以下のようにcomputedでreturnします。

  computed: {
    faSearch() {
      return faSearch
    },
    faSearchPlus() {
      return faSearchPlus
    },
  },

以下のようにpropsに渡すと表示されます。

<fa :icon="faSearch" />
<fa :icon="faSearchPlus" />

Gitのglobal設定で.DS_Storeを無視する

参考にさせていただいたページ

目的

リポジトリ毎に.DS_Storeを.gitignoreに書かなくても良いようにglobalに設定します。

手順

.gitignore_globalを作成して、.DS_Storeと記述します。

echo .DS_Store > ~/.gitignore_global

設定します。

git config --global core.excludesfile ~/.gitignore_global

Nuxt.js 2.x + TypeScript 4.x その0003 Sassを使えるようにする

参考にさせていただいたページ

公式ページ

その他のページ

今日の開発環境

  • Nuxt 2.14.12
  • TypeScript 4.2.3

パッケージのインストール

公式ページに倣って以下の通りインストールしました。 sass-loaderはv10を指定しています。

npm install --save-dev sass sass-loader@10 fibers

このとき、sass-loader v11 など最新バージョンををインストールすると以下のようなエラーが出るかもしれません。

Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
TypeError: this.getOptions is not a function

この記事はあくまでも2021年3月19日時点での情報なので、公式ページを見ていただくのが良いと思います。

vueファイルの記述について

langを指定します。scopedもだいたいみなさん付与すると思います。

<style lang="scss" scoped>

VeeValidateでcheckboxのfalseを許容しない場合のrules

checkboxでfalseを許容しない場合のrules

falseでも値があればバリデーションが通ってしまうっぽいので、ValidationProviderに以下のような感じでオブジェクトを渡すと良いかも。

rules="{ required: { allowFalse: false } }"

例えば以下のようになる。

<ValidationProvider v-slot="{ errors }" rules="{ required: { allowFalse: false } }">
  〜略〜
</ValidationProvider>

その他の方法

上の方法でうまくいかなかったら、もう自分でバリデーションルールを定義して厳密に value === true みたいに比較するとよさそう。

GoogleTagManager(GTM) その0002 dataLayer.push()を使用して計測をする

参考にさせていただいたページ

dataLayer.push()を使用して計測をする

プレビューモードの使い方

前の記事

前提

まず前の記事でやったことのうち、以下の2つは完了しているものとします。

  1. アカウントの作成をします。Googleのアカウントがあれば、「Google アナリティクス」にアクセスしてすぐアカウント作成ができます。
  2. インストールします。計測したいページのHTMLにscriptタグとnoscriptタグをコピペして、サーバーにアップロードします。

dataLayer.pushを使えるようにするまで

Google Tag Manger から Google Analytics にカスタムイベントを送る方法 - Qiita」を参考にさせていただきながら進めていきます。

1. GTMのユーザー定義変数を定義します。複数のタグ設定で使い回すときに便利なので、ANALYTICS_TRACKING_IDという定数を定義して値はUA-から始まるGoogle AnalyticsのIDを入れます。今回の作業に必要な変数としてeventCategory、eventAction、eventLabel、eventValueというデータレイヤーの変数を定義します。ユーザー定義変数は以下の画像のようにしました。 f:id:motomichi_works:20210305213129p:plain

2. トリガーを設定します。トリガーの種類は「カスタムイベント」を設定します。他の項目も以下の画像のように設定しました。 f:id:motomichi_works:20210305213245p:plain

3. タグの設定をします。タグの種類は「Google アナリティクス: ユニバーサル アナリティクス」を設定します。先ほど定義したデータレイヤーの変数を使用します。配信トリガーは手順「2」で作成したカスタムイベントを設定します。 f:id:motomichi_works:20210305213349p:plain

4. 一旦公開します。

5. headタグ内に以下のscriptを書いて、サーバーにアップロードします。サンプルとしてページ描画時に一度だけ実行されるようにしておきます。ここで送信する event: 'ga_event' の値はトリガーで設定したものと等しい文字列にする必要があります。

  <script>
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event: 'ga_event',
      eventCategory: 'sampleCategory',
      eventAction: 'sampleAction',
      eventLabel: 'sampleLabel',
      eventValue: 0,
    });
  </script>

6. 「新しいGTMプレビューモードの使い方」を参考にプレビューします。もしプレビューが上手くいかない場合も、引き続き同じページを参考にトラブルシューティングをします。

7. 動作確認ができたら、プレビューを終了して、最新の設定で公開します。

8. 数分後にGoogle Analyticsの「リアルタイム > イベント」のページで「(直前の 30 分間)」をクリックするとイベント数がカウントされていることが確認できると思います。

実装について

サンプルはページ描画時にdataLayer.push()を実行していますが、リンクをクリックしたときに実行すればクリックの計測も行えます。

GoogleTagManager(GTM) その0001 導入とクリックイベントの計測

参考にさせていただいたページ

公式ページ

クリックイベントの計測を始めるための設定

プレビューモードの使い方

クリックイベントの計測ができるようになるまで

1. まずアカウントの作成をします。Googleのアカウントがあれば、「Google Analytics」にアクセスして、すぐアカウント作成ができます。

2. 「Google タグ マネージャーをインストール」のページにあるscriptタグとnoscriptタグを計測したいページのHTMLにコピペして、サーバーにアップロードします。コピペするコードスニペットは「https://tagmanager.google.com/#/home」から設定ページへ遷移すると確認できると思います。

3. 「Googleタグマネージャーでクリックイベントを計測する方法 - ランディングページ制作・改善」を参考にトリガーを新規作成します。トリガーのタイプは「クリック・リンクのみ」を選択して、このトリガーの発生場所ラジオボタンは「一部のリンククリック」を選択して、適当に「Page Hostnameが等しい」とかで条件を指定しました。条件はなんでも良いのでご自身の環境に合うものを設定してください。

4. 引き続き同じページを参考にタグを新規作成して、タグの設定と配信トリガーの選択をします。タグの種類は「Google アナリティクス: ユニバーサル アナリティクス」を選択します。トラッキングタイプは「イベント」を選択します。カテゴリ、アクション、ラベル、値は適当に自分が分析に使用したい変数などを指定します。以下の画像で{{ANALYTICS_TRACKING_ID}}となっている箇所はユーザー定義の定数を使用していますが、定数を使わなくてもUA-から始まるGoogle AnalyticsのIDを普通に入れれば大丈夫です。

5. 一旦公開します。

6. 「新しいGTMプレビューモードの使い方 | アユダンテ株式会社」を参考にプレビューします。もしプレビューが上手くいかない場合も、引き続き同じページを参考にトラブルシューティングをします。

7. プレビューを終了して、最新の設定で公開します。

8. サイトにアクセスして色々クリックします。

9. 数分後にGoogle Analyticsの「リアルタイム > イベント」のページで「(直前の 30 分間)」をクリックするとイベント数がカウントされていることが確認できると思います。手順「4」で設定したカテゴリ、アクション、ラベルごとに絞り込んでイベント数を確認したりできます。

これでどのリンクが何回クリックされたかが計測できるようになりました。