TL;DR
Prettier触ってみたかったので、boilerplateっぽいのを作った。
- JSはESLint。CSSはStylelintを使います。
- FormatterとしてPrettierを使用。これはJSのみ。
-
git commit
時に自動整形されるようにしておく。
PrettierそのものはCSSにも対応しているが、Stylelintと併用しようとすると、まだ足りない感じなので様子見。けっきょくPrettierしてるのはJSだけなので、なんだか片手落ちな感が否めない。追って対応していきたいところ。いちおレガシーCSSに導入するときとか事前にPrettier通しておくと、多少は楽だった。
コーディングルールに関しては一例として、今回は無難なルールをベースに設定しています。
導入数でいえばGitHubやAirBnBコーディングルールが多数派だが、Linter導入の目的としてはstandardの方が合っているだろうと思う。
メリット
- 記法が統一されるとレビューで見やすくなる
- 細かいコードの書き方で揉めるのを防ぐ
- 並び順とか手動でやらせると非現実的な指定を、自動で行える
Q. PrettierとLinterの--fixオプションは何が違うの?
A. Prettierはコードの整形はするが、警告を出してくれない。
コードの整形そのものは、LinterよりPrettierのほうが巧くやってくれる(1行80文字とか)。とはいえ、あまり細かな指定はできない。なんなら.editorconfigのほうが多いかもくらいなので。
Linterが出してくれる警告には意味があるので消したくないが、エラーがindentで埋まるのは好ましくないので使い分ける。Linterには「記法の統一」と「品質の担保」という2つの側面があって、前者を機械的に処理することによって、本質的なレビューに専心できる。
デメリット
- エディタ連携すると好みのスタイルで書けない
- Pre-commit設定するとコミット時に多少もたつく
手元では好きなスタイルで書かせておいて、push時にインデントとか整形するってのが、一番Prettierを活かしてるスタイルな気がする。eslint-plugin-standard
を抜けばできそうに思うが、どうせmergeすれば変わってるので良いかなとシンプルに--fix
で纏めることにした。
Install
$ yarn add -D prettier
$ yarn add -D eslint eslint-plugin-prettier eslint-config-prettier
$ yarn add -D eslint-config-standard eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node
$ yarn add -D stylelint stylelint-order stylelint-config-standard
Usage
$ eslint --fix src/**/*.js
$ stylelint --fix src/**/*.css
ESLintがPrettierを実行するように設定しているのでシンプル。エラーもPrettierの出力を前提にチェックしている。sylelintはそのままで、Prettierなし。
Pre-commit Hook
全員にエディタプラグイン入れさせるのは現実的でないため、
git commit
すると自動でLinter/formatterが走るように設定しておく。
$ yarn add -D lint-staged husky
...
"scripts": {
"precommit": "lint-staged"
},
"lint-staged": {
"src/**/*.{js,json}": [
"eslint --fix", "git add"
],
"src/**/*.{css,scss}": [
"stylelint --fix", "git add"
]
},
...
参考: Pre-commit Hook
Note: ESLintと併用する場合
PrettierとESLintと併用する場合、2つの方法がある
-
eslint-plugin-prettier
- ESLintのworkflowで処理する
- Prettierの出力が維持される
- .eslintrcにprettierが明記されるので判りやすい
-
eslint-config-prettier
を使えば、ESLintのPrettierと重複してるルールを無効化してくれる -
eslint --fix
だけで、PrettierとESLintの自動修正を同時に行ってくれる - Integrating with ESLint
-
prettier-eslint
- Prettierしてから
eslint --fix
に渡す - Prettierのオプションは
.prettierrc
で管理する -
prettier-eslint --write
でeslint --fix
もしてる
- Prettierしてから
ESLintがPrettierを実行するか、PrettierがESLintに渡すか。
ほとんど変わらないが、後者だと--fix
なしでチェックだけしたいってのができない。あと、prettier-eslint
の作者はもう使ってないとのことなので、現実的にはeslint-plugin-prettier
一択。
Note: CSSの場合
stylelint --fix
を用いて整形まで行う。
stylelint-orderを入れれば、プロパティのソートが可能になる。postcss-orderの内部で使われていて、今回の場合はstylelint-idiomatic-order
に含まれている。
少し前ならstylefmtて良いツールがあって、Prettierのissueからも誘導されてたけど、stylelintが--fix
に対応したので開発が止まってる。prettier使うか、stylelint --fix
しろって感じらしい。
- Stylistic issues
- Prettier + Stylelint: Writing Very Clean CSS (Or, Keeping Clean Code is a Two-Tool Game)
- Prettier for CSS
Note: prettier-stylelint(できなかったメモ)
$ yarn add -D stylelint prettier-stylelint
$ yarn add -D stylelint-config-standard stylelint-config-idiomatic-order
$ yarn add -D stylefmt
$ prettier-stylelint --write src/test.css
prettier-eslintから着想を得たらしい、prettier-stylelintがあるが、2018-03-30時点ではCLIでは整形されるものの、エラー終了しているのでVimプラグインでは変化しなかった。おそらく以下のエラーを吐いているから。
`{ "parser": "postcss" }` is deprecated. Prettier now treats it as `{ "parser": "css" }`.
- Warning:
parser
with value "postcss" is deprecated. Use "css", "less" or "scss" instead. - Cannot set property 'singleQuote' of null
Vim Setup
公式でいくつかのエディタに対応している旨が紹介されている。
Editor Integration
以下はVimの場合。
ALE
非同期でチェックが走るので、Syntasticなんかより軽い。設定項目が少なく、標準で多くの言語とツールに対応している。AirLineに対応している点もポイント高い。
[[plugins]]
repo = 'w0rp/ale'
hook_add = '''
let g:ale_fixers = {
\ 'javascript': ['prettier-eslint'],
\ 'css': ['stylelint'],
\ 'scss': ['stylelint'],
\}
" if you want to fix files automatically on save.
let g:ale_fix_on_save = 1
'''
Neoformat
シンプルで良さそうだったが、標準でstylelint --fix
に対応しておらず、標準出力の受け渡しまわりが巧くできなかった。ひとまず例として紹介しておく。
[[plugins]]
repo = 'sbdchd/neoformat.git'
hook_add = '''
"let g:neoformat_verbose = 1 " only affects the verbosity of Neoformat
" Enable tab to spaces conversion
let g:neoformat_basic_format_retab = 1
" Enable trimmming of trailing whitespace
let g:neoformat_basic_format_trim = 1
" js
let g:neoformat_javascript_prettiereslint = {
\ 'exe': './node_modules/.bin/prettier-eslint',
\ 'args': ['--stdin'],
\ 'stdin': 1,
\ }
let g:neoformat_enabled_javascript = ['prettiereslint']
" css
let g:neoformat_css_stylelint = {
\ 'exe': './node_modules/.bin/stylelint',
\ 'args': ['--stdin', '--fix'],
\ 'stdin': 1,
\ }
let g:neoformat_enabled_css = ['stylelint']
augroup fmt
autocmd!
autocmd BufWritePre *.js Neoformat
autocmd BufWritePre *.css Neoformat
autocmd BufWritePre *.scss Neoformat
augroup END