まくろぐ

VS Code の Explorer で特定のファイルやディレクトリを非表示にする (files.exclude)

更新:
作成:

VS Code のエクスプローラービューは、サイドバー上にプロジェクト内のファイル一覧を表示してくれる便利な機能ですが、編集対象ではないファイルまで表示されていると地味に邪魔だったりします。 例えば、Node.js アプリの node_modules ディレクトリなどは常に表示されていてもあまり役に立たないかもしれません。

/p/raku5dn/img-001.png
図: 不要なディレクトリが表示されている

このような場合は、設定ファイル (settings.json)files.exclude プロパティで非表示にしたいファイルやディレクトリのパターンを指定します。 どのようなグロブパターン(** など)が指定できるかは、Advanced search options のドキュメントが参考になります。

settings.json
{
  // Explorer で非表示にするもの
  "files.exclude": {
    "**/node_modules": true,
    "**/.next": true
  },
  // ...
}
/p/raku5dn/img-002.png
図: 指定したディレクトリが非表示になった

ちなみに、デフォルト設定では次のようなファイルとディレクトリが非表示になります。

{
  // Configure glob patterns for excluding files and folders.
  // For example, the file Explorer decides which files and folders
  // to show or hide based on this setting.
  // Refer to the `search.exclude` setting to define search specific excludes.
  "files.exclude": {
    "**/.git": true,
    "**/.svn": true,
    "**/.hg": true,
    "**/CVS": true,
    "**/.DS_Store": true
  },
  // ...
}

関連記事

Apollo Client の useQuery 呼び出し部分をカスタムフックで分離する

更新:
作成:

Apollo Client で GraphQL クエリを実行するときは、カスタムフックとして useQuery 関数の呼び出し部分を抽出すると、コンポーネント側のコードをシンプルにすることができます。

分離前のコード

次のサンプルコードでは、GraphQL クエリで GitHub のログインユーザー情報を取得して表示する Viewer コンポーネントを実装しています。 GraphQL のクエリ呼び出し部分や、取得したデータを ViewerData オブジェクトに詰める部分などが混在しており、あまり整理されているとは言えません。

components/Viewer.tsx
import { FC } from 'react'
import { gql, useQuery } from '@apollo/client'
import { LoadingComponent } from './LoadingComponent'
import styles from './Viewer.scss'

const GET_VIEWER = gql`
  query {
    viewer {
      login
      url
      avatarUrl
    }
  }
`

type ViewerData = {
  /** ログインID */
  login: string
  /** ホームページのURL */
  url: string
  /** アバター画像のURL */
  avatarUrl: string
}

/** 「ユーザー情報」を表示するコンポーネント */
export const Viewer: FC = () => {
  const {loading, error, data} = useQuery(GET_VIEWER)
  if (loading) return <LoadingComponent />
  const viewer: ViewerData = data.viewer

  return (
     <div className={styles.container}>
       <a href={viewer.url}><img src={viewer.avatarUrl}/></a>
     </div>
  )
}

こんなときは、カスタムフックを作成して、GraphQL クエリを実行する部分や、その結果を加工する部分などを分離するとコンポーネント側のコードがシンプルになります。

分離後のコード

下記の useViewer カスタムフックは、Apollo Client API の useQuery 呼び出し部分や、その戻り値のデータパース処理を実装しています。

☝️ カスタムフックとは 関数内部で useXxx 系のフック関数を呼び出すものをカスタムフックと呼びます。 カスタムフックは通常のフック関数と同様の制約を引き継ぐため、関数コンポーネント内では一定の順序で呼び出さないといけません。
hooks/useViewer.ts(カスタムフック)
import { gql, useQuery } from '@apollo/client'

export const QUERY_VIEWER = gql`
  query QueryViewer {
    viewer {
      login
      url
      avatarUrl
    }
  }
`

/** useViewer カスタムフックの戻り値の型 */
export type ViewerData = {
  /** ログインID */
  login: string
  /** ユーザーのホームページアドレス */
  url: string
  /** アバター画像のURL */
  avatarUrl: string
}

/** useQuery の戻り値 QueryResult の data プロパティの型 */
type Data = {
  viewer: ViewerData
}

/**
 * サインイン中の GitHub ユーザー情報を取得します。
 * ロード中やエラー時は undefined を返します。
 */
export function useViewer(): ViewerData | undefined {
  const { data } = useQuery<Data>(QUERY_VIEWER)
  return data?.viewer
}

ポイントは、useQuery の型パラメータとして Data 型を指定しているところです。 これにより、useQuery の戻り値の data プロパティの型が Data 型になります。

☝️ QueryResult インタフェース QueryResult インタフェースは、Apollo Client が定義している useQuery の戻り値の型です。 QueryResult オブジェクトの data プロパティは、デフォルトでは any 型ですが、QueryResult<ViewerData> のように型パラメータを指定すると、data プロパティを ViewerData 型として参照できるようになります。

この Data 型は、下記の GraphQL クエリに対応するプロパティを保持するよう定義する必要があります(この場合、Data 型は viewer プロパティを持つよう定義します)。

query {
  viewer {
    login
    url
    avatarUrl
  }
}

実際に useViewer カスタムフックを使う側が参照したいのは、この Data 型のデータではなく、そこに含まれている viewerViewerData オブジェクト)の方なので、res.data.viewer オブジェクトをリターンするようにしています。

下記は、このカスタムフックの使用例です。

