delhi09の勉強日記

技術トピック専用のブログです。自分用のメモ書きの投稿が多いです。あくまで「勉強日記」なので記事の内容は鵜呑みにしないでください。

【Reactの勉強】JSのimport/export時のESLintのエラー対応

概要

前回に引き続き、以下の日本大学文理学部情報科学科の教授の方がクリエイティブ・コモンズで公開してくださっているチュートリアルをやっていく。

zenn.dev

今回は「サーバーからのデータ取得」のセクションをやっていたところ、JSのimport/exportの書き方でESLintでエラーが出て対応したのでメモ。

バージョン

「Reactの勉強」で使用している主なソフトウェアのバージョンは以下の通り。

  • node: 15.5.0
  • react-create-app: 4.0.1
  • react: 17.0.1
  • react-dom: 17.0.1
  • typescript: 4.1.3
  • eslint: 7.17.0
  • prettier: 2.2.1
  • stylelint: 13.8.0

結論

以下のように書かないとESLintでエラーになった。

  • 「src/api.ts」では「default export」を使用する。
  • 「src/App.tsx」では波括弧を使わずにfetchImages関数をimportする。

具体的なコードは以下

[src/api.ts]

const fetchImages = async (breed: string): Promise<string[]> => {
  // 省略
};
export default fetchImages;

[src/App.js]

import fetchImages from './api';

詳細

exportについて

まず、チュートリアルと同じく以下のように、関数宣言の前にexportをつけると、ESLintで「Prefer default export.」というエラーが出てしまう。

export const fetchImages = async (breed: string): Promise<string[]> => {
  // 省略
};

f:id:kamatimaru:20210126231953p:plain

では、「default」を付ければよいのかというとそういう訳ではなかった。

以下のstack overflowの記事にもあるように、export default constという構文はシンタックスエラーになってしまう。

stackoverflow.com

従って、以下のように、ファイルの最後でexport defaultする必要があった。
こうすると、ESLintのエラーが出なくなる。

const fetchImages = async (breed: string): Promise<string> => {
  // 省略
};
export default fetchImages;

importについて

チュートリアルと同じく以下のように、波括弧でモジュールをimportするとESLintで以下のエラーが発生する。

import { fetchImages } from './api';

f:id:kamatimaru:20210126233316p:plain

デフォルトエクスポートされたモジュールをimportする場合は、モジュール名を波括弧で囲ってはいけないらしい。

以下のように波括弧を外すとエラーが消える。

import fetchImages from './api';

以下、Mozillaの公式ドキュメント
developer.mozilla.org

以上

【Reactの勉強】チュートリアルをやってみる(「条件分岐」まで)

概要

前回で最低限の環境構築が完了したので、以下の日本大学文理学部情報科学科の教授の方がクリエイティブ・コモンズで公開してくださっているチュートリアルをやっていく。

zenn.dev

今回は、「条件分岐」のセクションまでやったので感想・変更点・ハマったことなどを書く。

また、適宜、以下の本を参考にさせて頂きながら進める。(以下、『りあクト!』)

oukayuka.booth.pm

バージョン

「Reactの勉強」で使用している主なソフトウェアのバージョンは以下の通り。

  • node: 15.5.0
  • react-create-app: 4.0.1
  • react: 17.0.1
  • react-dom: 17.0.1
  • typescript: 4.1.3
  • eslint: 7.17.0
  • prettier: 2.2.1
  • stylelint: 13.8.0

感想・変更点・ハマったことなど

react-scriptsの設定について

私は、『りあクト!』に従って、「Create React App」で環境を構築したが、チュートリアルの方は「Create React App」使わずに

  • react
  • react-dom
  • react-scripts

をインストールする手順になっていた。
その際に、package.jsonscriptsに以下を登録していた。

"scripts": {
    "build": "react-scripts build",
    "start": "react-scripts start"
}

私の環境を確認したところ、package.jsonには既に以下の設定がされていた。

"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },

今まで特に意識していなかったが、npm startと打っただけで画面が起動するのは、「Create React App」がこれらのコマンドを登録しておいてくれているからなんだと勉強になった。

FunctionComponentを使ってみた

コンポーネントの分割」のセクションのところで、『りあクト!』の8章で紹介されている「FunctionComponent」の書き方を使ってみた。

「FC」をimportする。

import React, { FC } from 'react';

例えば「Header」コンポーネントの場合は以下のように書ける。

