React + Reduxアプリケーションプロジェクトのテンプレートを2020年版にアップデート ― その2: パスエイリアス設定
Mon, Apr 27, 2020
react redux frontend webpack eslint babel typescriptTable of Contents
2018年後半にスクラッチから作ったReactとReduxのプロジェクトテンプレートを2020年版として色々アップデートしている。
前回はライブラリのアップデートや差し替えをした。
今回はパスエイリアス設定をする。
モジュール解決
import React from 'react';
import Button from '@material-ui/core/Button';
import HogeButton from '../containers/HogeButton';
import Fonts from '../fonts';
こんな感じにモジュールのimportを書いたとき、webpackとかがモジュールの実際のパスを解決する処理をモジュール解決という。
基本的にモジュール解決はimportの仕方によって3通りある:
絶対パス
import App from '/home/kaitoy/react-redux-scaffold/src/views/App';
こんな感じでimportするモジュールを絶対パスで指定すると、そのままそれがロードされる。
相対パス
import OkButton from '../../form/OkButton';
こんな感じでimportするモジュールを相対パスで指定すると、importを書いたモジュールから見た相対パスとして解決される。
モジュールパス
import React from 'react';
こんな感じで、ドライブレターとか
/
とか.
で始まらないパスを書くと、それはモジュールパスとして解決される。 モジュールパスは、処理系にモジュールディレクトリとして指定されたディレクトリからのパスになる。 モジュールディレクトリは普通はnode_modules
。
パスエイリアス
プロジェクトディレクトリ内の自作モジュールをimportするとき、絶対パスでimportするのはプロジェクトディレクトリの可搬性が悪いしパスが長くなるのでダメ。
プロジェクトのソースディレクトリ辺りを(node_modules
に加えて)モジュールディレクトリに指定しておいて、モジュールパスで
importするのも、node_modules
のnpmパッケージと見分けがつきにくいし、名前がコンフリクトする可能性もなくはないので微妙。
ということで以前のプロジェクトテンプレートでは相対パスでimportしていたけど、../
がたくさん要ったりして書きにくいし読みにくいし、モジュールの移動をするときに書き換えが面倒。
これら3通りのimport方法の欠点をすべて解消するのがパスエイリアス。 モジュールディレクトリに名前を付けて、そこからのパスでimportするモジュールを指定できるような感じ。
import App from '~/views/App';
この~
の部分がパスエイリアス。
プロジェクトテンプレートへのパスエイリアス設定
<プロジェクトルート>/src
に~
というパスエイリアスを設定したい。
プロジェクトテンプレートでモジュールの解決をする必要があるのは、バンドルファイルを生成するwebpack、TypeScriptのトランスパイラ、リンティングをするESLintと、Jestの実行時に使うBabel。
webpackへのパスエイリアス設定
webpackは標準でパスエイリアスをサポートしているので、設定に書き加えるだけ。
webpack.common.js
:
(snip)
resolve: {
extensions: ['*', '.ts', '.tsx', '.js', '.jsx'],
modules: ['node_modules'],
+ alias: {
+ '~': path.resolve(__dirname, 'src'),
+ },
},
(snip)
TypeScriptのパスエイリアス設定
TypeScriptにはPath mappingという機能があってパスエイリアスとして使える。
tsconfig.json
:
{
"compilerOptions": {
(snip)
- // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
- // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
+ "baseUrl": "./" /* Base directory to resolve non-absolute module names. */,
+ "paths": {
+ /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
+ "~/*": ["./src/*"]
+ },
(snip)
}
ESLintのパスエイリアス設定
ESLintは、eslint-import-resolver-webpackというプラグインを使うと、モジュール解決の設定をwebpackの設定から取得してくれる。
npm install -D eslint-import-resolver-webpack
.eslintrc.js
:
(snip)
overrides: [
{
files: ['**/*.ts', '**/*.tsx'],
rules: {
// Set 'no-unused-vars' to off to suppress errors on importing types.
// (e.g. error 'FunctionComponent' is defined but never used no-unused-vars)
// Unused vars are checked by TypeScript compiler (at-loader) instead.
'no-unused-vars': 'off',
'react/prop-types': 'off',
},
},
],
+ settings: {
+ 'import/resolver': {
+ webpack: { config: path.join(__dirname, 'webpack.prod.js') },
+ },
+ },
};
Babelのパスエイリアス設定
Babelはbabel-plugin-module-resolverを入れるとできる。
npm install -D babel-plugin-module-resolver
babel.config.js
:
module.exports = {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: 3,
},
],
'@babel/preset-react',
'@babel/preset-typescript',
],
- plugins: ["babel-plugin-styled-components", "@babel/plugin-syntax-dynamic-import"],
+ plugins: [
+ 'babel-plugin-styled-components',
+ '@babel/plugin-syntax-dynamic-import',
+ [
+ 'babel-plugin-module-resolver',
+ {
+ root: ['./'],
+ alias: { '~': './src' },
+ },
+ ]
+ ],
};
問題点
以上で一通り設定できているはずなんだけど、ユニットテストとか実装途中でまだ使ってないモジュールとか、index.tsx
から辿れない(?)やつでパスエイリアスを使うと、VSCode上でTypeScriptコンパイラがCannot find module
というエラーを表示してくるし、補完が利かない。
何か設定が足らない?