スタイルガイドジェネレーターっぽいもの作ったので紹介

[Geek-Inc Advent Calendar 2017](https://adventar.org/calendars/2422)の18日目の記事です。

定義がよく分からなかったので一応スタイルガイドジェネレーターっぽいものとしておきます。

## メタ情報

|リポジトリ|https://github.com/nju33/yosuga|
|:--|:--|
|デモ|https://nju33.github.io/yosuga/|

## モチベーション

### 複数のAltCSS(sass,less,stylus...)に対応したい

時々、クライアント指定のAltCSSを使わなければならない時があります。それが例えばLessで、自分達がSassに強くてモジュール管理までちゃんとしているようなチームだとしたら、その恩恵を使えずに作ることになってしまいます。またLessで同じようなモジュールを作ったりしても、それを保守していくとこまで持っていけることがないです。（やっぱり意識してないとすぐ廃れる）
ただシンタックスの違いなんかで、割りと馬鹿にできない時間を消費したり、その時間も勿体無いなーとも思っていてるので、どのAltでも同じように使えるモジュール群を作って管理できるツールがほしいと思ってました。
また小さな案件などでは、１人で対応だし何を使っても構わないぜというようなものもあります。その人が好きなAltCSSを使っても恩恵を受けられるようにしたいという思惑もあります。

これはある完全なプロジェクトに含めるのではなくて、モジュール管理用として用意した単体のプロジェクトで複数の(Alt)CSSを管理していくイメージです。（で、npmに上げたりとかで使う）
というかcssフレームワークが近いかも。

### オフラインでも見れるように

これはもう個人的に何度も見に来るという想定で、オフラインでも見れるドキュメント最強だと思っている為。(オフライン > オンライン > ファイルを受け渡しするドキュメント)

ちなみに`lodash`のドキュメントサイトなどもいつの間にかオフラインで閲覧できるようになってます。

## 使った技術

良いなと思ったものとか。

### [NuxtJS](https://github.com/nuxt/nuxt.js)

数分あれば簡単なspaサイトが作れちゃうスグレモノ。今回もドキュメントページ生成にはNuxtJSを使いました。オフラインでも見れるようにといっても何やら難しそうでよく分からないと思うかもしれませんが、これは単に[pwa-module](https://github.com/nuxt-community/pwa-module)というモジュールを使うことで、これを使うことで30秒ぐらいで達成できます。以下のように設定に追加するだけで最低限のオフライン対応はできちゃうというお手軽さです。

```
{
  modules: [
    '@nuxtjs/pwa',
  ]
}
```

NuxtJSで１つよくわからないですがハマった点があり、１つのページに`<iframe src="/sections/foo"/>`のような同じnuxtでレンダリングするページを大量に設置したらページの反応が無くなってしまうという問題がありました。結局解決方法は分からず。。。😇

### [flow-runtime](https://github.com/codemix/flow-runtime)

Flowの型はコード内では有効ですが、外部からくる値入力値に対するチェックはしてくれないので、そのバリデーションに使用。引っかかるとスローしてそのままエラーメッセージを表示すればそこそこの出来になって便利です。

```js
t.string().assert('foo') // OK
t.string().assert(1) // throw
```

### [fast-memoize](https://github.com/caiogondim/fast-memoize.js)

`lodash.memoize`と比較すると、最初の引数以外も見てキャッシュしてくれるのが大きいです。

```js:repl
// _.memoze
fn = _memoize((a, b) => {
  console.log('called');
  return [a, b];
});

fn(1, 2)
// called
// => [1, 2]

fn(1, 3)
// => [1, 2]

fn = fastMemoize((a, b) => {
  console.log('called');
  return [a, b];
});

fn(1, 2)
// called
// => [1, 2]

fn(1, 3)
// called
// => [1, 3]

fn(1, 3)
// => [1, 3]
```

### [gray-matter](https://github.com/jonschlinkert/gray-matter)

jekyllなどでお馴染みのフロントマターありのコンテンツをパースしてくれるスグレモノ。

## 紹介

### 機能

#### それぞれAltCSSの出力結果が同じになるかどうかチェック

Yosugaでは（デフォルトで）このようなディレクトリ構造を想定してます。

```bash
.
├── css
│   └── button.css
├── example.js
├── less
│   ├── button.less
│   └── button.yosuga.less
├── postcss
│   ├── button.css
│   └── button.yosuga.css
├── sass
│   ├── button.scss
│   ├── button.yosuga.scss
│   ├── nav.scss
│   └── nav.yosuga.scss
├── stylus
│   ├── button.styl
│   └── button.yosuga.styl
└── yosuga
    ├── button.html
    └── nav.html
```

cssだけがそのままで、他のAltCSSは`*.yosuga.*`というファイルが比較対象になります。そしてファイルの結果が`button.css === button.yosuga.less === button.yosuga.css === button.yosuga.scss button-yosuga.styl`かというのをチェックします。どれを`main`にするかは設定で変えることができて、例えばデフォルトの`css`の場合`button`だけが対象で、`sass`にした場合は、`button`と`nav`が対象になります。その時、`nav`は１つだけなので必ずチェックを通ります。
そして、チェックを通ったものだけページで表示されます。

`*.html`はそのコンポーネントのためのマークアップやメタ情報を設定するために使います。例えばこんな感じになります。フロントマターは[toml](https://github.com/toml-lang/toml)で記述します。

> 本当はyamlでやりたかったのですが、nodejsのyamlパーサーで複数行の文字列に対応したもの（`|`使うやつ）がなかったのでTomlになりました…

```html:button.html
---
title = "Button"
summary = "ボタンの概要"
description = """
  ## ボタン

  詳しい説明
"""
---

<!-- 以下のボタンのための補足説明 -->
<button>...</button>
```

<img width="797" alt="screenshot.png" src="https://qiita-image-store.s3.amazonaws.com/0/84144/f3a81c4a-d31c-b263-da91-2779dd0abb79.png">


また、実際にチェックする時は、それぞれの出力結果にcssnanoとpostcss-sortingをかました上で比較することで、プロパティの並びの違いなどその他各(AltCSS)間で起きそうな微妙な違いは無視できるようになっています。

ちなみにチェックに引っかかった時はこんな感じでログに出ます。（色ついてるところが違う）
<img width="545" alt="Hyper.png" src="https://qiita-image-store.s3.amazonaws.com/0/84144/b736d917-f500-81eb-c91e-a2580e9918be.png">

#### カスタマイズ

<img width="239" alt="screenshot.png" src="https://qiita-image-store.s3.amazonaws.com/0/84144/26a318da-521a-114e-abcb-0aa070446188.png">

##### ①

ベースディレクトリ（デフォルトで今いるディレクトリ）に`icon.png`を置くとアイコンを設定できます。

##### ②

`new Yosuga`するときに`name`を設定することで設定できます。

```js
new Yosuga({name: 'Yosuga DEMO'});
```

##### ③

同じく`style`色とフォントサイズは変えられます。

```js
new Yosuga({
  style: {
    accentColor: '#...',
    fontSize: '15px',
  }
});
```

## 使いかた紹介

多分１番早いと思います。

### インストール


#### API


```bash
yarn add -D yosuga
npm i -D yosuga
```

```
const yosuga = new Yosuga({...});
(async () => {
  await yosuga.prepare({name: '...'});
  // 開発時
  yosuga.serve();

　// ビルド時
  // baseは`<base/>`のhref属性の値
  yosuga.generate(base?)
})();
```

`serve`するとデフォルトで`localhost:3333`で起動するので色々css書いたりで作っていきます。一応`serve`中はcssファイルなどを変更すると自動で反映されるような仕組みになってます。

#### CLI

```bash
npm i -g yosuga-cli
yosuga init
yosuga server # or generate
```

#### QuickStart

```bash
git clone git@github.com:nju33/yosuga-quickstart.git
cd yosuga-quickstart
yarn
yarn dev
```

## 感想

…とここまで作っておいてあれなんですが、今の段階ではまだ色々微妙かもしれない＼(^o^)／
作り込みも色々甘いので自分の能力的にもまだまだだな〜と感じました😇

ひとまず会社とかで使えるといいな〜。
NuxtJSを使えばちょっとした、サイトも欲しいようなツールを割りとすぐ作れそうなので、他色々作ってみたいです。

明日19日ははデザイナーのRさんです！よろしくお願いします！