const Header: FC = () => {
  return (
    <header className="hero is-dark is-bold">
      <div className="hero-body">
        <div className="container">
          <h1 className="title">Cute Dog Images</h1>
        </div>
      </div>
    </header>
  );
};

型を定義する

元のチュートリアルの方ではTypeScriptを使用していないので、サンプルコードでは型を定義していない。

私はTypeScriptで開発環境を構築しており、ESLintも導入しているので、型を定義しないとESLintでエラーが発生してしまう箇所があった。

例えば、Galleryコンポーネントのpropsに画像のURLのリストを渡す箇所では、以下のように型情報を定義した。

Galleryコンポーネントのpropsの型を定義する。

type GalleryProps = {
  urls: string[];
};

Galleryコンポーネントのpropsに型情報を付与する。

const Gallery: FC<GalleryProps> = (props) => {
  const { urls } = props;
  // 省略
};

mainタグを知らなかった

チュートリアルでmainタグというのが使われているが、今まで使ったことなかったのと、そもそも存在自体を知らなかったので、こんなのあるんだという感じだった。

developer.mozilla.org

成果物

まだチュートリアルの途中だが、ここまでの段階で以下のようなアプリがローカルで動いた。

f:id:kamatimaru:20210112015451p:plain

以上

【Reactの勉強】環境構築(stylelintの設定)

概要

前回に引き続き、環境構築を行う。
今回はCSSのLinterであるstylelintを設定する。

stylelint.io

適宜、以下の本を参考にさせて頂きながら進める。(以下、『りあクト!』)

oukayuka.booth.pm

バージョン

「Reactの勉強」で使用している主なソフトウェアのバージョンは以下の通り。

  • node: 15.5.0
  • react-create-app: 4.0.1
  • react: 17.0.1
  • react-dom: 17.0.1
  • typescript: 4.1.3
  • eslint: 7.17.0
  • prettier: 2.2.1
  • stylelint: 13.8.0

stylelintを設定する。

インストール

以下のコマンドでstylelint及び関連するモジュールをインストールする。

$ npm install -D stylelint
$ npm install -D stylelint-config-standard
$ npm install -D stylelint-order
$ npm install -D stylelint-config-recess-order

stylelintの設定ファイルの作成

.stylelintrc.js というファイルを作成する。

.stylelintrc.js の中にstylelintの設定を記述する。

設定に関しては、以下の『りあクト!』の作者の方がGitHubに公開してくださっている設定を、それぞれの意味を簡単に確認しながらコピペしていく。(解説は本の方を参照。)

github.com

※ stylelintの方は割とシンプルで、ESLintのような複雑な設定ではなかった。

VS Codeと連携する。

stylelint.vscode-stylelintというプラグインをインストールする。

f:id:kamatimaru:20210111031532p:plain

settings.jsoneditor.codeActionsOnSave"source.fixAll.stylelint": trueを追加する。

{
    "typescript.tsdk": "./node_modules/typescript/lib",
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true,
        "source.fixAll.stylelint": true 
    }
}

動作確認

VS Codeでindex.cssを開いて、保存した際にフォーマットされることが確認できればOK。

【Reactの勉強】環境構築(ESLintのエラーを解消する)

概要

前回に引き続き、環境構築を行う。
今回はESLintのエラーを解消する。

適宜、以下の本を参考にさせて頂きながら進める。(以下、『りあクト!』)

oukayuka.booth.pm

バージョン

「Reactの勉強」で使用している主なソフトウェアのバージョンは以下の通り。

  • node: 15.5.0
  • react-create-app: 4.0.1
  • react: 17.0.1
  • react-dom: 17.0.1
  • typescript: 4.1.3
  • eslint: 7.17.0
  • prettier: 2.2.1

ESLintのエラーを解消する

create-react-appで生成されたコードには、ESLint違反のコードが含まれていた。
ESLintを導入したことによって、以下のようにビルドが失敗するようになってしまったので、ESLintのエラーを解消していく。

f:id:kamatimaru:20210107210357p:plain

出ているエラーは以下の2つである。

  1. 'React' was used before it was defined no-use-before-define
  2. Promises must be handled appropriately or explicitly marked as ignored with the `void` operator @typescript-eslint/no-floating-promises

1のエラーについて

App.tsxindex.tsx

import React from 'react';

という一文のところで、

'React' was used before it was defined no-use-before-define

というエラーが出ていた。

