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
baseUrlorpathsconfigured 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
~/fooresolvesfoorelative 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
~/fooresolvesfoorelative to nearestnode_modulesdirectory, the nearest directory withpackage.jsonor 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.jsonandjsconfig.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