久々にReact触ったら色々変わっていたので改めて環境構築

最近は業務では自分で開発することがほとんどなくなってしまい、時流が分からなくなってしまった。
プライベートでなんかアプリ作って最近の流行りをキャッチアップしてみる。

npxってなんだ

とりあえずReactのドキュメントを読んでいて。注釈にも入っている。
どうやらrun-scriptを書かなくてもローカルのnode_moduleのバイナリを参照したり、インストールしていないものを一時的に使えるようになるらしい。
グローバルとローカルが異なるときとかは便利かも。

スクラッチで環境をつくる

CreateReactApp使ってしまうとモック作るのはいいけど細かいところの設定で結局ばらすので環境は自前で作りたい。

作った環境は下記で公開
https://github.com/umema4/react16_babel7_webpack4

公式からリンクされている記事を読んで環境構築
https://blog.usejournal.com/creating-a-react-app-from-scratch-f3c693b84658

初期設定

.gitignoreとREADMEは作成済み

npm init
mkdir public src

publicディレクトリに起点となるindex.htmlの作成

code public/index.html
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <title>React Starter</title>
</head>

<body>
  <div id="root"></div>
  <script src="../dist/bundle.js"></script>
</body>

</html>

babelの設定

記事中では7.1になっているけど2020/04ではバージョンがあがっているのでlatestにしておく

npm install --save-dev @babel/core@latest @babel/cli@latest @babel/preset-env@latest @babel/preset-react@latest

インストールされた最新バージョンは下記だった。

+ @babel/cli@7.8.4
+ @babel/preset-env@7.9.5
+ @babel/core@7.9.0
+ @babel/preset-react@7.9.4

babelの設定

code .babelrc
{
  "presets": ["@babel/env", "@babel/preset-react"]
}

webpackの設定

記事中では4.19になっているけど2020/04では4.42とあがっていたのでこちらもlatestdで。

npm install --save-dev webpack@latest webpack-cli@latest webpack-dev-server@latest style-loader@latest css-loader@latest babel-loader@latest

インストールされた最新バージョンは下記だった。
css-loaderが1.0=>3.5とえらい上がっている。
ベースの記事が2018/04。css-loaderのreleaseログみたら2018/12にv2がでてそこからいろいろと上がっている模様。
この先の設定で気を付けたほうがよいかも

+ style-loader@1.1.3
+ webpack-cli@3.3.11
+ webpack-dev-server@3.10.3
+ webpack@4.42.1
+ css-loader@3.5.2
+ babel-loader@8.1.0

webpack.configの設定。特に以前と変わっているところは無さそう。

code webpack.config.js
const path = require('path');
const webpack = require('webpack');

module.exports = {
  entry: './src/index.js',
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /(node_modules|bower_components)/,
        loader: 'babel-loader',
        options: {
          presets: ['@babel/env']
        }
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  },
  resolve: {
    extensions: ['*', '.js', '.jsx']
  },
  output: {
    path: path.resolve(__dirname, 'dist/'),
    publicPath: '/dist/',
    filename: 'bundle.js'
  },
  devServer: {
    contentBase: path.join(__dirname, 'public/'),
    port: 3000,
    publicPath: 'http://localhost:3000/dist/',
    hotOnly: true
  },
  plugins: [new webpack.HotModuleReplacementPlugin()]
};

Reactの設定

記事ではReact v16.5。このあたりから触っていないような。。。
最新だとv16.13なので環境以外にも機能面での差分を確認する必要がある。

npm install --save react@latest react-dom@latest
+ react@16.13.1
+ react-dom@16.13.1

エントリーポイントの設定

code src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.js';

ReactDOM.render(<App />, document.getElementById('root'));

ためにしに読み込ませるcomponentの作成

code src/App.js
import React, { Component } from 'react';
import './App.css';

class App extends Component{
  render(){
    return(
      <div className='App'>
        <h1> Hello, World! </h1>
      </div>
    );
  }
}

export default App;

CSSファイルも作る

code src/App.css
.App {
  margin: 1rem;
  font-family: Arial, Helvetica, sans-serif;
}

起動スクリプトの追加

package.jsonに追加する

  "scripts": {
    "start": "webpack-dev-server --mode development"
  },

あれ、npm script書いたほうが余計な記述少なそうだし、npx を使うパターンが見えない。。。

実行

npm run start

下記に接続できることを確認

http://localhost:3000/

