1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

JAMStack作成の軌跡Part2

Posted at

はじめに

TypeScriptの導入

GatsbyにはデフォルトでTypeScriptに対応しているが、型チェックの恩恵を十分に得られないため、DX(Developer Experience)を向上させるために追加の設定を行っていく。

tsconfig.jsonの作成

{
  "include": ["./src/**/*"], // コンパイル対象
  "compilerOptions": {
    "target": "esnext", // 出力するjsのバージョン
    "module": "esnext", // 出力するjsのモジュール
    "lib": ["dom", "es2017"], // コンパイルする際に使用する組み込みライブラリ
    "jsx": "react", // tsxファイルの出力形式
    "esModuleInterop": true, // CommonJSモジュールのインポートをサポートする
    "forceConsistentCasingInFileNames": true, // 大文字小文字を区別して参照解決する
    "strict": true, // 型チェックをstrictモードにする
    "skipLibCheck": true, // 型定義ファイルの整合性チェックを行わない
    "noEmit": true, // コンパイル結果を出力しない
    "moduleResolution": "node"// tscのモジュール解決方法(新しい環境で行う場合はnodeを指定する)
  }
}

.js -> .tsxへ変更する

  • src/下の.jsファイルを.tsxに変更する
  • この状態でyarn developをしても問題なく動作するが静的解析の恩恵は得たい

ESLintの設定

  • JS のための静的検証ツール
  • Pythonのflake8みたいなやつ
yarn add -D eslint eslint-loader
yarn run eslint --init

# 以下、選択内容
? How would you like to use ESLint? … 
  To check syntax only
  To check syntax and find problems
❯ To check syntax, find problems, and enforce code style

? What type of modules does your project use? … 
❯ JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these

? Which framework does your project use? … 
❯ React
  Vue.js
  None of these
  
? Does your project use TypeScript? › No / [Yes]

? Where does your code run? …  (Press <space> to select, <a> to toggle all, <i> to invert selection)[Browser]
✔ Node

? How would you like to define a style for your project? … 
❯ Use a popular style guide
  Answer questions about your style
  Inspect your JavaScript file(s)
  
? Which style guide do you want to follow? … 
❯ Airbnb: https://github.com/airbnb/javascript
  Standard: https://github.com/standard/standard
  Google: https://github.com/google/eslint-config-google
  XO: https://github.com/xojs/eslint-config-xo
  
? What format do you want your config file to be in? … 
  JavaScript
  YAML
❯ JSON

? Would you like to install them now with npm? › No / [Yes]
  • この状態でyarn run eslint --fix "**/*.tsx"を実行すると大量のエラー文が出力される
    • .cache/, public/もESLintの対象になっているが後述のtsconfig.eslint.jsonで対象外にする

ESLintで出るエラーの解消するために.eslintrc.jsonを修正する

{
    "extends": [
        // 省略
        "plugin:import/errors", // 追加
        "plugin:import/warnings", // 追加
        "plugin:import/typescript", // 追加
    ],
    "rules": {
        "no-use-before-define": "off", // 追加
        "@typescript-eslint/no-use-before-define": ["error"], // 追加
        "react/jsx-filename-extension": ["error", { "extensions": [".jsx", ".tsx"] }], // 追加
        "react/no-unescaped-entities": "off", // 追加
        "react/prop-types": "off" , // 追加
        "react/require-default-props": "off", // 追加
        "import/extensions": [ // 追加
            "error",
            "ignorePackages",
            {
              "js": "never",
              "jsx": "never",
              "ts": "never",
              "tsx": "never"
            }
        ]
    },
}

  • この状態でyarn run eslint --fix "**/*.tsx"を実行するとエラーは全て消えているが、型が指定されていなかったり、そもそもインストールされていなかったりする(react-helmetなど)

  • これをチェックするため、eslintrc.jsonにさらに以下を追加すると型が指定されていないエラーなどが出現する

"extends": [
// 省略
"plugin:@typescript-eslint/recommended", // 追加
"plugin:@typescript-eslint/recommended-requiring-type-checking", // 追加
],
"parserOptions": {
// 省略
"project": "./tsconfig.eslint.json" // 追加
},
  • parserOptions.projectに設定したtsconfig.eslint.jsonでESLint対象のファイルを設定する
{
  "extends": "./tsconfig.json",
  "include": ["./src/**/*"],
}

TypeScirptへの本格対応

  • TypeScriptの型チェックが正しく効くようになったため、ソースコードを修正していく

src/componentsの修正

  • src/components/seo.tsxを例にとる(他のcomponentsも同様に修正)
  • 修正ポイントは以下の通り
    1. react-helmetの型定義
    2. Seo関数の型定義
    3. GraphQLの型定義

react-helmetの型定義

import { Helmet } from "react-helmet";
  • react-helmetの定義ファイルがないために、VSCodeがエラーを吐いている
  • これは定義ファイルをインストールすれば解決