これに関しては、

  • 根本原因が分からなかった。
  • 以下のようにReact1.7以降ではそもそも、import React from 'react';の一文自体がいらないというような情報もあったが、消してみたらさらにエラーが増えて動かなくなった。

github.com
zenn.dev


というようなことがあったが、とりあえず以下のissueのコメントの通り、.eslintrc.jsrulesに以下の2行を追加したところエラーを抑制できた。

'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': 'warn',

github.com

根本原因が分からないのは気持ち悪いが、今はとりあえずチュートリアルを早くやってみたいので、いったんこれでよしとする。

2のエラーについて

reportWebVitals.tsの以下のコードのところで

Promises must be handled appropriately or explicitly marked as ignored with the `void` operator @typescript-eslint/no-floating-promises

というエラーが出ていた。

const reportWebVitals = (onPerfEntry?: ReportHandler) => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      getCLS(onPerfEntry);
      getFID(onPerfEntry);
      getFCP(onPerfEntry);
      getLCP(onPerfEntry);
      getTTFB(onPerfEntry);
    });
  }
};

これに関しては、以下のstackoverflowにも同じ質問があった。

stackoverflow.com

Promise文を使っているのに最後がcatchで終わっていないという警告のようであり、

  1. thenの後にcatchをつける。
  2. 関数の戻り値のtypeにvoidを明示する。

のどちらかで解消するようだった。

2の方で対応しようと思ったが、ES6・TypeScript初心者なので、このコードをみてパッとどこにvoidを書いたら良いのか分からず(このimportの使い方はなんだ?って感じだった。)、VS CodeのQuick Fix機能を使った。

f:id:kamatimaru:20210107212532p:plain

すると、コードが以下のように修正されて、ESLintのエラーも消えた。

const reportWebVitals = (onPerfEntry?: ReportHandler) => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    void import('web-vitals').then(
      ({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
        getCLS(onPerfEntry);
        getFID(onPerfEntry);
        getFCP(onPerfEntry);
        getLCP(onPerfEntry);
        getTTFB(onPerfEntry);
      },
    );
  }
};

ビルドが成功するようになった。

上の二つのエラーを抑制 or 解消したところ、再度ビルドが成功するようになった。

f:id:kamatimaru:20210107213104p:plain

以上

【Reactの勉強】環境構築(Prettierの設定)

概要

前回に引き続き、環境構築を行う。
今回はPrettierの設定を行う。

prettier.io

適宜、以下の本を参考にさせて頂きながら進める。(以下、『りあクト!』)

oukayuka.booth.pm

バージョン

「Reactの勉強」で使用している主なソフトウェアのバージョンは以下の通り。

  • node: 15.5.0
  • react-create-app: 4.0.1
  • react: 17.0.1
  • react-dom: 17.0.1
  • typescript: 4.1.3
  • eslint: 7.17.0
  • prettier: 2.2.1

設定

Prettierをインストールする

以下のコマンドを実行してPrettierをインストールする。

$ npm install -D prettier
$ npm install -D eslint-plugin-prettier
$ npm install -D eslint-config-prettier

typesyncを実行する。

$ node_modules/typesync/bin/typesync

.eslintrc.jsにPrettierの設定を追加する。

以下の作者の方のリポジトリを見ながら、.eslintrc.jsにPrettierの設定を追加する。

github.com

.prettierrcを作成・設定する。

同様に、以下の作者の方のリポジトリを見ながら、.prettierrcというPrettierの追加設定用のファイルを作成・設定する。

github.com

ESLintとPrettierが衝突していないかの確認

本には以下のコマンドで確認できると書いてあったが、公式ドキュメントによると、eslint-config-prettierのバージョン7.0.0移行ではこのやり方ではないらしい。(私の環境のバージョンは7.1.0)

$ npx eslint --print-config .eslintrc.js | npx eslint-config-prettier-check

github.com

バージョン7.0.0以降では、任意の対象ファイルに対して以下のコマンドを実行するようである。

$ npx eslint-config-prettier path/to/main.js

※ 原理的には全ての対象ファイルに対して上記のコマンドを実行しないと、衝突していないことを100%担保したとはいえないが、フォーマットルールが共通なら、1ファイルサンプリングして実行してOKなら良いのでは?とのことのようである。

In theory you need to run the tool for every single file in your project to be 100% sure that there are no conflicting rules, because ESLint supports having different rules for different files. But usually you’ll have about the same rules for all files, so it is good enough to run the command on one file. But if you use multiple configuration files or overrides, you can provide several files check:

