🐈

Nuxt.js プロジェクト(2系)に後から部分的に TypeScript を導入する方法

2023/07/07に公開

こんにちは、AIQ株式会社のフロントエンドエンジニアのまさぴょんです!

普段は、Outputは個人ブログでしていますが、Book機能などもあるZennでの情報発信に興味があったので、こちらでも執筆してみます。
https://masanyon.com/

Nuxt公式のTypeScript導入DocのとおりにやってもErrorになる・・・

タイトルのとおり、Nuxt.js プロジェクト(2系)に後から部分的にTypeScriptを導入する必要が、現在commitしている プロジェクトにて発生しました。
導入の際に、Nuxt公式のTypeScript導入Docのとおりにやっても Errorになってしまうので、、、
その対応も含めたNuxt.js プロジェクト(2系)に後から部分的に TypeScript を導入する方法を説明していきます。
https://typescript.nuxtjs.org/ja/

今回の TypeScript導入の経緯と、導入の要件定義

元々は、誰もが知る某大手ベンダーが作成したNuxtプロジェクトだったのですが、
そこから私の所属する会社が引き継ぎ、プロジェクトの新機能開発やデザインのバージョンアップなど大規模な改修を担当することとなりました。

外から見ると、ある程度ちゃんと動作するプロジェクトですが、中身を見てみると、VuexのState管理がルール無視の状態で、localhostで平気で、
vuex do not mutate vuex store state outside mutation エラー が発生するような状況だったり、
Bugをまあまあ内包していたり、ViewとLogicが密に結合していたりと、中身は引き継ぎ時点から、ヤバい状態でした。
https://masanyon.com/vue-vuex-do-not-mutate-vuex-store-state-outside-mutation-error-resolve/

そこで、このままJSベースでやっていくよりかは、この大規模に改修しているこのタイミングで、TypeScriptを導入したり、State管理を見直すことになった、というのが、ことの経緯になります。

TypeScript導入の経緯の説明が長くなってしまいましたが、今回のTypeScript導入の要件定義をまとめると、次のとおりです。

  1. JSベースで作成してきた Nuxt.jsプロジェクト(2系)に、後からTypeScript を導入する。

  2. 全体ではなく、改修するComponentやJSファイルなど部分的に適用するようにしたい。

環境情報

  1. Nuxt.js: v2.15.8
  2. Node: v16.15.1

Nuxt公式Doc: Nuxt 2 向け TypeScript サポートを実践する

ここからは、Nuxt Org の Nuxt・TypeScript イントロダクション を参考に、Nuxt・TypeScript 環境をセットアップしていきます。
(この先に、悲劇が待っているとは、知らず。。。)

Nuxt・TypeScript のための 3 つの Package

Nuxt の TypeScript サポートは 3 つのパッケージからなっています。

  1. @nuxt/types

    • Nuxt TypeScript の型定義が含まれています。
  2. @nuxt/typescript-build

    • layouts、components、plugins および middlewares で TypeScript を使用するための Nuxt モジュールです。
  3. @nuxt/typescript-runtime

    • nuxt.config ファイル、ローカルの modules および serverMiddlewares で TypeScript ランタイムサポートを提供する Nuxt の Wrapperバイナリ。

これらのパッケージは Nuxt 2.10 またはそれ以上のバージョンで使用されることを想定しています。

Nuxtプロジェクトに追加でTypeScriptを導入する

  1. 次のコマンドで、install を実行する
yarn add --dev @nuxt/typescript-build @nuxt/types
  1. TypeScript を設定する

    • 必要なことは、nuxt.config.ts 内の buildModules@nuxt/typescript-build を追加することです。
nuxt.config.ts
import type { NuxtConfig } from '@nuxt/types'

const config: NuxtConfig = {
  buildModules: ['@nuxt/typescript-build']
}

export default config
  1. tsconfig.json ファイルを作成する
