【Vue, YAML】Vue.jsでYMLファイルを読み込みする、画像パスを管理する

## 経緯

非エンジニアが管理しやすいように、ということで、vue.jsでYMLファイルを読み込んで設定ファイルとして使用したかったけれど、少し悩むところもあったので備忘録

## 結論
```vue
<!-- @/components/Hoge.vue -->
<script>
import yaml from "js-yaml"

export default {
    data() {
        return {
            title: "",
            image: ""
        }
    },
    methods: {
        loadConfig() {
            try {
                // .defaultが重要
                const txt = require("raw-loader!@/assets/hogehoge.yml").default
                const config = yaml.load(txt)

                this.title = config["hoge"].title
                // 画像パスの解決
                this.image = require(`../assets/${config["hoge"].image}`)
            } catch (error) {
                console.log('YMLファイルの読み込みに失敗しました: ', error)
            }
        }
    }
}
</script>
```

## 環境
windows10
Vue.js v3.2系
webpack v4

ymlサンプル
```yml
hoge:
  title: "youkoso!!"
  image: "hoge.png"
```

## 読み込みにはjs-yamlを使用
まずは[js-yaml](https://www.npmjs.com/package/js-yaml)をインストール

```terminal
npm i js-yaml
```

次に公式の手順だと以下となる

```js
const yaml = require('js-yaml');
const fs   = require('fs');

// Get document, or throw exception on error
try {
  const doc = yaml.load(fs.readFileSync('/home/ixti/example.yml', 'utf8'));
  console.log(doc);
} catch (e) {
  console.log(e);
}
```

が、残念ながらVue.jsではfsは使用できないらしい
※js-yamlはそもそもnode.js向け

## fsの代わりに

next.jsだと下記引用のような方法もあるみたいですが、私の環境では使えませんでした。
https://stackoverflow.com/questions/71040231/typeerror-fs-readfilesync-is-not-a-function-in-next-js

ここでは代わりに[raw-loader](https://v4.webpack.js.org/loaders/raw-loader/)を使用します。

まずはインストール
```terminal
npm install raw-loader --save-dev
```

そしてconfigに以下を追加
```js
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.yml$/i,
        use: 'raw-loader',
      },
    ],
  },
};
```

公式だと`test: /\.txt$/i`ですが、今回はymlファイルの読み込みに使いたいだけなのでymlとしました。

## raw-loaderを使ってみる
では準備もできたので早速反映

```vue
<!-- @/components/Hoge.vue -->
<template>
    <div>
        <h1>{{ title }}</h1>
        <img :src="image" />
    </div>
</template>
<script>
import yaml from "js-yaml"

export default {
    data() {
        return {
            title: "",
            image: ""
        }
    },
    methods: {
        loadConfig() {
            try {
                const config = yaml.load(require("raw-loader!@/assets/hogehoge.yml"))
                console.log('config', config)
                
                this.title = config["hoge"].title
                this.image = config["hoge"].image
            } catch (error) {
                console.log('YMLファイルの読み込みに失敗しました: ', error)
            }
        }
    }
}
</script>
```
これでようやく使えるかと思いきや、私の環境ではエラーが出ました。
>ここにエラー書く

何か間違ったかと焦りましたが、ESLintのエラーでした。
`.eslintrc.js`等設定ファイルに無視する設定を追記して、黙っていただきましょう。→[参考](https://stackoverflow.com/questions/45443274/webpack-2-expected-error-using-with-import)

```js
// .eslintrc.js
module.exports = {
    rules: {
        "import/no-webpack-loader-syntax": "off"
    }
}
```

## それでも読めない
ここまで設定してもYMLファイルの読み込みは失敗し、configの中身を確認しても`length: 1`の`['object Module']`だけが返る状況…

調べたところ、`require()`には`.default`が必要になる場合があるみたいでした。
```js
require("raw-loader!@/assets/hogehoge.yml").default
```
これでようやくYMLファイルの読み込みができるようになりました。

`.default`が必要かどうかは、`export default`と`export.default`の違いらしいですがよくわからず…
こちらは別の機会に調べたいと思います。笑

## 画像パスが解決できない
せっかくYMLが読めるようになりましたが、今度はYMLに書いた画像パスを解決できず、画像が表示されません…
### 原因は2つ
1つ目はwebpackが原因で静的アセットのパス解決ができていませんでした。
webpackも理解ができるよう、`require()`してあげます。

2つ目は相対パスです。
今回のファイル構造は以下です。

```
src/
  assets/
    hoge.png
    hogehoge.yml
  components/
    Hoge.vue
```

当初ymlの位置からのパスとして`./hoge.png`としていたのですが、yml読み込みをしたHoge.vueからpngを探しに行くため、`../assets/hoge.png`が正解でした。

今回はymlファイルの管理は非エンジニアが行う想定なので、記述時に混乱しないようにということも兼ねて、ymlにはファイル名だけを記載し、パスは読み込み時に追加する方式にしました。

```js
// 画像パスの解決
this.image = require(`../assets/${config["hoge"].image}`)
```

これでようやく、YMLファイルの内容をVueから読み込み、画面に反映させることができました。


## 感想
まだまだわからないことだらけですね。