Directory Path の alias 設定（備忘録）

# 1. VSCode

1. `jsconfig.json` に書く。

```json:jsconfig.json
{
  "compilerOptions": {
    "paths": {
      "@root/*": [
        "./*"
      ],
      "@/*": [
        "./src/*"
      ]
    }
}
```

# 2. babel

1. `babel-plugin-module-resolver`([公式](https://github.com/tleunen/babel-plugin-module-resolver))をインストール
1. `babel.config.js`に書く

```javascript:babel.config.js
module.exports = {
  plugins: [
    [
      "module-resolver",
      {
        root: [".", "./src"],
        alias: {
          "@root": ".",
          "@": "./src",
        },
      },
    ],
  ],
};
```

# 3. Webpack

1. `webpack.config.js` に書く

```javascript:webpack.config.js
module.exports = {
  resolve: {
    alias: {
      "@root": "./",
      "@": "./src",
    },
}
```

# 4. Vue.js

1. `vue.config.js`に書く

```javascript:vue.config.js
const { defineConfig } = require("@vue/cli-service");

const root = __dirname; // プロジェクトディレクトリの絶対パス

module.exports = defineConfig({
  configureWebpack: (config) => {
    config = {
      resolve: {
        alias: {
          "@root": `${root}`, // 絶対パスで指定するのが無難
          // "@": `${root}/src`, // vue.config の default で定義されているので、明示は不要
        },
      },
    };

    return config;
  },
  transpileDependencies: true,
});
```

# 5. Storybook

`.storybook/main.js`に書く

```javascript:./storybook/main.js
const merge = require("webpack-merge");
const root = process.env.INIT_CWD;

module.exports = {
  webpackFinal: async (config) => {
    merge(config, {
      resolve: {
        "~": root,
        "@": `${root}/src`
      }
    });
    return config;
  },
}

```

# ext.

## ext.1. 動的にプロジェクトルートを計算し取得する

### ext.1.1. 独自に作る
:::note warn
全てのパターンに対応できてない
:::

```javascript:get-project-dir.js
const fs = require("fs");
const path = require("path");

/**
 * Dynamically determine the absolute path of the project root.
 *
 * @param {String} curDir
 * @return {String} Absolute path of project root.
 */
const getProjectDir = (curDir = __dirname) => {
  // node.exe の Initialize Current Working Directory(CWD) を取得
  // undefined な場合もある
  const {INIT_CWD} = process.env;

  // project root として一旦割当
  let projectDir = INIT_CWD;

  // 未割当の場合
  if (!projectDir) {
    // この script が配置されている directory
    projectDir = curDir;

    // directory を上階層に探索し、package.json を探す。
    // あればその階層が Project root directory
    while (!fs.existsSync(path.join(projectDir, "package.json"))) {
      // なければ更に上位階層を探索
      projectDir = path.join(projectDir, "..");
    }
  }

  // project root directory を返却
  return projectDir;
};

module.exports = getProjectDir;
```

### ext.1.2. `app-root-path` を使う

:::note info
使いやすいのでおすすめ
:::

#### リンク

https://www.npmjs.com/package/app-root-path

#### Install

```bash:gitbash
$ npm install --save app-root-path
```

#### 使い方

##### プロジェクトディレクトリの絶対パスを取得

```javascript:sample.js
const appRootPath = require("app-root-path");

const rootPath = appRootPath.toString();

console.log(`rootPath=${rootPath}`);
//=> プロジェクトディレクトリの絶対パスが出力される
//=> ${ABSOLUTE_PROJECT_DIRECTORY}
```

##### 相対パスをプロジェクトルートからの絶対パスに解決

```javascript:sample.js
const appRootPath = require("app-root-path");

const absolute = appRootPath.resolve("./hoge/dir");
//=> const absolute = require("node:path").resolve(appRootPath.toString(), "./hoge/dir"); と書くのと同じ。

console.log(`absolute=${absolute}`);
//=> プロジェクトディレクトリを含んだ絶対パスが出力される
//=> ${ABSOLUTE_PROJECT_DIRECTORY}/hoge/dir
```

##### モジュールのインポート

```javascript:sample.js
const appRootPath = require("app-root-path");

const app = appRootPath("/hoge/app");
//=> プロジェクトルート直下の /hoge/app が読み込まれる
//=> const app = require(`${appRootPath.toString()}/hoge/app`) と書くのと同じ。

app.func();
//=> Linter には対応していないのか、読み込みモジュール内の関数を Call するコードを書くと、
// 警告がログ出力されるが、実際に動作させると問題なく動く。設定の問題かもしれない。
```

## ext.2. `npm run-script` で実行される script でも directory path の alias を使いたい

### ext2.1. `babel-node`を使う

:::note info
`babel-node` 経由で実行する事により、`babel.config.js` で設定した directory path の alias が有効になる。
:::

例えば、以下の様な script を作成し、npm run すると、`Error: Cannot find module` になる。
```javascript:runner.js
const apple = require("@/lib/apple.js"); 

apple();
```

```bash:gitbash
$ npm run runner.js

node:internal/modules/cjs/loader:936
  throw err;

Error: Cannot find module '@/lib/apple.js'
...
```

`require("@/lib/apple.js")`を`require("./src/lib/apple.js")`と読み替えしてほしい時は`@bable/node`([公式](https://babeljs.io/docs/en/babel-node))を使う

```bash:gitbash
$ npm install --save-dev @babel/core @babel/node
```

インストール後は、`node`コマンドと互換性のある`babel-node` コマンドを使えるようになる。`babel-node`経由で実行されたスクリプトは`babel`及び各種プラグインの恩恵を受けられる。

```bash:gitbash
$ bable-node runner.js
```

### ext.2.2 `module-alias`を使う

`module-alias`([公式](https://github.com/ilearnio/module-alias))

:::note warn
※`require()`そのものの動作をオーバーライドするらしい。
:::

```bash:gitbash
$ npm i --save module-alias
```

インストール後、`package.json`に`_moduleAliases`を追加していく。

```diff_json:package.json
{
  "name": "my-project",
+  "_moduleAliases": {
+    "@": "./src"
+  },
  "scripts":{
  }
}
```

使い方は`require('module-alias/register')`を最初の行に記述するだけ。

```javascript:runner.js
require('module-alias/register'); // <- この行を追加する

const apple = require("@/lib/apple.js"); //<- "./src/lib/appne.js" に読み替えしてくれる様になる

apple();
```

`node`でも`npm run`でも`Error:module not found`は発生しなくなる。

```bash:gitbash
$ node runner.js
```

```bash:gitbash
$ npm run runner.js
```