この後、記事ではreact-hot-loader使うようにしているけどJSのコードにhotとか入れたくなかったのでwebpack dev serverの設定を変える。
reloadしてもかまわないのでhotOnlyをhotに変更

  devServer: {
    contentBase: path.join(__dirname, 'public/'),
    port: 3000,
    publicPath: 'http://localhost:3000/dist/',
-   hotOnly: true
+   hot: true
  },

ファイルの出力

dev server使っているので出力はされないので、ファイルと出力する部分も確認。
下記を追加

"scripts": {
  "build": "webpack --mode production"
}

distディレクトリがができていることを確認。
記事の記述はだいたいこれで終わりだけど、開発するのに足りないところを追加。

SourceMapを用意する

SourceMapがないとデバッグ面倒なのでSourceMapの設定を追加。

これも変わらずdevtoo: trueでよい模様。
ついでにprodの判定も追加しておく。

https://webpack.js.org/configuration/devtool/

const isDebug = process.env.NODE_ENV !== 'production';
console.log(`debug is ${isDebug}`);

module.exports = {
  mode: isDebug ? 'development' : 'production',
  devtool: isDebug ? 'source-map' : false,

これでreactを動かす環境は整った。次はLint系。

Lintの設定

eslint-config-airbnb

自分がメインで使っていたのはeslint-config-aribnb
repositoryを見るとまだactive。
調べると最近はPrettierなるものが流行っているらしい。eslint --fixだけでは足りないようだ。
こっちもeslint-config-prettierというものがあるとのこと。
star数をみるとairbnbのほうがまだ圧倒しているのでairbnbを使い修正にprettierを使うのでよさそうな気がする。

まずはUsageに従ってeslint-config-airbnbを導入

https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb

npx install-peerdeps --dev eslint-config-airbnb

おお。npxを使うタイミングが来た。
上のコマンドでdevDevenenciesに全部追加されてる。これは楽。

+ eslint-plugin-react@7.19.0
+ eslint-config-airbnb@18.1.0
+ eslint@6.8.0
+ eslint-plugin-react-hooks@2.5.0
+ eslint-plugin-import@2.20.2
+ eslint-plugin-jsx-a11y@6.2.3

babel-eslintからbabel-eslint-parserのはずが。。。

babelの設定忘れてた
babel-eslintの公式見たらbabelのmorepoに統合されてた。

https://github.com/babel/babel/tree/master/eslint/babel-eslint-parser

npm install --save-dev @babel/eslint-parser

installできないorz

npm ERR! 404 Not Found - GET https://registry.npmjs.org/@babel%2feslint-parser - Not found
npm ERR! 404 
npm ERR! 404  '@babel/eslint-parser@latest' is not in the npm registry.

仕方ないので従来のbabel-eslintを入れる

npm install  --save-dev babel-eslint

eslintはとりあえず初期として下記を設定

{
  "extends": [
    "airbnb"
  ],
  "parser": "babel-eslint",
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  }
}

とりあえずnpm scriptを追加して実行

    "eslint": "eslint ./src",

なんかエラーでた。

Warning: React version not specified in eslint-plugin-react settings. See https://github.com/yannickcr/eslint-plugin-react#configuration .