yarn add -D @types/react-helmet

Seo関数の型定義

type SEOProps = {
  title: string;
  lang?: string;
  meta?: React.ComponentPropsWithoutRef<'meta'>[];
  description?: string;
};

const SEO: React.VFC<SEOProps> = ({
  title,
  lang = 'ja',
  meta = [],
  description = '',
}) => {
  // 省略
}

GraphQLの型定義

yarn add gatsby-plugin-typegen
  • gatsby-config.jsにpluginを追加
plugins: [
    // 省略
    `gatsby-plugin-typegen`,
]
  • yarn buildを実行し、src/__generated__ディレクトリが作成されることを確認する
  • これでエラーは消える(消えない場合はCtrl + Shift + PなどでVSCodeのWindowを再起動してみる)

src/pagesの修正

  • src/pages/index.tsxを例にとる(他のpagesも同様に修正)
  • IndexPage関数の型定義を加えればOK
const IndexPage: React.VFC<PageProps> = () => (
  // 省略
)

Prettierの設定

  • JSのためのコードフォーマッタ
  • Pythonのblackみたいなやつ
  • prettierはデフォルトでインストールされている
  • 設定ファイル.prettierrcを修正する
  • Prettier
.prettierrc
{
  "arrowParens": "avoid",
  "semi": true,
  "singleQuote": false,
  "tabWidth": 2,
  "trailingComma": "es5"
}

ESLintとPrettierの競合回避

yarn add -D eslint-config-prettier
  • eslintrc.jsonのextendsにprettierを追加
"extends": [
  // 省略
  "prettier"
],
  • この状態でyarn run prettier --write "**/*.tsx"を実行するとコードフォーマットが実行される

パッケージ追加 & package.jsonの設定

  • ESLint, Prettierを実行したい時に長ったらしいコマンドを打つのは面倒
  • コミットする前にELint, Prettierが確実に実行されるようにしてコードの品質を保ちたい

ESLint, Prettierの実行を楽にする

  • package.jsonにスクリプトを登録しておく
"scripts": {
    // 省略
    "format:prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
    "format:eslint": "eslint --fix",
    "format": "yarn format:eslint && yarn format:prettier"
}
  • これでyarn formatを実行すればESLintもPrettierも実行される

(Optional) コミット前にESLint, Prettierが実行されるようにする

# yarn v1の場合
yarn add -D husky lint-staged
yarn husky install
yarn husky add .husky/pre-commit "yarn lint-staged"
  • Package.jsonに設定を記述しておく
"scripts: {
    // 省略
},
"lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write \"**/*.{js,jsx,ts,tsx}\"",
    ],
    "*.{json,md}": [
      "prettier --write \"**/*.{json,md}\""
    ]
},

VSCodeの設定

  • VSCodeでリアルタイムコード解析がされるようにする
  • VSCodeで保存時に自動でESLint, Prettierを自動実行してくれるようにする

拡張機能のインストール

以下の拡張機能をインストールするとリアルタイムコード解析がされるようになる

  • ESLint: dbaeumer.vscode-eslint
  • Prettier - Code formatter: esbenp.prettier-vscode

保存時にESLint, Prettierを自動実行するように設定する

  • ※以下で行う設定を有効化するには開いているWorkspase直下に後述する.vscodeが存在している必要があるので注意

  • プロジェクトルート直下に.vscodeフォルダを作成し、.vscode直下に以下のsettings.jsonを作成する

{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll": true,
    "source.organizeImports": true
  },
}
  • 蛇足だが.vscode直下にextensions.jsonを作成しておくと推奨拡張機能などを記述できるため、チーム開発等に便利
  • VSCodeのコード解析をすると、赤線が引かれているところが散見されるため次項で対応する

tscの対応

"scripts": {
    // 省略
    "check-types": "tsc --noemit", // 追加
    "format:prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
    "format:eslint": "eslint --fix",
    "format": "yarn format:eslint && yarn format:prettier && yarn check-types", // 修正
  },
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write \"**/*.{js,jsx,ts,tsx}\"",
      "bash -c tsc --noEmit" // 追加
    ],
  },
  • 次にエラーが出ないように修正していく

  • GraphQLのレスポンスとしてundefinedかもしれないオブジェクトは?をつけてNull許容型にする

const metaDescription = description || site?.siteMetadata?.description;
  • titleTemplateの型を合わせるためにnullからundefinedに変更する
<Helmet
  htmlAttributes={{
    lang,
  }}
  title={title}
  titleTemplate={defaultTitle ? `%s | ${defaultTitle}` : undefined} // null -> undefined
  meta={defaultMeta.concat(meta)} // defaultMetaは後述
/>
  • metaの型を明示する
const defaultMeta: React.ComponentPropsWithoutRef<"meta">[] = [
  {
    name: "description",
    content: metaDescription,
  },
  // 省略
]
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?