GameWith Developer Blog

GameWith のエンジニア、デザイナーが技術について日々発信していきます。

モジュールをオンデマンド自動インポートする仕組みを導入しました #GameWith #TechWith #typescript

こんにちは! @53able です。

今回は、VueCLI プロジェクトにおいてモジュールのオンデマンド自動インポートの仕組みを導入したお話をしていきたいと思います。

概要

TypeScript コード上で一部の import 文が省略できるようになります。

開発環境

プロダクションコードは src ディレクトリ配下にあり、src/*.d.ts の型定義が適用されているようになっております。

プロジェクトルート
├ src
│ └ auto-imports.d.ts
├ .eslintrc-auto-import.json
├ .eslintrc.js
├ jest.setup.js
└ vue.config.js

依存モジュールのバージョンは以下の通りです。

  • VueCLI v5.0.8
  • Vue v2.7.10
  • VueUse v9.2.0
  • Jest v27.5.1
  • ESLint v8.23.0
  • unplugin-auto-import v0.11.2
  • TypeScript v4.8.2
  • NodeJS v16.14.2
  • PNPM v7.9.3

課題

SFC の <script lang="ts"> ブロックや、 .ts ファイルに同じような import 文を長々しく書くことが煩雑でした。

VSCode などの先進的なエディタを用いれば import 文の自動挿入が可能ですが、やはり省略できるようであればそれに越したことはありません。

また、コードの簡潔化が実現できればコード差分をより小さくし、コードレビューの負担を少しでも軽減できるのではないかと思いました。

解決策

unplugin-auto-import を用いて import 文を省略できることが分かったので導入します。

github.com

あらかじめ import 文が省略可能なモジュールを設定し、コード上でモジュールが利用されている場合に自動インポートが行われます。

インストール

$ pnpm add -D unplugin-auto-import

設定

unplugin-auto-import の README に、VueCLIプロジェクト向けの設定サンプルが記載されています。

// vue.config.js
module.exports = {
  configureWebpack: {
    plugins: [
      require('unplugin-auto-import/webpack')({ /* options */ }),
    ],
  },
}

/* options */ の部分に設定を追加していきます。

options 設定

今回設定した options は以下の通りです。

{
    /* options */
    include: [
      /\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
      /\.vue$/,
      /\.vue\?vue/, // .vue
    ],
    imports: [
      "vue",
      "@vueuse/core",
      {
           // 個別のモジュール
      },
    ],
    dts: "src/auto-imports.d.ts",
    dirs: ["src"],
    vueTemplate: true,
    eslintrc: {
      enabled: true, // Default `false`
      filepath: "./.eslintrc-auto-import.json", // Default `./.eslintrc-auto-import.json`
      globalsPropValue: true, // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable')
    },
}

import 文省略対象のファイルパターン指定

.vue, .ts, .tsx, .js, .jsx を対象となるように正規表現でファイル名のパターンを指定します。

include: [
  /\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
  /\.vue$/, /\.vue\?vue/, // .vue
],

import 文省略対応モジュール指定

unplugin-auto-import が定義しているプリセットか、自作のモジュールも指定可能です。

プリセット

本プロジェクトは、Vue2.7@vueuse/core に依存しているので、プリセットから vue@vueuse/core を採用しました。

これらのプリセットを設定すると、import { } from "vue"; , imort { } from "@vueuse/core"; を多く省略できるようになります。

imports: [
  "vue",
  "@vueuse/core",
  {
     // 個別のモジュール
  },
],

⚠️: プリセットには、モジュール名がパスカルケースの型定義は含まれていないです。それらは、 import 文を省略することは出来ません。また、 imort { get } from "@vueuse/core"; など普遍的なモジュール名の省略は避けているようです。

個別モジュール

個別モジュールの指定に関しては、以下のように指定します。

import { モジュール名 } from "パス"; を省略指定する場合には、以下の通りになります。

{
 "パス": ["モジュール名"],
},

モジュール名の指定は配列形式になっているので複数モジュールが指定可能です。

TypeScript でのコード補完を有効にするための dts 出力

import 文省略モジュールに関してコード補完が効くようにするため型定義ファイル auto-imports.d.ts を出力します。

auto-imports.d.ts は、 vue-cli-service serve 実行時に出力されます。

dts: "src/auto-imports.d.ts",

自動インポート対応ディレクトリ指定

dirs: ["src"],

Vue テンプレートでの自動インポートフラグ

SFC の <script> 内で自動インポートを有効にするフラグです

vueTemplate: true,

ESLint ルール設定ファイル出力

import 文を省略したことにより、ESLint の no-undef エラーが検出されるようになってしまいます。

import 文省略モジュールに関してはグローバルスコープで定義済みと解釈されるように ESLint ルール .eslintrc-auto-import.json を出力します。

.eslintrc-auto-import.json は、 vue-cli-service serve 実行時に出力されます。

eslintrc: {
  enabled: true, // Default `false`
  filepath: "./.eslintrc-auto-import.json", // Default `./.eslintrc-auto-import.json`
  globalsPropValue: true, // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable')
},

ESLint

.eslintrc.js に出力された .eslintrc-auto-import.json で定義されている ESLint ルールを組み込みます。

module.exports = {
  extends: [".eslintrc-auto-import"]
}

自動出力される auto-imports.d.ts は、ESLint の範囲から除外します。

module.exports = {
  ignorePatterns: [
    "src/auto-imports.d.ts"
  ]
}

Jest

本プロジェクトは、ユニットテストに Jest を採用しています。

unplugin-auto-import はwebpack プラグインなので、 Jest 実行時に import 文を省略したモジュールの参照が解決できません。

import 文省略の設定をしたモジュールをグローバルスコープで定義するため、jest.setup.js でモジュールをインポートします。

// プリセット
import * as Vue from "vue";
for (const key of Object.keys(Vue)) {
  global[key] = Vue[key];
}
import * as vueuseCore from "@vueuse/core";
for (const key of Object.keys(vueuseCore)) {
  global[key] = vueuseCore[key];
}

// 個別モジュール
import { モジュール名 } from "パス";
global.モジュール名 = モジュール名;

まとめ

unplugin-auto-import を使って import 文を省略できるようになり、コードが簡潔になりました。

本エントリーでは、unplugin-auto-import の README を見つつ、よりキャッチアップしやすい様に具体的な説明をさせていただきました。

impor 文省略を導入した場合に、ESLint を導入済みのプロジェクトでは no-undef の指摘がたくさん出てしまうのと、コード補完が不完全になることを避ける方法が用意されていることがポイントになります。

それらが実現させるために unplugin-auto-import には、auto-imports.d.ts.eslintrc-auto-import.json を出力させるオプションが備わっています。

また、Jest に関しては import 文省略コードの個別対応が必要なので、今後はコードの自動生成で対応できるようにしたいと考えています。

現時点では、指定したモジュールに関しては import 文の省略が完全に対応できているので、DX (開発体験)が向上したのではないでしょうか。