tsconfig.json
{
  "compilerOptions": {
    "target": "ES2018",
    "module": "ESNext",
    "moduleResolution": "Node",
    "lib": ["ESNext", "ESNext.AsyncIterable", "DOM"],
    "esModuleInterop": true,
    "allowJs": true,
    "sourceMap": true,
    "strict": true,
    "noEmit": true,
    "baseUrl": ".",
    "paths": {
      "~/*": ["./*"],
      "@/*": ["./*"]
    },
    "types": ["@nuxt/types", "@nuxt/typescript-build", "@types/node"]
  },
  "exclude": ["node_modules"]
}

現時点では ESNext が Optional Chaining と Nullish Coalescing をサポートしていないようです。これらの機能を使えるようにするためにターゲットに ES2018 を指定する必要があることに注意してください。

  1. vue-shim.d.ts に次の型宣言を追加し Vue ファイルの型を提供する必要があります。
vue-shim.d.ts
declare module "*.vue" {
  import Vue from 'vue'
  export default Vue
}

このファイルはプロジェクトのルートディレクトリか types という名前のディレクトリに配置できます。カスタムディレクトリにも配置できますが、その場合は tsconfig.json ファイルに typeRoots を設定する必要があります。

これで layouts、components、plugins と middlewares で TypeScript が使えるように設定できました。

とのことですが、Errorが発生。。。

Nuxt公式Docには、記載のないTypeScript導入手順

ここからは、Nuxt公式Docには、記載のなかったError対応も含めたTypeScript導入手順です。

ERROR Cannot find module 'typescript'が発生

上記までのマニュアル通りの作業で、ERROR Cannot find module 'typescript'が発生。

typescript Moduleが見つからないというErrorなので、

yarn add -D typescript

を実行して解決する。

require() of ES Module xxxxx dynamic import() which is available in all commonjs modules エラー

続いて、CommonJS のモジュールから ESM を 読み込もうとしているため Error 発生

require() of ES Module xxxxx dynamic import() which is available in all commonjs modules エラー

require()で ES Modules を使用しようとしているために発生するエラーになります。

https://masanyon.com/javascript-node-npm-commonjs-es-modules-require-of-es-module-dynamic-import-which-is-available-in-all-commonjs-modules-error-resolve/

最初に作成したtsconfig.json ファイルの"module": "commonjs"を修正しましたが、効果なし。。。

tsconfig.json
{
  "compilerOptions": {
    "target": "ES2018",
    "module": "commonjs",
    "moduleResolution": "Node",
    "lib": ["ESNext", "ESNext.AsyncIterable", "DOM"],
    "esModuleInterop": true,
    "allowJs": true,
    "sourceMap": true,
    "strict": true,
    "noEmit": true,
    "baseUrl": ".",
    "paths": {
      "~/*": ["./*"],
      "@/*": ["./*"]
    },
    "types": ["@nuxt/types", "@nuxt/typescript-build", "@types/node"]
  },
  "exclude": ["node_modules"]
}

さらに、調べてみると、これは、Nuxt・Vue内部のPackage内で発生している 互換性Errorだったので。。。

yarn add -D @nuxt/typescript
yarn add ts-node
yarn add -D vue-property-decorator

上記の3つのPackageを追加することで、Errorは解決しました。

これで、Nuxt公式Docにも記載のないTypeScript導入手順は、完了しました。

各ファイルをTypeScript化していきます。

  1. 各JSファイルをTSファイルに変更していきます。

  2. Vueファイル(VueのComponentファイル)をTypeScript化していきます。

    • VueのComponentファイルに TypeScriptを導入する方法は、いくつかありますが、今回は、Vue.extendの方法で、TypeScriptを導入していきます。
    1. scriptタグにlang="ts"を追加する。
    2. import Vue from 'vue'を追加する。
    3. Vue.extend()export default{}を Wrapする。
Robotama.vue

<script lang="ts">
  import Vue from 'vue'
  export default Vue.extend({
    name: 'Robotama',
    components: {},
    data() {
      return {
        robotama: true,
      }
    },
  })