github.com

試しに以下の2ファイルに対して実行してみたが、衝突はなかった。

$ npx eslint-config-prettier index.tsx App.tsx
No rules that are unnecessary or conflict with Prettier were found.

VS Codeに自動フォーマットを設定する。

VS Codesettings.jsonに以下を設定する。

"editor.codeActionsOnSave": {
    "source.fixAll.eslint": true 
}

動作確認

まずは、VS Code上でtsxファイルのフォーマットを適当に崩してみて、保存すると、フォーマットが実行されることを確認する。

上記でフォーマットされた場合でも、ESLintの標準のフォーマット機能でフォーマットされた可能性もあるので、例えば、.prettierrcのprintWidthの値を小さくした場合に、ファイルがより短い文字数で改行されるようになることを確認する。

→ 確認できたが、.prettierrcの変更は、VS Codeを一度再起動しないと反映されないようだった。即時反映する方法があったら知りたい。

とりあえず、VS Code上からフォーマットはできたので、以上

VS Codeが使用するTypeScriptを変更する

概要

Reactの環境構築中にVS Code上で「Cannot use JSX unless the '--jsx' flag is provided.」というメッセージのエラーが発生して解決方法を調査していた。

以下のissueと同じだと思われる。
github.com

その時に、エラーを解消する過程で、VS Codeでデフォルトで使われるTypeScriptは、プロジェクトでnpmでローカルインストールしたTypeScriptではないことを知ったのでメモ。(グローバルインストールの場合は分からない。)

なお、プロジェクトでnpmでローカルインストールしたTypeScriptを使用するように変更したら上記のエラーも解消した。

結論

  • VS Codeでデフォルトで使われるTypeScriptは、VS Codeに同封されているTypeScriptである。
  • プロジェクトでnpmでローカルインストールしたTypeScriptを使用したい場合は、以下のようにVS Codesettings.jsonを設定する必要がある。
{
  "typescript.tsdk": "./node_modules/typescript/lib"
}

詳細

前提

前提として、公式ドキュメントに以下のように記載されている通り、VS Codeでデフォルトで使われるTypeScriptは、自分でインストールしたTypeScriptではない。

It is important to keep in mind that VS Code's TypeScript language service is separate from your installed TypeScript compiler.

code.visualstudio.com

現在VS Codeが参照しているTypeScriptを確認する方法

これも、確認する方法が公式ドキュメントに記載されているが、任意のTypeScriptファイルをVS Codeで開くと、バージョンとTypeScriptのパスが画面右下に表示される。

f:id:kamatimaru:20210104102844p:plain

デフォルトで使われているTypeScriptの存在を確認する。

上記で確認したところ、VS Codeに内蔵されているv3.8.3のTypeScriptが使用されているようである。

そもそも、VS CodeにTypeScriptが内蔵されているということを知らなかったので、このTypeScriptが実際に存在するのか確認してみる。

$ cd /Applications/Visual\ Studio\ Code.app/Contents/Resources/app/extensions/
$ npm ls typescript
/Applications/Visual Studio Code.app/Contents/Resources/app/extensions
└── typescript@3.8.3 extraneous

→ 確かにVS Codeに内蔵されているTypeScriptが存在しており、バージョンも3.8.3であることが確認できた。

VS Codeで使用するTypeScriptを変更する。

プロジェクトでnpmでローカルインストールしたv4.1.3のTypeScriptを使用するように変更したいので、公式ドキュメントに従い以下のようにsettings.jsonに設定する。

{
  "typescript.tsdk": "./node_modules/typescript/lib"
}

code.visualstudio.com

※ 「Settings」画面で「typescript.tsdk」と検索すると、以下の画面が表示されるので、「Edit in settings.json」のリンクを押すと編集できる。

f:id:kamatimaru:20210104104846p:plain

変更されたことを確認する。

VS Codeを再起動した後に、再度、任意のTypeScriptのファイルを開いて、バージョンが変更されていることを確認する。

f:id:kamatimaru:20210104105235p:plain

以上

参考にさせていただいた記事など

公式ドキュメント以外に以下を参考にさせて頂いた。

typescript-jp.gitbook.io
github.com

【Reactの勉強】環境構築(ESLintの設定)

概要

前回に引き続き、環境構築を行う。
今回はESLintの設定を行う。

ESLintは現時点(2021年1月)における、JS界のデファクトスタンダードのLinterのようである。

