LoginSignup
2
2

eslint-plugin-import-accessを使ってみる

Last updated at Posted at 2024-05-23

概要

defaultImportability: 'package'のオプションで丸ごとpackage-privateにできます
このオプションがない場合だと@packageのつけ忘れによる誤exportが起こり得ますがそれを防いでくれます 👍
dependency-cruisereslint-plugin-strict-depenenciesとの使い分けを考え直す必要性を感じました

1. 背景 🖼️

TypeScirptではexport宣言した変数や関数は全てのファイルからimportできてしまいます。

これにpackage-privateの機能を組み合わせれば外部のディレクトリからimportを制限できたり、モジュール管理がしやすくなると思い調査しました。

この記事でeslint-plugin-import-accessについて触れてはいますが、使い込んでみたいと思い今回細かく調査します。

ESLint,typescript-eslintの設定はこちらで紹介していますのでご覧ください!
Eslintとtypescript-eslintを手動で設定してみる

こちらが紹介するライブラリの作者の方でこのライブラリについて記事も書かれています。

こちらが今回の一連の作業のリポジトリですので、確認用にお使いください

2. eslint-plugin-import-accessとは 🤔

ディレクトリ外のファイルからインポートすることを制限するESLintのプラグインです。

3. eslint-plugin-import-accessの設定 🚧

eslint-plugin-import-accessのインストール

npm i -D eslint-plugin-import-access

eslintの設定ファイルを修正

  • importAccessをimport
  • pluginとruleを追加
eslint.config.js
import typescriptEslintParser from "@typescript-eslint/parser";
import js from "@eslint/js";
import tseslint from 'typescript-eslint';
import importAccess from "eslint-plugin-import-access/flat-config";

export default [
    {languageOptions: {
        parser: typescriptEslintParser,
        parserOptions: {
          project: true,
          sourceType: "module",
        },
      }
    },
    js.configs.recommended,
    ...tseslint.configs.recommended,
    {
        plugins: {
          "import-access": importAccess,
        },
    },
   {
       rules: {
            "import-access/jsdoc": ["error"],
       }
   }
];

4. エラーになるか試す 🚨

以下のディレクトリ構成で検証します。

.
├── call.ts
├── eslint.config.js
├── node_modules
├── package-lock.json
├── package.json
├── sub
│   ├── call.ts
│   └── called.ts
└── tsconfig.json
sub/called.ts
/**
 * @package
 */
export const called = "called";
call.ts
import { called } from "sub/called";

image.png

エラーが表示されました!

5. TypeScript Language Service Pluginを有効にする 🧪

tsconfig.json
{
  "compilerOptions": {
    // ...
    "plugins": [
      // ...
      {
        "name": "eslint-plugin-import-access"
      }
    ]
  }
}

VSCodeのコマンドパレット(Ctrl+Shift+P または Cmd+Shift+P)を開き、「TypeScript: Select TypeScript Version」を選択し、「Use Workspace Version」を選びます。

image.png

これで、「Use Workspace Version」を選択します。

すると、先ほどのcall.tsでsubディレクトリのcalledをimportする分がサジェスチョンで表示されなくなりました。

image.png

ですが、クイックフィックスではimportできそうです 😅

image.png

image.png

5. defaultでpackage-privateにできるルール📦

こちらで紹介されていました。

rulesにdefaultImportability: 'package'を追加します。

eslint.config.js
{
       rules: {
            "import-access/jsdoc": ["error",
            {
              // defaultImportabilityをpackageに設定
              defaultImportability: 'package',
            }],
       }
   }

これをすると、デフォルトでexportされた宣言はpackage-privateになります。

sub/called.ts
export const called = "called";

image.png

@packageのつけ忘れによる誤exportを防げます👍

6. 紹介されていた「2種類の抜け穴」について 🫢

こちらのdocの設定を参考に進めます!

同じディレクトリ内のindex.tsから再exportすると他のディレクトリからもimport可能

sub/index.ts
import { called } from "./called";

export { called };
call.ts
import { called } from "sub/index";

inde.tsに名前を変えてみます。

sub/inde.ts
import { called } from "./called";

export { called };

image.png

デフォルトの設定だと名前はindexにする必要があるそうです。

必要であれば以下の対応をするとこの抜け穴はなくなります。
indexLoophole:trueオプションを追加します。

eslint.config.js
rules: {
            "import-access/jsdoc": ["error",{
              // defaultImportabilityをpackageに設定
              defaultImportability: 'package',
              indexLoophole: false
            }],
       }

image.png

importできなくなりました。

ディレクトリ名と同じファイルからはディレクトリの中の package エクスポートをインポートできる

eslint.config.js
rules: {
            "import-access/jsdoc": ["error",{
              // defaultImportabilityをpackageに設定
              defaultImportability: 'package',
              filenameLoophole:true
            }
            ],
       }
.
├── call.ts
├── eslint.config.js
├── node_modules
├── package-lock.json
├── package.json
├── sub
│   ├── call.ts
│   └── called.ts
├── sub.ts
└── tsconfig.json

image.png

sub.tsからsubディレクトリ内のcalledがimportできました。

これはtestの実装時に有効らしいです!

test/sub.test.ts
import { called } from "sub/called";

importできています。

↑弊社のテックブログで紹介されています!

7. default exportでもimportできない 👍

sub/defaultExport.ts
const exported = 1;
export default exported;

image.png

8. 最後に

  • defaultImportability: 'package'のオプションで丸ごとpackage-privateにできます
  • このオプションがない場合だと@packageのつけ忘れによる誤exportが起こり得ますがそれを防いでくれます 👍
  • dependency-cruisereslint-plugin-strict-depenenciesとの使い分けを考え直す必要性を感じました

参考 ✨

本記事を読んで頂き、ありがとうございました。
いいねいただけると記事執筆の励みになりますので、参考になったと思われた方は是非よろしくお願い致します🙏

他にも依存関係の管理に関する記事を書いています 💪

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2