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