eslint.org

適宜、以下の本を参考にさせて頂きながら進める。(以下、『りあクト!』)

oukayuka.booth.pm

バージョン

「Reactの勉強」で使用している主なソフトウェアのバージョンは以下の通り。

  • node: 15.5.0
  • react-create-app: 4.0.1
  • react: 17.0.1
  • react-dom: 17.0.1
  • typescript: 4.1.3
  • eslint: 7.17.0
  • prettier: 2.2.1

インストールされていることの確認

『りあクト!』によると、ESLintはcreate-react-appコマンド実行時にインストールされるreact-scriptsモジュールの中に含まれているとのことなので、インストール済みであることを確認する。

$ npm ls eslint
react_tutorial_nihon_u_1@0.1.0 /path/to/react_tutorial_nihon_u_1
└─┬ react-scripts@4.0.1
  ├─┬ @typescript-eslint/eslint-plugin@4.11.1
  │ ├─┬ @typescript-eslint/experimental-utils@4.11.1
  │ │ └── eslint@7.17.0 deduped
  │ └── eslint@7.17.0 deduped
  ├─┬ @typescript-eslint/parser@4.11.1
  │ └── eslint@7.17.0 deduped
  ├─┬ babel-eslint@10.1.0
  │ └── eslint@7.17.0 deduped
  ├─┬ eslint-config-react-app@6.0.0
  │ └── eslint@7.17.0 deduped
  ├─┬ eslint-plugin-flowtype@5.2.0
  │ └── eslint@7.17.0 deduped
  ├─┬ eslint-plugin-import@2.22.1
  │ └── eslint@7.17.0 deduped
  ├─┬ eslint-plugin-jest@24.1.3
  │ └── eslint@7.17.0 deduped
  ├─┬ eslint-plugin-jsx-a11y@6.4.1
  │ └── eslint@7.17.0 deduped
  ├─┬ eslint-plugin-react-hooks@4.2.0
  │ └── eslint@7.17.0 deduped
  ├─┬ eslint-plugin-react@7.22.0
  │ └── eslint@7.17.0 deduped
  ├─┬ eslint-plugin-testing-library@3.10.1
  │ ├─┬ @typescript-eslint/experimental-utils@3.10.1
  │ │ └── eslint@7.17.0 deduped
  │ └── eslint@7.17.0 deduped
  ├─┬ eslint-webpack-plugin@2.4.1
  │ └── eslint@7.17.0 deduped
  └── eslint@7.17.0

→ インストールされていることは確認できた。

ESLintの設定ファイルの作成

雛形の作成

以下のコマンドを実行して、ESLintの設定ファイルの雛形を生成する。

$ npx eslint --init

eslint.org

コマンドを実行すると、対話モードで用途に関する質問をいくつかされるので、原則『りあクト!』に紹介されているのと同じように回答していく。(第6章参照)

回答が完了すると、コマンドを実行したディレクトリ直下に.eslintrc.jsというファイルが生成されている。

この時に.eslintcacheというファイルも作成されるが、このファイルはGit管理の対象外にしたいかつ、create-react-appコマンドで生成された.gitignoreには含まれていないので、.gitignoreに以下の1行を追加する。

.eslintcache

設定のカスタマイズ

上記で生成された設定をカスタマイズする。

といっても、以下の『りあクト!』の作者の方がGitHubに公開してくださっている設定を、それぞれの意味を簡単に確認しながらコピペしていくだけである。(解説は本の方を参照。)
github.com

プラグインに関しては、以下の3つを追加している。

www.npmjs.com
www.npmjs.com
github.com

本の方ではyarnを使用しているので、.eslintrc.jsに追加したモジュールをyarnでインストールしているが、npmを使用している場合はnpx eslint --init実行時にpackage.jsonにも追加されるようなので、手でインストールする必要はなかった。

型定義ファイルが存在する場合は追加するためにtypesyncを実行する。

$ node_modules/typesync/bin/typesync

typesyncをローカルインストールするとpathが通らないので、node_modules配下のpathを明示しないといけないことに気づいた。

VS CodeとESLintを連携する。

marketplaceを検索して、以下の「dbaeumer.vscode-eslint」というextensionをインストールする。

f:id:kamatimaru:20210103202102p:plain

デフォルトの設定値をみた感じ、特に設定値の変更は不要そうだった。
(実際に開発してみて、変更が必要な設定値があったら追記・修正します。)

以上