自分流の静的ウェブ開発環境　2018年版



[出来上がったもの(2018年9月)](https://sno2wman.graphics/)

[ソースコード](https://github.com/SnO2WMaN/sno2wman.graphics/tree/v2)

**この記事は半起半眠みたいな状態で書いたので、文章が壊滅している可能性がありますがご了承ください。**

#dependencies
```
yarn add -D parcel-bundler babel-core babel-preset-env css-mqpacker eslint eslint-config-precure husky lint-staged node-sass node-sass-package-importer parcel-bundler parcel-plugin-imagemin parcel-plugin-inlinesvg postcss postcss-short postcss-sorting pug stylelint stylelint-config-recommended-scss stylelint-scss 
```

```
yarn add @fortawesome/fontawesome-svg-core @fortawesome/free-brands-svg-icons @fortawesome/free-solid-svg-icons awesome-sass-easing barba.js bezier-easing imagesloaded masonry-layout mathsass minireset.css sass-metallic-ratio webfontloader
```

#バンドルツール

普段は[webpack](https://github.com/webpack/webpack)を使っていましたが、今回は[Parcel](https://github.com/parcel-bundler/parcel)を採用しました。

理由は`webpack.config.js`書くのがそろそろダルくなってきたというのがメインなんですが、それ以外にwebpack-dev-server関係が上手くいかなかったなどがありました。

```json:package.json
  "scripts": {
    "dev": "npx parcel ./src/index.pug",
    "build": "npx parcel build ./src/index.pug --experimental-scope-hoisting",
  }
```

基本的にnpmスクリプトとして登録しておくと楽でいいと思います。

`build`の際に`--experimental-scope-hoisting`なるオプションをつけるとTree-Shakingが行われ、ファイルサイズを圧縮する事ができます。（FontAwesome5関連は後述します）

## Parcelプラグイン
Parcelにはプラグインがいくつか開発されており、`parcel-plugin-*`という名前で登録されています。
Parcelプラグインはインストールしておくだけでparcel側が勝手に使用します。

今回は[parcel-plugin-imagemin](https://github.com/DeMoorJasper/parcel-plugin-imagemin)と[parcel-plugin-inlinesvg](https://github.com/albinotonnina/parcel-plugin-inlinesvg)を使いました。

### parcel-plugin-imagemin

Imageminプラグインでは画像の圧縮を担当します。
`imagemin.config.js`で画像の圧縮に関する設定を行うことが出来ます。自分の場合はこんな風です。

```js:imagemin.config.js
module.exports = {
  mozjpeg: {
    progressive: true,
    quality: 65,
  },
  pngquant: {
    quality: 65,
    speed: 4,
  },
  gifsicle: {
    interlaced: false,
    optimizationLevel: 3,
  },
  webp: { quality: 25 },
}
```

デフォルト値、設定方法はこれらのリポジトリを参照してください。

- [imagemin-gifsicle](https://github.com/imagemin/imagemin-gifsicle)
- [imagemin-pngquant](https://github.com/imagemin/imagemin-pngquant)
- [imagemin-svgo](https://github.com/imagemin/imagemin-svgo)
- [imagemin-mozjpeg](https://github.com/imagemin/imagemin-mozjpeg)
- [imagemin-webp](https://github.com/imagemin/imagemin-webp)

アニメーションwebpはまだ対応しておらず、エラーを吐いてしまうことが注意点です。

### parcel-plugin-inlinesvg

SVGファイルをこのように使ったりする時に必要になります。

```js
const logo = require("mylogo.svg")
```

# 中間ツール

Parcelはいくつかの中間ツールに対応しています。([公式ドキュメント](https://parceljs.org/transforms.html))

## browserslist
対応させるブラウザを指定することが出来ます。([Github](https://github.com/browserslist/browserslist))

```:.browserslistrc
>0.25%
not ie 11
not op_mini all
```

Opera Mini、IE11を除く0.25%以上のシェア率のウェブサイトに対応するように記述してあります。

## babel

Babelはごく一般的な、[babel-preset-env](https://github.com/babel/babel-preset-env)だけの構成です。

```json:.babelrc
{
  "presets": ["env"]
}
```

babel-preset-envはbrowserslistに対応しています。([公式ドキュメント](https://babeljs.io/docs/en/babel-preset-env#browserslist-integration))

## postcss

```json:.postcssrc
{
  "parser": "postcss-scss",
  "plugins": {
    "autoprefixer": {},
    "css-mqpacker": {},
    "postcss-sorting": {},
    "postcss-short": {}
  }
}
```
- [postcss-scss](https://github.com/postcss/postcss-scss) PostCSS用のSCSSパーサー。
- [autoprefixer](https://github.com/postcss/autoprefixer) 自動でプレフィックスを付ける。browserslistで対応ブラウザを指定することが出来る。
- [css-mqpacker](https://github.com/hail2u/node-css-mqpacker) メディアクエリを一つにまとめる。
- [postcss-sorting](https://github.com/hudochenkov/postcss-sorting) プロパティを並び替えて、サイズの縮小化を図る。
- [postcss-short](https://github.com/jonathantneal/postcss-short) プロパティーのショートハンドを追加。

## Sass

```scss:root.scss
@import '~minireset.css/minireset';//node_modules直下のファイルを読み込みたい。
```
webpackなどではスンナリ通ったこれらのコードが突然死んだので、[node-sass-package-importer](https://github.com/maoberlehner/node-sass-magic-importer/tree/master/packages/node-sass-package-importer)を使いました。

[この記事](https://www.rainorshine.asia/2018/01/12/post2855.html)などが参考になると思います。

```js:.sassrc.js
const packageImporter = require('node-sass-package-importer')

module.exports = {
  importer: [packageImporter()],
}
```

# Lint、フォーマット関連

使用したのは[ESLint](https://github.com/eslint/eslint)、[Stylelint](https://github.com/stylelint/stylelint)、[Prettier](https://github.com/prettier/prettier)です。

エディタ側のフォーマットの設定で、[editorconfig](https://editorconfig.org/)も使いました。

ESLint、Prettierはお使いのエディタの拡張機能も合わせて使うと幸せになれるかもしれません。

## ESLint

@akameco氏の[eslint-config-precure](https://github.com/akameco/eslint-config-precure)をそのまま継承しています。([Qiita記事](https://qiita.com/akameco/items/33629ecd9740be1545a1))

PrettierとESLintのコンフィグ重複の調整を行ってくれるので幾分か楽です。

```json:.eslintrc
{
  "extends": ["precure"]
}
```

## Stylelint

SCSS使いなので、コンフィグは[Stylelint-config-recommended-scss](https://github.com/kristerkari/stylelint-config-recommended-scss)を継承しています。

`no-descending-specificit`は自分のコードの書き方に合わなかったので無効化しています。

```json:.stylelintrc
{
  "extends": "stylelint-config-recommended-scss",
  "rules": {
    "no-descending-specificity": null
  }
}
```

## Prettier, EditorConfig

akameco氏のコンフィグを参考に。

```json:.prettierrc
{
  "semi": false,
  "singleQuote": true,
  "trailingComma": "es5"
}
```

```:.editorconfig
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false
```

## コミット時のLintとか

[husky](https://github.com/typicode/husky)、[lint-staged](https://github.com/okonet/lint-staged)を使って、`package.json`に以下のプロパティを追加。

```json:package.json
  "scripts": {
    "precommit": "npx lint-staged"
  },
  "lint-staged": {
    "src/**/*.js": [
      "prettier --write",
      "eslint --fix",
      "git add"
    ],
    "src/**/*.{css,scss}": [
      "prettier --write",
      "stylelint",
      "git add"
    ]
  },
```
これでgit commitする度にLintが通ったりフォーマットされたりします。

# その他色々
## FontAwesome5
FontAwesome5にはTree Shakingの機能がちゃんとあるのですが([公式ドキュメント](https://fontawesome.com/how-to-use/with-the-api/other/tree-shaking))、Parcel側が採用しているJS圧縮パッケージと相性が悪く、下記の書き方だと成功しません。

```js:fontawesome.js
import { dom, library } from '@fortawesome/fontawesome-svg-core'
import { faEnvelope, faCopy } from '@fortawesome/free-solid-svg-icons'

library.add(
  faEnvelope,
  faCopy
)
```

結構面倒くさいですが、この書き方だと成功するのでかなり圧縮されます。（自環境では900kBから200kBほど）

```js:fontawesome.js
import { dom, library } from '@fortawesome/fontawesome-svg-core'
import { faEnvelope } from '@fortawesome/free-solid-svg-icons/faEnvelope'
import { faCopy } from '@fortawesome/free-solid-svg-icons/faCopy'

library.add(
  faEnvelope,
  faCopy
)
```

いずれ対応することを願っていましょう。

## CSSノーマライズ
「結局どれが良いんだよ！」と思いながら、今回は[MiniReset.css](https://github.com/jgthms/minireset.css/)を採用しました。

おすすめがあったら誰か教えてください。

## Webフォント

WebフォントのCSSをHTMLにベタ書きすると読み込まれた判定が出来ないので、[webfontloader](https://github.com/typekit/webfontloader)を使用しています。

結構色々な事ができるので、詳しくは公式ドキュメントを読んでください。
私はGoogleFonts信者なので、googleプロパティしか使ったこと無いのですが.......

自分は`Promise`として使っています。

```js
import webfontloader from 'webfontloader'

const webfont = new Promise(resolve => {
  webfontloader.load({
    google: {
      families: [
        'VT323',
        'Lobster Two:400i',
        'Poppins;400,300',
        'Roboto Mono',
        'Sawarabi Gothic:latin,japanese',
      ],
    },
    active() {
      resolve()
    },
  })
})
```

余談ですが、いつの間にかGoogleFontsに日本語が追加されてました。やったね！
https://fonts.google.com/?subset=japanese


#おわりに

[barba.js](https://github.com/luruke/barba.js/)に苦戦したり、スマホ対応を全力でぶん投げたりしましたが、楽しかったです。

また作り直したいですね。

こんなライブラリあるよ！等のコメントがあれば大変嬉しいので、よろしくおねがいします。