JavaScript や CSS で ~/ から始まるパスをマッピングして import する方法 2020
この記事では ~/
を任意のディレクトリにマッピングするための方法を解説します。
TL;DR
import util from '~/util';
のように ~/
から始まるパスにしたとき、 src
ディレクトリからの相対パスとしてマッピングするには、2020 年 12 月現在、次の方法があります。
- Parcel もしくは Nuxt.js を使う場合、設定しなくても自動でマッピングされます
- webpack を使う場合、
webpack.config.js
のresolve.alias
を設定します - Babel だけを使う場合、
babel-plugin-module-resolver
を使って設定します - tsc で型チェックする場合、もしくは Next.js を使う場合、
tsconfig.json
のpaths
を設定します
「~/ を任意のディレクトリにマッピングする」メリットとは
例えば、ディレクトリ階層が深いファイルから階層が浅いファイルを読み込む場合を考えてみます。
次のように、ディレクトリ階層が浅いファイルを読み込むには、相対パスで ../
を多く書く必要があります。
このとき、「対象のファイルがどこにあるのかわかりづらい」「違うディレクトリにあるファイルへのパスが長くなる」などの問題があります。
import HeroImage from '../HeroImage';
import util from '../../../../util';
問題を解決するために、任意のディレクトリを ~/
にマッピングすると、次のように書くことができます。
この記法の良い点は、「対象のファイルを探しやすい」「パスの表記がわかりやすくなる」などが挙げられます。
また、ディレクトリ階層は、対象のファイルの関心を表すことも多いので、「対象のファイルの関心が可視化されやすい」という利点もあります。
import HeroImage from '~/domains/home/components/HeroImage';
import util from '~/util';
VSCode
VSCode では、tsconfig.json
もしくは jsconfig.json
の設定によって、パスをマッピングできます。
また、設定の javascript.preferences.importModuleSpecifier
を non-relative
に設定すると、auto imports 時のパスを ~/
から始まるパスにできます。
Reference
javascript.preferences.importModuleSpecifier
Preferred path style for auto imports.
- shortest: Prefers a non-relative import only if one is available that has fewer path segments than a relative import.
- relative: Prefers a relative path to the imported file location.
- non-relative: Prefers a non-relative import based on the
baseUrl
orpaths
configured in yourjsconfig.json
/tsconfig.json
.- project-relative: Prefers a non-relative import only if the relative import path would leave the package or project directory. Requires using TypeScript 4.2+ in the workspace.
Atom
Atom で JavaScript を書く場合は、autocomplete-modules
を使うと、パスの auto complete ができます。
autocomplete-modules
では、"Webpack support" を有効にすることで、webpack.config.js
の resolve.alias
の設定からパスをマッピングできます。
また、"Babel Plugin Module Resolver support" を有効にすることで、babel-plugin-module-resolver
の設定を読み込んでパスをマッピングできます。
Atom で TypeScript を書く場合は、atom-typescript
もしくは ide-typescript
によって、 tsconfig.json
を使ってパスの auto complete ができます。
WebStorm / IntelliJ
WebStorm / IntelliJ では、webpack.config.js
の resolve.alias
の設定によって、パスをマッピングできます。
プロジェクトルートディレクトリに webpack.config.js
がない場合、Preferences > Languages & Frameworks > JavaScript > Webpack
に webpack.config.js
へのパスを設定すると読み込まれます。
Reference
WebStorm runs webpack under the hood when you open a project or change webpack.config.js and, thanks to the information it gets, WebStorm now properly understands the project resolve roots and resolve aliases.
By default WebStorm will analyze the webpack configuration file in the root of the project, but you can select another file in Preferences | Languages & Frameworks | JavaScript | Webpack.
https://blog.jetbrains.com/webstorm/2017/06/webstorm-2017-2-eap-172-2827/
また、TypeScript を書く場合は、tsconfig.json
を使ってパスをマッピングできます。
Preferences/Settings > Editor > Code Style > TypeScript
から Use paths relative to tsconfig.json
を有効にすると、tsconfig.json
が読み込まれます。
Reference
For TypeScript, you can use the paths that are relative to the nearest tsconfig.json file with the option “Use paths relative to tsconfig.json”, which is in the Imports tab in Preferences/Settings | Editor | Code Style | TypeScript.
https://blog.jetbrains.com/webstorm/2020/07/configuring-the-style-of-imports-in-javascript-and-typescript/
Parcel
Parcel v1 では、~/
をマッピングする機能が有効になっているため、追加の設定は必要ありません。
~/
は、主に「entrypoint となるファイルがあるディレクトリ」としてマッピングされます。
Reference
~/foo
resolvesfoo
relative to the nearest package root or, if not found, the entry root.
https://parceljs.org/module_resolution.html#~-tilde-paths
Parcel v2 では挙動が変わり、主に「package.json
があるディレクトリ」か「プロジェクトのルートディレクトリ」のどちらか、呼び出し元のファイルから近いディレクトリとしてマッピングされます。
Reference
~/foo
resolvesfoo
relative to nearestnode_modules
directory, the nearest directory withpackage.json
or the project root - whichever comes first.
https://v2.parceljs.org/features/module-resolution/#tilde-paths
Next.js
Next.js は、 tsconfig.json
もしくは jsconfig.json
の設定から、パスをマッピングできます。
Reference
Next.js automatically supports the
tsconfig.json
andjsconfig.json
"paths"
and"baseUrl"
options since Next.js 9.4.
https://nextjs.org/docs/advanced-features/module-path-aliases
Nuxt.js
Nuxt.js では、~/
をマッピングする機能が有効になっているため、追加の設定は必要ありません。
~/
は、nuxt.config.js
の srcDir
としてパスがマッピングされます。
Reference
By default the source directory (srcDir) and the root directory (rootDir) are the same. You can use the alias of
~
for the source directory.
You can use the alias of~~
or@@
for the root directory.
We recommend using the~
as an alias.@
is still supported but will not work in all cases such as with background images in your css.
https://nuxtjs.org/docs/2.x/directory-structure/assets/#aliases
webpack
webpack では、webpack.config.js
の resolve.alias
を使って、パスをマッピングできます。
const path = require('path');
module.exports = {
resolve: {
alias: {
'~': path.resolve(__dirname, 'src'),
},
},
};
Rollup
Rollup では、@rollup/plugin-alias
を使って、パスをマッピングできます。
const path = require('path');
const alias = require('@rollup/plugin-alias');
module.exports = {
plugins: [
alias({
entries: {
'~': path.resolve(__dirname, 'src'),
},
}),
],
};
TypeScript
TypeScript では、 tsconfig.json
にある paths
フィールドによって、パスをマッピングできます。
型チェックのときにもマッピングされるため、TypeScript を書くときには、他ツールでのマッピングと同じになるように tsconfig.json
を設定する必要があります。
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~/*": ["src/*"]
}
}
}
https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
Babel
Babel 単体でトランスパイルするとき、babel-plugin-module-resolver
を使うとパスをマッピングできます。
module.exports = {
plugins: [
[
'module-resolver',
{
alias: {
'~': './src',
},
},
],
],
};
PostCSS
PostCSS 単体でトランスパイルするとき、postcss-import
と postcss-import-resolver
を組み合わせることで、パスをマッピングできます。
const path = require('path');
const resolver = require('postcss-import-resolver');
module.exports = {
plugins: {
'postcss-import': {
resolve: resolver({
alias: {
'~': path.resolve(__dirname, 'src'),
},
}),
},
},
};
ESLint
eslint-plugin-import
でパスを解決するとき、任意の resolver を設定することでパスをマッピングできます。
webpack.config.js
の resolve.alias
からパスをマッピングする場合は、eslint-import-resolver-webpack
をインストールして、次のように設定します。
module.exports = {
extends: ['plugin:import/recommended'],
plugins: ['import'],
settings: {
'import/resolver': {
webpack: {
config: './webpack.config.js',
},
},
},
};
tsconfig.json
の paths
からパスをマッピングする場合は、@typescript-eslint/parser
と eslint-import-resolver-typescript
をインストールして、次のように設定します。
module.exports = {
parser: '@typescript-eslint/parser',
extends: ['plugin:import/recommended', 'plugin:import/typescript'],
plugins: ['@typescript-eslint', 'import'],
settings: {
'import/resolver': {
typescript: {
project: './tsconfig.json',
},
},
},
};
Node.js (runtime)
Node.js の実行時に、パスをマッピングする方法は、主に 3 種類あります。
require option
tsconfig-paths
を事前に require
することで、tsconfig.json
の設定からパスを実行時にマッピングできます。
node -r tsconfig-paths/register src/index.js
experimental loader option
Node.js v9.0.0 から、実験的機能として、モジュールの解決に外部の loader を使えます。
@node-loader/import-maps
は、loader 機能によって、import maps の設定からパスをマッピングできます。
{
"imports": {
"~/": "./src/"
}
}
IMPORT_MAP_PATH=import-map.json node --experimental-loader @node-loader/import-maps src/index.mjs
imports field
Node.js v14.6.0 から、 package.json
の imports
field を使って、実行時にパスをマッピングできます。
ただし、この機能では #
から始まるパスしか設定できないため、ここの例では #~/
から始まるパスをソースディレクトリにマッピングしています。
Reference
Entries in the imports field must always start with
#
to ensure they are disambiguated from package specifiers.
https://nodejs.org/dist/v15.5.0/docs/api/packages.html#packages_subpath_imports
All instances of
*
on the right hand side will then be replaced with this value, including if it contains any/
separators.
https://nodejs.org/dist/v15.5.0/docs/api/packages.html#packages_subpath_patterns
{
"type": "module",
"imports": {
"#~/*": "./src/*.mjs"
}
}
Deno
Deno では、実験的機能として import maps によるパスのマッピングに対応しています。
Reference
This is an unstable feature.
Deno supports import maps.
You can use import maps with the--import-map=<FILE>
CLI flag.
https://deno.land/manual@v1.6.3/linking_to_external_code/import_maps
{
"imports": {
"~/": "./src/"
}
}
deno run --unstable --import-map=import-map.json src/index.ts
Browser
2020 年 12 月現在、Chromium では試験的機能として、import maps を使ってパスをマッピングできます。
caniuse.com
https://caniuse.com/import-maps (2021 年 1 月 1 日参照)
<script type="importmap">
{
"imports": {
"~/": "/scripts/"
}
}
</script>
<script src="/scripts/index.mjs" type="module"></script>
Discussion