Node.jsでファイルを読み込んであれこれする時の備忘録

# ゴール
コマンドひとつでpublic/htmlに入っているファイルのリストをfileList.jsonに作る。
public/htmlにファイルが増えてもコマンドを叩けばリストが更新されるようになる。
※パッケージマネージャーはnpmを使います。

```md:ディレクトリ（public/htmlはbaseをビルドしたものが入る前提）

list/
　│　　　　└ fileList.json
src/
　├ public/
　│　　　　　├ html
　│　　　　　│　　　　　├ index.html
　│　　　　　│　　　　　├ news.html
　│　　　　　│　　　　　├ hoge.html
　│　　　　　│　　　　　└ fuga.html
　│　　　　　├ js/
　│　　　　　├ css/
　│　　　　　└ images/
　├ dev/
　│　　　　　└ htmlList.js 　　←リストを作るjsはこちらに入れます。
　└ base/
　　　　　　└ index.html
　　　　　　└ news.html
　　　　　　└ hoge.html
　　　　　　└ fuga.html
```

fileList.jsonは下記のようになるイメージ。
nameに入るのはtitleタグ内に入っている文字列の想定。
```json:fileList.json
{[
    {
        "name": "ホーム",
        "file": "/index.html"
    },
    {
        "name": "ニュース",
        "file": "/news.html"
    },
    {
        "name": "ほげ",
        "file": "/hoge.html"
    },
    {
        "name": "ふが",
        "file": "/fuga.html"
    }
]}
```


# 事前準備
Node.jsをインストールしておくこと。
「とりあえず最新にしておくか」とインストールしてみたら、意外と使えないnpmパッケージとかもあるので注意です。
わからない時は推奨版をインストールしておくのがいいかと思います。
https://nodejs.org/ja/download/


# 早速やっていきましょうか
やることは下記の５つです。
1. [コマンドを登録](#コマンドを登録)
2. [モジュールの呼び出し](#モジュールの呼び出し)
3. [リストにする対象のディレクトリを定義する](#リストにする対象のディレクトリを定義する)
4. [リストデータを入れるファイルを定義する](#リストデータを入れるファイルを定義する)
5. [ファイル一覧を作ってjsonファイルに上書きをする](#ファイル一覧を作ってjsonファイルに上書きをする)

## コマンドを登録
package.jsonのscriptsに下記のように記述すればOK
```json:package.json
  "scripts": {
    "htmlList": "node dev/htmlList.js",
  }
```
これでコマンド `npm run htmlList` を打てばリストが作れるようになります。

## モジュールの呼び出し
fsとglobを使うので下記のように呼び出してください。他のものはいりません。
```js
const fs = require('fs');
const glob = require('glob');
```

npmのglobはパターンにマッチするパス名を探してくれます。
なので、どれだけbuild配下のディレクトリが複雑になったとしても安心です。
https://www.npmjs.com/package/glob
インストールは`npm install --save-dev glob`でできます。

一覧を作るためにfsモジュールとpathモジュールを使ってfs.readdirする方法もありますが、ディレクトリが複雑になっていると少々扱いづらいので、私はglobを使った方法でやります。
fsはtitleタグの中の文字列を読むために使います。


## リストにする対象のディレクトリを定義する
私はsrc/public/htmlを無条件ですべてリスト化したいので、下記のようになります。
```js
const buildDir = 'src/public/html/**/*.html';
```

もしコマンドでディレクトリ指定をしたい場合は下記のとおりになります。
```js:コマンドでsrc/public/html/spのみを指定したい場合
const targetDir = process.argv[2];
const buildDir = 'src/public/html/' + targetDir + '/**/*.html';
```
`process.argv[2]`でコマンドの最初の引数を取得できます。

## リストデータを入れるファイルを定義する
```js
const fileListJson = 'list/fileList.json';
```

## ファイル一覧を作ってjsonファイルに上書きをする
いっぺんにやってしまいましょう。ざっと書くと下記のようになります。
```js
glob(buildDir, (err, files) => {
	if (err) {
		console.log(err);
	} else {
        const fileList = files.map(file => {
            const fileContents = fs.readFileSync(file, 'utf-8');
            const startPosition = fileContents.indexOf('<title>') + '<title>'.length;
            const endPosition = fileContents.indexOf('</title>');
            const name = fileContents.substring(startPosition, endPosition);
            return {
                'name': name,
                'file': file.replace(/\/src\/public\/html/, ''),
            };
        });
        fs.writeFileSync(fileListJson, JSON.stringify(fileList));
	}
});
```
globのerrorの中身ですが、エラーであればオブジェクト、成功であればnullが返ってきます。

成功したら、mapでファイルリストを配列で作りましょう
mapの中のfileContentsではファイルの中身をutf-8で読み込んでいます。文字コードがないと文字化けします。
中身を取り出せたら`<title>`と`</title>`のあいだの文字列を取得します。
`startPosition`で最初の文字のインデックス、`endPosition`で最初の文字のインデックス、`name`で文字を取得しています。
それができたらfileはいらない文字列を消してから、オブジェクトにしてリターンしましょう。

リストができたらfileList.jsonに上書きをします。
`fs.writeFileSync`がファイルの上書きのメソッドです。
第一引数に書き込みたいファイルを指定し、第二引数に書き込みたい内容をいれます。
今回はjsonファイルへの書き込みのため、json文字列に書き換える`JSON.stringify()`をお忘れずにつけてください。

# 完成
これで完成です！
今回追記＆新規作成をしたものをおさらいしましょう。

・package.jsonにコマンドを登録
```json:package.json
  "scripts": {
    "htmlList": "node dev/htmlList.js",
  }
```

・ファイルリストを作るためのjsを新規作成
```js:src/dev/htmlList.js
const fs = require('fs');
const glob = require('glob');
const buildDir = 'src/public/html/**/*.html';
const fileListJson = 'list/fileList.json';

glob(buildDir, (err, files) => {
	if (err) {
		console.log(err);
	} else {
        const fileList = files.map(file => {
            const fileContents = fs.readFileSync(file, 'utf-8');
            const startPosition = fileContents.indexOf('<title>') + '<title>'.length;
            const endPosition = fileContents.indexOf('</title>');
            const name = fileContents.substring(startPosition, endPosition);
            return {
                'name': name,
                'file': file.replace(/\/src\/public\/html/, ''),
            };
        });
        fs.writeFileSync(fileListJson, JSON.stringify(fileList));
	}
});
```


「できんのですが...」等なった場合はコメントいただければと思いますmm