</script>
  1. Projectで使用する型定義を追加します。

    • .tsファイルに必要な型定義を追加します。

    • これにより、IDEが正しい型チェックや補完を提供できるようになります。

    • プロジェクトの要件に応じて、必要な型定義を手動で作成するか、既存の型定義をインストールすることができます。

    • たとえば、Vue.jsの型定義を追加するには、次のコマンドを実行します。

yarn add -D @types/vue

番外編: WebPack を拡張して、TypeScript 導入する方法もある

・ Nuxt の Package を使用して、TypeScript を導入することができない場合は、WebPackを拡張して、TypeScript導入する方法もあるようです。

・今回は、NuxtのPackageで、何とかなったので、その手段は使用せずに済みました。

参考・引用

  1. Nuxt・TypeScript イントロダクション

  2. Error: Cannot find module 'typescript'

  3. NuxtにThree.jsを導入する

  4. CommonJS と ES Modules の違いとは?互換性や require() と import文 の違いについて

  5. CommonJS と ES Modules についてまとめる

  6. TypeScript の ESM でハマる

  7. TypeScript 4.7 と Native Node.js ESM

  8. Vite だと require() が使えないよ〜

  9. Node.js: require()は同期型ロード、import は非同期型ロード

  10. 【Nuxt.js】プロジェクトに後から自前で TypeScript を導入する方法【yarn でサクッと簡単】

  11. Nuxt.js に TypeScript を導入する手順まとめ

  12. [Vue+TypeScript] Vue.extend で Vue らしさを保ちつつ TypeScript で書くときの型宣言についてまとめた

注意事項

この記事は、AIQ 株式会社の社員による個人の見解であり、所属する組織の公式見解ではありません。

求む、冒険者!

AIQ株式会社では、一緒に働いてくれるエンジニアを絶賛、募集しております🐱🐹✨

エンジニア視点での我が社のおすすめポイント

  1. フルリモート・フルフレックスの働きやすい環境!
    • 前の会社でアサインしてた現場は、フル出社だったので、ありがたすぎる。。。
    • もうフル出社には、戻れなくなります!
  2. 経験豊富なエンジニアの先輩方
    • 私は、3年目の駆け出しエンジニアなので、これが、かなりありがたいです!
  3. 自社開発とR&D(受託開発)を両方している会社なので、経験できる技術が多い。
    • 自社のProduct開発と、他社からの受託案件で、いろいろな技術を学ぶことができます。
  4. AI関連の最新の技術に触れられるチャンスが多い。
    • 自社で特許を持つほど、AI技術に強い会社で、プロファイリングを得意とした技術体系があります。
    • ChatGPTを自社アプリに搭載など、AIトレンドも、もちろん追っており、最新の技術に触れられるチャンスが多いです。
  5. たまに、札幌ラボ(東京から札幌) or 東京オフィス(札幌から東京)に出張で行ける!
    • 東京と、札幌に2拠点ある会社なので、会合などで集まる際に、出張で行けます。

採用技術 (一部抜粋)

  • FrontEnd: TypeScript, JavaScript, React.js, Vue.js, Next.js, Nuxt.js など
  • BackEnd: Node.js, Express,Python など
  • その他技術: Docker, AWS, Git, GitHub など

エントリー方法

  1. 私達と東京か札幌で一緒に働ける仲間を募集しています。
    詳しくは、Wantedly (https://www.wantedly.com/companies/aiqlab)を見てみてください。

Webエンジニア向け説明

https://www.wantedly.com/projects/1089410

データサイエンティスト向け説明

https://www.wantedly.com/projects/1089406

人事に直通(?)・ご紹介Plan(リファラル採用)

私経由で、ご紹介もできますので、興味のある方や気軽にどんな会社なのか知りたい方は、X(旧:Twitter)にて、DMを送ってくれても大丈夫です。
https://twitter.com/masanyon1212

AIQ Tech Blog (有志)

Discussion