components/Viewer.tsx(リファクタ後)
import { FC } from 'react'
import { LoadingComponent } from './LoadingComponent'
import { useViewer } from '../hooks/useViewer'
import styles from './Viewer.scss'


/** 「ユーザー情報」を表示するコンポーネント */
export const Viewer: FC = () => {
  const viewer = useViewer()
  if (!viewer) return <LoadingComponent />

  return (
    <div className={styles.container}>
      <a href={viewer.url}><img src={viewer.avatarUrl} /></a>
    </div>
  )
}

とてもシンプルですね! Viewer コンポーネントから GraphQL クエリの呼び出し部分などが取り除かれ、UI 表現に集中して実装できるようになりました。

useViewer フックは、データ取得前は undefined を返し、データ取得後に ViewerData オブジェクトを返すようにしているので、戻り値が undefined の場合は Loading 表示などを行えば OK です。

エラー情報やローディング状態を独立した変数で返して欲しいのであれば、カスタムフックの戻り値を次のように一段ラップすればよいです。

export type UseViewerOutput = {
  loading: boolean
  error?: ApolloError
  viewer?: ViewerData
}

export function useViewer(): UseViewerOutput {
  const { loading, error, data } = useQuery<Data>(QUERY_VIEWER)
  return { loading, error, viewer: data?.viewer }
}

(ただ、基本的にローディング中かどうかは viewer == undefined で判定できるので loading は必要ないはず)

関連記事

ESLint (4) ESLint の設定方法まとめ (for Next.js 11)

更新:
作成:

Next.js 11 が ESLint を組み込みサポート

Next.js 11 で ESLint を Next.js が組み込みでサポートしました。 これで、create-next-app で新規作成するアプリでは、ESLint に関してもゼロコンフィグで next eslint とするだけで実行できるようになります。

ただ、ESLint には色々な共有設定 (config) があるわけで、Next.js がデフォルトで設定してくれているもの以外(TypeScript や Prettier 関連)は自分で設定する必要があります。 ここでは、Next.js 11 がデフォルトで提供する .eslintrc にそれらの設定を追加します。

Next.js 11 デフォルトの ESLint 設定

Next.js 11 が生成する .eslintrc ファイルは次のようなシンプルなものです。

.eslintrc
{
  "extends": ["next", "next/core-web-vitals"]
}

問題はこれらがどのような共有設定を含んでいるかですが、eslint-config-next のコードを見ると、次のような感じになっています。

module.exports = {
  extends: [
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:@next/next/recommended',
  ],
  // ...
}

React 系の共有設定はここに含まれているので、"extends": ["next"] だけでカバーできそうです。 公式ドキュメントの ESLint - Base Configuration にも同様の説明が書かれています。 逆に、TypeScript 関連や、Prettier 関連の共有設定は自分で追加しなければいけません。

ESLint 設定を追加する

ここでは、下記のような ESLint extends 設定を手動で追加してやります。

  • ESLint 推奨 (eslint:recommended)
  • TypeScript 関連 (plugin:@typescript-eslint/recommended*)
  • Prettier 関連 (prettier)

eslint:recommeded 以外は外部パッケージとして提供されているので、先にインストールしておきます。

必要なパッケージ(Plugin & Config)のインストール
$ yarn add --dev @typescript-eslint/eslint-plugin
$ yarn add --dev eslint-config-prettier

そして、ESLint 設定ファイルを次のように書き換えてやります。 Yaml 形式の方が記述が楽なので、.eslintrc.eslintrc.yml に置き換えています。

.eslintrc.yml
# これがルートの設定ファイル(上位ディレクトリを検索しない)
root: true

extends:
  - eslint:recommended
  - plugin:@typescript-eslint/recommended
  - plugin:@typescript-eslint/recommended-requiring-type-checking
  - next
  - next/core-web-vitals
  - prettier

parserOptions:
  # extends で指定している
  # plugin:@typescript-eslint/recommended-requiring-type-checking
  # に対して型情報を提供するため tsconfig.json の場所を指定。
  project: ./tsconfig.json

あとは、next lint で実行すればよさそうですが、プロジェクト内の TypeScript 型情報に関する警告 (plugin:@typescript-eslint/recommended-requiring-type-checking) を有効にするには、eslint コマンドを直接実行しないといけないみたいです(next lint では全ての警告が出ない…)。

$ npx eslint src --ext .ts,.tsx

いずれにしても、最終的には、package.json の中で次のような感じで npm-scripts を定義して、yarn lint (npm run lint) コマンド一発で各種 Lint ツールをまとめて実行できるようにしておくのがよいです。

package.json(抜粋)
{
  "scripts": {
    // ...
    "lint": "run-p -c lint:prettier lint:eslint lint:tsc",
    "lint:prettier": "prettier --check src",
    "lint:eslint": "eslint src --ext .ts,.tsx",
    "lint:tsc": "tsc",
    "fix": "run-s fix:prettier fix:eslint",
    "fix:prettier": "prettier --write src",
    "fix:eslint": "eslint src --ext .ts,.tsx --fix",
    // ...

上記で使用している run-prun-s は、複数の npm-scripts を並列 or 順次実行するためのコマンドで、npm-run-allyarn-run-all パッケージをインストールすると使えるようになります。

$ yarn add yarn-run-all --dev

関連記事

メニュー

まくろぐ
サイトマップまくへのメッセージ