eslintrcでreactのバージョンの設定が必要とのこと

  "settings": {
    "react": {
      "version": "detect", // React version. "detect" automatically picks the version you have installed.
                           // You can also use `16.0`, `16.3`, etc, if you want to override the detected value.
                           // default to latest and warns if missing
                           // It will default to "detect" in the future
    },

prettier

次はprettierを入れる
調べた感じ下記のものを入れておくのが良さそう

npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier pretty-quick
+ pretty-quick@2.0.1
+ eslint-config-prettier@6.10.1
+ prettier@2.0.4
+ eslint-plugin-prettier@3.1.3

pretty-quickは変更されたファイルだけprettierを実行するので余計なことが起きない模様

eslintをアップデート
https://github.com/prettier/eslint-config-prettier
によるとairbnbと併用する場合はextendsでprettier/reactを設定する必要があるとのこと
eslint-plugin-prettierも入れてあるのでこんな感じか

+ "plugins": ["prettier"],
  "extends": [
+   "plugin:prettier/recommended",
+   "prettier/react""
  ],

試しに実行するとエラーが出た。

  1:34  error  Replace `'react'` with `"react"`          prettier/prettier
  2:8   error  Replace `'./App.css'` with `"./App.css"`  prettier/prettier
  4:28  error  Insert `・`                                prettier/prettier
  5:11  error  Insert `・`                                prettier/prettier
  6:11  error  Insert `・`                                prettier/prettier
  7:22  error  Replace `'App'` with `"App"`              prettier/prettier

single quotationとdouble quotationのエラーが出ている。これはsingleにしておきたいのでルールを変えたい

eslintに下記を追加

  "rules": {
    "prettier/prettier": [
      "error",
      {
        "singleQuote": true
      }
    ]
  }

fixのscriptを追加。自動で修正されると何が変わったかがわからなくなるので把握しておきたい
eslint-plugin-prettierを入れてあるので下記でまとめて修正がかかる(と理解している)

    "eslint:fix": "eslint --fix ./src",

エラーが修正されることを確認

CSS loaderは何か変わったのか

前述の通り、CSS loaderのバージョンが大きく変わっている。
release note見ると大き目の話は

  • cssの中でimportができるようになってる
  • urlの扱いが変わったぽい
  • @valueで変数定義できるようになった
    というところだろうか

個人的には従来通りlocal使ってscope管理できる設定が使えればそこまで困らない。
CSS modulesを有効にする必要がある。
下記の設定を追加

    {
      loader: 'css-loader',
      options: {
        modules: true,
      },
    },

こんな感じになる。

<div class="_1o-FpbQrR11SDFN-G7O4U3"><h1> Hello, World! </h1></div>

debugしにくいのでlocalIdentNameを設定。設定方法が以前と変わっていた。modulesに追加するようになったようなので
下記のように変更

    {
      loader: 'css-loader',
      options: {
        modules: {
          localIdentName: isDebug
            ? '[path][name]__[local]'
            : '[hash:base64:8]',
        },
      },
    },

指定したclassがわかるようになった

<div class="src-App__App"><h1> Hello, World! </h1></div>

自分の以前のprojectみたらpostcss-loaderも使っていた。
css-nanoを設定している。
githubの更新は2年くらい止まっているみたい。
cssnanoの公式では

Webpack
You can use cssnano explicitly with postcss-loader.

とされているのでそのまま設定するのでよさそう

npm install --save-dev cssnano postcss-loader

z-indexはいじることあるので下記の設定しておく
css-loaderでsourcemap有効にしておけばcasnano使ってもたどれるのでpostcssでは設定不要のようだ

    {
      loader: 'postcss-loader',
      options: {
        plugins: () => [
          require('cssnano')({
            zindex: false,
          }),
        ],
      },
    },

style-lintも入れておく

npm install --save-dev stylelint stylelint-config-recommended
code .stylelintrc.json

{
  "extends": "stylelint-config-recommended"
}

lint実行したらエラーが発生。versionは13.3.2

const { isPathValidisPathValid } = require('ignore').default;
TypeError: Cannot destructure property 'isPathValid' of 'require(...).default' as it is undefined.

バージョン変えるとstylelint12はOKで13はNG
nodeのサポートが変わった影響?手元の環境はnode12なのだがisPathValidisPathValidがなくなったのだろうか
とりあえずstylelint@12.0.1を入れておく

css-loadでlocalを設定するようにしたのでselector-pseudo-class-no-unknownのエラーが発生
ruleを追加しておく

    "selector-pseudo-class-no-unknown": [true, {
      "ignorePseudoClasses": ["local"]
    }]

出力ファイルを分割しておく。

3rd partyと自前のものを分割しておきたいので下記の設定を導入

https://webpack.js.org/plugins/split-chunks-plugin/#split-chunks-example-2

before

        Asset      Size  Chunks                   Chunk Names
    bundle.js  1.33 MiB    main  [emitted]        main
bundle.js.map  1.53 MiB    main  [emitted] [dev]  main

after

                Asset      Size   Chunks                   Chunk Names
            bundle.js  66.4 KiB     main  [emitted]        main
        bundle.js.map  63.2 KiB     main  [emitted] [dev]  main
    vendors.bundle.js  1.27 MiB  vendors  [emitted]        vendors
vendors.bundle.js.map  1.47 MiB  vendors  [emitted] [dev]  vendors

precommitフック

flowtype

テスト系が残っているけどとりあえず動かせる環境はやっと用意できた。

知らなったReactの機能

react-hooks

commit前にlint実施してエラーがあればcommitしないようにする。

自動でfixまでしてまうと自分でわからなくなりそうなのでlintまでにしておく

npm i --save-dev husky lint-staged

lint-stagedの書き方変わってる。lintersが不要になってる。

brfore

  "lint-staged": {
    "linters": {
      "*.js": "eslint",
      "*.css": "stylelint"
    },
  },

after

  "lint-staged": {
    "*.js": "npm run eslint",
    "*.css": "npm run stylelint"
  },

1件のコメント

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

five × 4 =