importのエイリアスとソートを設定する
Reactではimport文を多用します。これは機能ごとにファイルを分けているため、メンテンナスしやすいコードを書いている証拠です。しかし、インポート自体はごちゃこちゃしてメンテナンスしづらいのも事実です。特に以下のケースが考えられます。
⚡ネスト地獄
インポートするコンポーネントの階層構造が深いと、メンテナンスが悪くなります。例えば、ファイルの物理的な位置を変更した場合に手直しが必要になります。
// ネストが深い
import someComponent from "../../../../components/someComponent";
// ファイルの位置を1つ上に移動すると手直しが必要になる
import someComponent from "../../../components/someComponent";
// こうなれば楽なのに...
import someComponent from "~components/someComponent"
⚡ファイルごとにインポートの順番がバラバラ
自分の中でインポート順序を決めることはありますが、強制力はないため即破綻してしまいます。順番がバラバラでもコードは動きますが、コードの保守性を考えると無視できない問題でもあります。以下のように、グループ化できると便利です。
// グループ1: Reactのパッケージ
import React from "react";
// グループ2: 外部ライブラリ
import { View, Text } from "react-native";
import { useDispatch, useSelector } from "react-redux";
// グループ3: 内部コンポーネントやユーティリティ
import { HeaderIcon } from "~components/header/HeaderMenuIcon";
import WrapContainer from "~components/layout/WrapContainer";
import ImageModalView from "~components/modal/ImageModalView";
この記事では、React Nativeにおける上記2つのソリューションを記載します。
インポートエイリアス
インポート時のエイリアスの設定を行っていきます。ここでは以下のようなディレクトリ構造を想定しています。
root/
┣ index.js
┣ assets/
┃ ┗ image.jpg
┗ src/
┣ components/
┣ api/
┣ hooks/
┗ App.js
assets/
にはアセットファイル、src/
にはすべてのソースコードが含まれています。後者は配下にいくつかの子ディレクトリが存在するものとします。今回はこの2つのディレクトリのエイリアスを設定します。
Expoの場合
Expoマネージドワークフローの場合、App.js
はルート直下にあるため、上記のディレクトリ構造にするには、app.json
にentryPoint: "./src/App.js"
を記述する必要があります。EASの場合はindex.js
を以下のようにします。また、Expoマネージドワークフローから移行する場合は、前述のentryPoint
を削除する必要があります。
// index.js
import { registerRootComponent } from "expo";
import App from "./src/App";
registerRootComponent(App);
💡上記は2021年12月時点の設定方法です。近々、カスタムルートの設定方法が追加されるそうです。
エイリアスの指定
エイリアスは指定ディレクトリ階層までのパスを省略することができます。例えば、src/components/api
までの階層を~components/api
と記述できます。この場合のエイリアスのプレフィックスは~
です。どのような階層からでも、~components/api
と記述できるので、ファイルの物理的な位置が変わってもインポート文のfrom "..."
を変更する必要はなくなります。
// これが
import someComponent from "../../../../components/someComponent";
// こうなる
import someComponent from "~components/someComponent"
それでは、必要なパッケージをインストールします。
yarn add --dev babel-plugin-module-resolver
そして、babel.config.js
に設定を追加します。
module.exports = function (api) {
// ...
return {
presets: ["babel-preset-expo"],
plugins: [
[
"module-resolver",
{
root: ["./"],
alias: {
"^~(.+)": "./src/\\1",
"@assets": "./assets",
},
extensions: [
".js",
".jsx",
".ts",
".tsx",
".android.js",
".android.tsx",
".ios.js",
".ios.tsx",
],
},
],
],
};
};
root
で基準となるディレクトリを指定し、alias
でエイリアスを設定します。ここではsrc
とassets
ディレクトリのエイリアスを設定しています。src/
配下は子ディレクトリが存在するため、それらに合わせるように正規表現を使用する必要があります。assets
は直下にはディレクトリがないので、@assets
という単純なエイリアスを指定しています。
これでインポートのエイリアスは動作します。
VSCode
VSCodeを利用している場合は、エイリアスをオートコンプリートさせることができます。
jsconfig.json
でpaths
に以下のような設定を記述します。
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~*": ["src/*"],
"@assets": ["./assets"]
}
},
"exclude": ["node_modules"]
}
これでimport
のオートコンプリート時にエイリアスが候補に入るようになります。
インポート文の順序
次にインポート文の記載順序という問題に移ります。これはESLintを使用します。
以下をインストールします。
# eslintが未導入の場合は、eslintもインストールする必要があります
yarn add --dev eslint-plugin-import
eslintrc.js
に以下を記述します。
module.exports = {
//...
extends: [
"eslint:recommended",
"plugin:import/recommended",
],
rules: {
"import/no-unresolved": "off",
"import/named": "warn",
"import/namespace": "warn",
"import/no-named-as-default": "off",
"import/export": "warn",
"import/order": [
"error",
{
// グループの定義、尊重する順番
groups: [
"builtin",
"external",
"internal",
"parent",
"sibling",
"index",
],
// インポートグループ間の新しいラインを強制または禁止します
"newlines-between": "always",
// 各グループはアルファベット順でソートされます
alphabetize: {
order: "asc",
caseInsensitive: true,
},
// パスグループ
pathGroups: [
{
pattern: "react",
group: "external",
position: "before",
},
],
// pathGroupsでは扱われないインポートタイプを定義
pathGroupsExcludedImportTypes: ["builtin"],
},
],
},
settings: {
"import/ignore": ["react-native"],
},
};
簡易なコメントは入れてありますが、ソートのオプションの詳細はこちらで確認できます。
これで一般的なLint同様、順序がおかしいと警告が表示されます。Prettierを導入してあれば、保存時にインポート文の自動補正も行われます。以下はVSCodeでの動作画面になります。
認知負荷を軽減するだけでなく、ファイルのスキャンも高速化されるそうです。