67
60

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

javascriptビルドツールなどで相対パス地獄(../../)を解決する方法まとめ

Last updated at Posted at 2016-03-15

requireimportなどのモジュール解決において、相対パスを解決しようとすると../../../と大量に出てしまう問題。
relative paths hellと呼ばれたりもするらしい。

基本requireの挙動としてはNode.jsのmodulesと同じ挙動を原則としたかったりわりと小めんどくさかったので結構今までガマンしておとなしく../../と書いたりしていた(モジュール小分けにしてあんまりこの問題に当たらないようにしていたというのもある)

しかし「import構文だと実はそもそもの原則違うのでは?1」とか「frontend向けに組んでいる時にそこ厳密にすることでもないのでは?」とか「趣味レベル越えたコードだとモジュール小分けとかも出来ないのでは?」とか思い各buildツールで相対パス地獄をどうすると出来るのかみたいなのを調べた。

前提など

こんな感じのプロジェクトを想定

.
└── src
    ├── foo
    │   └── baz.js
    └── index.js

そしてindex.jsにて

import baz from "foo/baz"

で解決できるような世界を考える。
import / exportを利用する前提として、必要があればbabelを使う

基本

node.jsのModulesではどうか?

requireでの話。結構複雑だが、概ねこんな感じ

  • ./node_modulesを解決する
    • ローカルもグローバルも見る
  • $NODE_PATHの環境変数に指定されたパスも解決する

詳細はドキュメントを
https://nodejs.org/api/modules.html

(参考) browserify handbookで紹介されている解決法

node.jsの世界に近めの解決法が紹介されている。とはいえあんまり頻繁に更新されてるものでもないので情報古めかも。

  • symlinkをnode_modules下に貼る
  • そもそもnode_modulesの下に自前のモジュールを作る
  • $NODE_PATHを使ってカスタムパスを使う(後述)

Build System編

webpack

webapckはなんでも出来てしまうので、普通に出来る。
loaderのinclude設定を利用する

module.exports = {
  entry: "./src/index.js",
  // resolve.rootで指定
  resolve: {
    root: [
      path.join(__dirname, "./src")
    ]
  },
  module: {
    loaders: [
      {
        test: /^src\/.*\.js$/,
        include: [
          path.resolve(__dirname, "src"),
        ],
        loader: "babel-loader"
      }
    ]
  }
}

browserify

コマンドラインの場合

node.jsの基本と一緒。
$NODE_PATHの環境変数を仕込む

NODE_PATH=./some/lib browserify -e src/index.js -o build/index.js

API利用の場合

opt.pathsの設定があるのでこれを利用できる

browserify("src/index.js", {
  paths:[
    "./node_module", "./src"
  ]
}).bundle(function(err, out){
  // out.toStirng() とかでコード取れる
})

ちなみにpackage.jsonにpathsとか仕込んだりして読み取ってはくれないし、同等のCLIオプションも用意されてない。

rollup

import構文はrollupではデフォルトなので、相対パスの解決だけ考えれば良い

include-pathプラグインを利用する。

手元でちゃんと試せてないが、概ねこんな具合。

import includePaths from 'rollup-plugin-includepaths';

let includePathOptions = {
    include: {},
    paths: ['src'],
};

export default {
    entry: './src/index.js',
    dest: 'build/index.js',
    plugins: [ includePaths(includePathOptions) ],
};

test framework編

mocha

$NODE_PATHを設定する。

webpackと組み合わせている場合は二重に設定を書くことになる。

NODE_PATH=src/ mocha ./test

ava

同じく$NODE_PATHを設定する。

NODE_PATH=src/ ava ./test

言語編

TypeScript

tsconfig.jsonにこう

{
    "baseUrl": "./src"
}

flowtype

0.32時点。

module.system.node.resolve_dirnameを設定する必要ありそう。NODE_PATHだけだと解決してくれないっぽい

.flowconfig
[options]

module.system.node.resolve_dirname=./node_modules
module.system.node.resolve_dirname=./src

まとめ

  • どうやっても邪道になる印象があったけど、結構なんだかんだ各ツール手法は出揃ってる
  • NODE_PATHを抑えておけばとりあえずはなんとかなる。
  • テストツールのことを考えるとむしろNODE_PATHを使うのをベースにするほうが良いのかも。
  • 当たり前だけどnpmにpublishするような予定のプロジェクトなら多分やめとくほうがいい
  1. importの実際の解決方法に関しては正直知識が薄いので不安感強め

67
60
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
67
60

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?