🐱
ESLintを使ってモジュール間のimportを制限する
モジュラモノリス的な構成でプロジェクトを作成していると、別モジュールからの import を制限したくなります。
具体的には以下のような要件です。
- modules/post からは modules/user のファイルを import できなくしたい
- 同様に、modules/userからは modules/post のファイルを import できなくしたい
- ただし、同一モジュール間では import の制限をしたくない
root/
└ src/
├ share/
│ └ components/**/* 共通コンポーネント
└ modules/
├ user
│ └ components/
│ ├ UserProfile.tsx
│ └ User.tsx
└ post
└ components/
└ Post.tsx
./src/modules/post/components/Post.tsx
// ./src/modules/user/components/Userからimport
import User from '@/modules/user/components/User' // エラーになってくれ!
const Post: React.FC = () => {
return <div>post</div>;
};
export default Post;
eslint-plugin-importの設定
下記のライブラリをインストールします
yarn add -D eslint-plugin-import eslint-import-resolver-typescript
eslint で使用する設定を記載します。
ひとまず、./modules/postを他moduleからimportできないように制限します。
zonesに記載していきます。
eslintrc.js
module.exports = {
extends: [
"next/core-web-vitals", // NextJSのESLintの設定
"plugin:import/recommended",
"plugin:import/typescript",
],
settings: {
"import/resolver": {
typescript: {},
},
},
rules: {
"import/no-restricted-paths": [
"error",
{
zones: [
{
from: `./src/modules/post/!(public)/**/*`,
target: `./src/modules/!(post)/**/*`
}
]
},
],
}
}
fromは、制限するimport元、targetはimportの制限を適用するファイルです。
- このパターンだと、「./src/modules/post」ディレクトリにあるファイルは、「./src/modules/post」以下のディレクトリからしかimportできなくなります
(同一のモジュール間でしかimportできなくなります) - ただし、「./src/modules/post/public」にあるファイルは、他モジュールからimportをできるようにしています。
モジュールのパスを取得してルールを自動生成する
同様にuserのモジュールのimportも制限していきたいのですが、モジュールが増えるたびにeslintの設定を追加していくのは面倒です。
そこで、ディレクトリ一覧を取得してzoneに記載する項目を自動生成するようにします。
具体的には、下記のようにします
const fs = require('fs');
const modules = fs.readdirSync('./src/modules'); // ./src/modulesのディレクトリ一覧を取得
const zones = modules.map(module => ({
from: `./src/modules/${module}/!(public)/**/*`,
target: `./src/modules/!(${module})/**/*`
})); // 配列でディレクトリの名前が帰ってくるのでそれを元にeslintの設定を作成
あとはこちらをimport/no-restricted-pathsのzonesに渡せばOKです。
eslintrc.js
const fs = require('fs');
const modules = fs.readdirSync('./src/modules');
const zones = modules.map(module => ({
from: `./src/modules/${module}/!(public)/**/*`,
target: `./src/modules/!(${module})/**/*`
}));
module.exports = {
extends: [
"next/core-web-vitals",
"plugin:import/recommended",
"plugin:import/typescript",
],
settings: {
"import/resolver": {
typescript: {},
},
},
rules: {
"import/no-restricted-paths": [
"error",
{
zones,
},
],
}
}
これでモジュール間のimportを制限することができるようになりました。
以上!
Discussion