Webpack4でReactの環境構築。Create react appを使わずにReactアプリを作る。- 3-Prettier, stylelint, Husky, Url loader, Style loader -
【所要時間】
9時間(2019年2月13日)
【概要】
- 第三弾はとりあえずReactを開発環境と本番環境でデプロイ出来るようにする方法にフォーカス
今回設定したのは
- コード整形にPrettier(それに伴うESLintの設定)
- Sass, CSSのLinterにstylelint
- コミット前にESLintとstylelintでコードをチェックし、問題がある場合はコミットさせないためのlint-staged, Husky
- 画像をアップロードするのためurl-loader, file-loader
レポジトリ
- 理解できてるかまだわからないので、間違ってたらご指摘いただきたいです。
【要約・学んだこと】
Prettierのインストール・設定
Prettierはコード整形するためのツール。例えば配列とかを横に長く書いていると、改行して見やすくしてくれる。
- Prettier: コードスタイル違反を指摘、修正してくれる。
- ESLint: コードを実行する前に問題のありそうな箇所を指摘する。スタイルを指摘、修正する機能もある。
ESLintしか使っていなかったが、強い人が設定してくれた環境で作業していた時に、セーブする度に修正してくれるのが便利だったので導入してみる。
- prettierをインストールする。
Prettier · Opinionated Code Formatter
Opinionated Code Formatter
Opinionated Code Formatterprettier.io
yarn add prettier --dev --exactESLintは
app.jsを下記のようにあえて変更してみる。
// src/components/app.jsimport React from 'react';
import { hot } from 'react-hot-loader';
import Test from './test';
import Counter from './counter' //セミコロンがない
import styles from "./appScss.scss"; //ダブルクオーテーションconst App = () => (
<div className={styles.app}>
<Counter />
<Test /><h2>これはh2</h2><p>ここはIndex</p><p>ここはIndex</p> //改行していない
</div>
);export default hot(module)(App);
早速実行してみる。
import React from 'react';
import { hot } from 'react-hot-loader';
import Test from './test';
import Counter from './counter';
import styles from './appScss.scss';const App = () => (
<div className={styles.app}>
<Counter />
<Test />
<h2>これはh2</h2>
<p>ここはIndex</p>
<p>ここはIndex</p>
</div>
);export default hot(module)(App);
修正された。
- セーブするたびに自動修正されるようにする。
見えないところで修正されるのは何となく怖いし、どこが悪いかその場でわかった方がいいので、onSaveを設定する。これはエディタの設定になる。
VSCodeを使っているので、下記を参考に設定。
分かりにくかったが、VS CodeのsettingsのSearch settingsバーに editor.formatOnSavと入力すると設定できる。
共通設定とワークスペースごとの設計もできるようだが、基本的に使いたいのでUser Settingで設定する。
これでセーブすると自動で補正される。
細かい設定は後ほど。
stylelintのインストール・設定
cssのLinter。scss用のプラグインも合わせてインストール。
まずはインストール。
yarn add -D stylelint stylelint-scss
とりあえずcssファイルに向かって実行してみるが、設定しろと出てくる。
$ ./node_modules/.bin/stylelint stylelint src/index.css
Error: No configuration provided for C:\Users\tatsuya.asami\my-app\webpackori\src\index.css
at module.exports (C:\Users\tatsuya.asami\my-app\webpackori\node_modules\stylelint\lib\utils\configurationError.js:8:28)
at searchForConfig.then.then.config (C:\Users\tatsuya.asami\my-app\webpackori\node_modules\stylelint\lib\getConfigForFile.js:55:15)
- stylelintの設定をインストール
stylelint-recommendedと stylelint-config-standardがあるが、standardの方が追加ルールがある(厳しいらしい)ので、そちらにしてみる。
インストール
yarn add -D stylelint-config-standard
configファイルを作成
// stylelint.config.jsmodule.exports = {
extends: "stylelint-config-standard",
plugins: ["stylelint-scss"]
};
実行。実行したいファイルはダブルクオテーションで囲う必要がある。
./node_modules/.bin/stylelint stylelint "src/components/*.scss"
動作しているようだ。
7:3 × Expected empty line before rule rule-empty-line-before
11:3 × Expected empty line before rule rule-empty-line-before
14:3 × Expected empty line before at-rule at-rule-empty-line-before
14:3 × Unexpected unknown at-rule "@include" at-rule-no-unknown
下記のコードで警告が出ている。
// src/components/appScss.scss@import "../styles";.app {
color: red;
p {
background-color: yellow;
color: red;
}
h2 {
color: $brown;
}
@include button;
}
上記のコードと設定を修正する。
コードの変更
// src/components/appScss.scss@import "../styles";.app {
color: red;p {
background-color: yellow;
color: red;
}h2 {
color: $brown;
}@include button;
}
設定ファイルも変更。
// stylelint.config.jsmodule.exports = {
extends: "stylelint-config-standard",
plugins: ["stylelint-scss"],
rules: {
"at-rule-no-unknown": null
}
};
これでエラーは消えた。(stylelint-config-standarどstylelint-scss入れてるのに@includeが出るのは悲しい。)
細かい設定はまた後ほど。
PrettierとESLint, stylelintの設定をする。
現在のままでよさそうな気がしていたが、prettierとESLint, stylelintが競合してしまうことがあるので、設定した方がいいそう。
- ESLintとPrettierの設定
prettier/eslint-plugin-prettierを導入する。あわせてprettier/eslint-config-prettierを導入する。(公式ドキュメントの推奨設定になっている。)
- eslint-plugin-prettier: ESLintルールを適用してPrettierを実行する。
- eslint-config-prettier: Prettierとコンフリクトする可能性があるルールや、不要なルールをオフにする。
eslintの設定を修正する。
// .eslintrc.jsmodule.exports = {
extends: [
// 'airbnb',
'eslint:recommended',
'plugin:react/recommended',
'plugin:prettier/recommended',
'prettier/react'
],
parser: 'babel-eslint',
globals: {
module: true,
document: true,
require: true,
__dirname: true
},
plugins: ['prettier'],
rules: {
'prettier/prettier': ['error', { singleQuote: false}]
}
};
globalsを宣言する前に出ていた警告は、prettier
警告が出ているcounter.jsを見てみる
import React from 'react';
import { hot } from 'react-hot-loader';class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
number: 1,
};this.clickHandler = this.clickHandler.bind(this);
}clickHandler() {
const increment = this.state.number + 1;
this.setState({
number : increment
});
}render() {
return (
<div>
<h3>{this.state.number}</h3>
<button type='button' onClick={this.clickHandler}>click</button>
<button type='button' onClick={this.clickHandler}>click</button>
</div>
);
}
}// export default Counter;
export default hot(module)(Counter);
ここでセーブをしてみると
下記のように修正された。
import React from "react";
import { hot } from "react-hot-loader";class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
number: 1
};this.clickHandler = this.clickHandler.bind(this);
}clickHandler() {
const increment = this.state.number + 1;
this.setState({
number: increment
});
}render() {
return (
<div>
<h3>{this.state.number}</h3>
<button type="button" onClick={this.clickHandler}>
click
</button>
<button type="button" onClick={this.clickHandler}>
click
</button>
</div>
);
}
}// export default Counter;
export default hot(module)(Counter);
シングルクオテーションの方がいいので、そのルールを変更してみる。
ESLintの設定ファイルにオプションルールを加えてもいいが、prettier-vscodeが読み込むのは.prettierrcなので、そちらにルールを加えた方がいい。そのため.prettierrcファイルを作成する。
// .prettierrc{
"singleQuote": true,
"semi": true,
"trailingComma": "es5"
}
こう設定してセーブするとシングルクオテーションになる。
が、コンマにESLintの警告がでる。つまり設定がコンフリクトしている。
なぜ?ESLintの設定が無視されるのでは?と思ったが、コード整形をする上での話だと思うので、ESLintの設定(警告の設定)と、Prettierの設定(コード整形の設定)を合わせる。シングルクオーテーションと、最後のコンマはない方がいいので、下記のようにする。
// .eslintrc.jsmodule.exports = {
extends: [
// 'airbnb',
'eslint:recommended',
'plugin:react/recommended',
'plugin:prettier/recommended',
'prettier/react'
],
parser: 'babel-eslint',
globals: {
module: true,
document: true,
require: true,
__dirname: true
},
plugins: ['prettier'],
rules: {
'prettier/prettier': ['error']
}
};
prettierの方は
{
"singleQuote": true,
"semi": true
}
これで警告が消える。
- stylelintとPrettierの設定
ESLintと同様に、stylelint-prettierと、stylelint-config-prettierをインストール。stylelint-plugin-prettierはもう使えないので、stylelint-prettierを使う点のに注意。
まずはインストール
yarn add -D stylelint-prettier stylelint-config-prettier
stylelintの設定を修正。
// stylelintrcmodule.exports = {
extends: ['stylelint-config-standard', 'stylelint-prettier/recommended'],
plugins: ['stylelint-scss', 'stylelint-prettier'],
rules: {
'at-rule-no-unknown': null,
'prettier/prettier': true
}
};
vs-code用のstylelintもあるようだが、あまりメジャーではないようなのでインストールしないでおく。
ESLintではやらなかったが、VScodeのStylelint Integrationをオンにする。
これでセーブするときにcss, scssなどのファイルが修正された。(よくわかっていない。)
- ESLint, PrettierのScriptを設定する。
コマンドラインからESLint, Prettierを実行できるようにする。
// package.json"scripts": {
"start": "webpack-dev-server --hot --mode development --open",
"build": "webpack --config webpack.config.js",
"eslint": "eslint \"src/**/*.{js,jsx}\"",
"stylelint": "stylelint src/**/*.*"
},
Pre-commitの設定
commitする前にESLint, StyleLintを走らせるようにし、問題がある場合はコミットできないようにしたい。
lint-stagedとhuskyを導入する。
まずはインストール
yarn add -D lint-staged husky
package.jsonに追記する。
// package.json...
},
"resolutions": {
"ajv": "6.8.1"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,jsx}": [
"eslint --fix",
"git add"
]
}
}
警告が出ている状態でコミットしてみる。
コミットできない。
うまく動作しているので、css, scssにも適用する。
自動でfixされるのもなんか怖いので、 — fixははずす。
// package.js
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,jsx}": [
"eslint",
"git add"
],
"*.{css,scss}": [
"stylelint",
"git add"
]
}
}
scssに余分な文字を入れてみると、ちゃんとエラーが出る。
これでOK
url-loaderのインストール・設定
ちょっと調べてもどうすればいいのかよくわからなかったが、webpackで静的ファイル(jpg, png形式の画像ファイルなど)を扱うにはurl-loaderとを使えばよい。Create-React-APPのページによると、10,000バイト以下のサイズのデータはURLを返すらしい。
まずはインストール
yarn add -D url-loader
webpackの設定。
// webpack.config.jsmodule: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.(css|scss)$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[name]_[local]_[hash:base64]'
}
},
{
loader: 'sass-loader'
// options: {
// modules: true,
// localIdentName: "[name]_[local]_[hash:base64]",
// }
}
]
},
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
}
]
},
src/images/boy.jpgを追加。
app.jsにimgタグを追加。
// src/components/app.js/*global module */import React from 'react';
import { hot } from 'react-hot-loader';
import Test from './test';
import Counter from './counter';
import styles from './appScss.scss';
import boy from '../images/boy.jpg';const App = () => (
<div className={styles.app}>
<Counter />
<Test />
<h2>これはh2</h2>
<p>ここはIndex</p>
<p>ここはIndex</p>
<img src={boy} width={300} height={300} />
</div>
);export default hot(module)(App);
これで実行するもurl-loader単体だと上手くいかなかった。file-loaderがいるらしい。
ERROR in ./src/images/boy.jpg
Module build failed (from ./node_modules/url-loader/dist/cjs.js):
Error: Cannot find module 'file-loader'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:581:15)
at Function.Module._load (internal/modules/cjs/loader.js:507:25)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (internal/modules/cjs/helpers.js:20:18)
at Object.loader (/Users/AsamiTasuya/my-app/webpackori/node_modules/url-loader/dist/index.js:68:20)
@ ./src/components/app.js 12:0-36 18:9-12
@ ./src/index.js
@ multi (webpack)-dev-server/client?http://localhost:8080 (webpack)/hot/dev-server.js ./src/index.js
file-loaderをインストールする。
yarn add -D file-loader
そして設定などはいじらず再度実行すると
上手くいった。共に笑ってくれる仲間もいる!
最後にbuildしても上手くいった!やったぜ!と思ったら、コミットしても進まない。vs codeからではなくターミナルからコミットしてみると、ESLintがbundle.jsをチェックするところで止まっている。
そこで.eslintignore fileを作成。
// .eslintignore/pubic
これでコミットできた。
【わからなかったこと】
- prettierとstylelintの設定がうまくいっているのかわからない。ESLintではVS codeの設定でESLint Integrationをオンにしていないが、セーブするたびに補正される。その代わりVS codeにESLintをインストールしている。
一方style lintは、VS codeの設定でStylelint Integrationをオンにしているが、VS codeにstylelintはインストールしていない。
【感想】
途中で色々直していたので、記事の生合成が取れてるか怪しくなってしまった。大きくハマった箇所はないのに結構時間がかかった。
これで一通りReactの開発、デプロイに必要なdependenciesがインストール、設定できたはず。
ブラックボックスだらけになってしまったが、一つづつ試したおかげで、違うパターンでの開発でも今回より早く設定できるはず。
怪しい部分は、
- React-hot-loader: stateがキープされない。わかる範囲で確認。
- ESLintがターミナルから実行した時と、エディタ上で同じ警告を出しているか。
- html-webpack-pluginが怪しい。
- ESLintの設定。とりあえずairbnbの設定に完全に従って、コード書いてるときにどうしようもなくなったらまた考えればいいのかな?
という感じ。