Masayan tech blog.

  1. ブログ記事一覧>
  2. 現代のフロントエンド開発に必須の技術と設定サンプル(Typescript、Webpack、ESLint、Jest、Prettier)

現代のフロントエンド開発に必須の技術と設定サンプル(Typescript、Webpack、ESLint、Jest、Prettier)

公開日

この記事を書いた理由

どんなフロントエンドのフレームワークを使って開発するにせよ、現代のモダンフロントエンド開発にTypescriptはもはや必須といっても過言ではないわけですが、Typescript含めそれらの周辺のエコシステムを使用するための設定ファイルが多く、初学者にとってとっつきにくいものとなっています。

そのため、雰囲気で使用するとうまく動作していなかったり意図していない動作になったりする危険性があります。

そこで、本記事ではTypescript、Webpack、ESLint、Jest、Prettierの設定サンプルと主要な各設定項目とその内容を列挙していますので、これらを参考にしていただければ、いきなりフロントエンドの開発を任されてもある程度は対応できると思いますし、雰囲気で設定を記述するということも減り、適切な開発環境を構築することができるのではないかと思います。 

環境

  • node 16.17.0
  • npm 8.15.0
  • typescript 4.8.4
  • webpack 5.74.0
  • eslint 8.27.0
  • jest 29.2.2
  • prettier 2.7.1

Typescript

ツールの役割

  • 型システムを活用することで、コードの品質を向上させる
  • エディタ上で型補完が効くので、開発効率が向上する

設定ファイル

以下のコマンドにより、tsconfig.jsonが初期生成される

npx tsc --init

デフォルトの設定は以下の通り(typescript 4.8.4)

tsconfig.json

{
    "compilerOptions": {
      "target": "es2016",
      "module": "commonjs", 
      "esModuleInterop": true,
      "forceConsistentCasingInFileNames": true,
      "strict": true,
      "skipLibCheck": true
  }
}

分類

項目

内容

compiler Options

target

  • TypeScriptをJavaScriptにコンパイルする際、どのバージョンのJavaScript(ECMAScript)で出力するか
  • 例えば、es6以降から使用できるclassのprivateアクセス修飾子などを使用したtsファイルのソースがある場合に、targetをes5で指定してしまうと、そのような記法はないので、以下のようにコンパイルエラーになる
    • TS18028: Private identifiers are only available when targeting ECMAScript 2015 and higher
  • 最終的には、ES5へトランスパイルされる
  • 指定する値の目安としては、コンパイルを実行する環境のNode.jsのバージョンに対応したものを指定するとよい。理由としては、コードサイズや実行時間の最適化が期待できるため(Node.js16はES2021をサポートしているので、target: "ES2021"となる)
  • Node.jsとtsconfig.jsonのtargetの対応は以下を参考に

module

  • どのような形式でモジュール(js)を読み込むか指定する(CommonJS, ES Module形式など)
  • モジュールの構文のみについてのオプションなので注意(ほかの構文は関係ない)
  • バックエンドならcommonjsを、フロントエンドならESModule(es2015, es2020, es2021, esnextを指定するのがよい
    • 例えば、ES2020からはawait文を使ったコード中のモジュールの読み込みができるようになったが、moduleを2015などで指定していると、それらのコードがコンパイルエラーになる(ESModule形式でもバージョンにより多少の違いがあるということ)
    • ESNextは、TypeScriptがサポートしているECMAScriptの最も新しいバージョンを指す
    • ESNextを指定すると、Tree Shakingなどの最適化ができる

esModuleInterop

CommonJS形式のモジュールをESModuleでimportする際などに、モジュールシステムの互換性を保つための設定

forceConsistent

CasingInFileNames

import時にファイルパスの文字列について大文字小文字を区別するかどうか

strict

コンパイル時の様々な厳格な型チェック機能を有効にする。Ex. noImplicitAny(any型が推論されたらエラーになる) https://www.typescriptlang.org/tsconfig/#strict

skipLibCheck

*.d.ts ファイルに対する型チェックをスキップする

上記以外でよく使用する設定は以下の通り

分類

項目

内容

compiler Options

rootDir

  • outDir(デフォルトならdist)にファイルを出力する際のディレクトリ構成を維持するためだけに使用される
  • コンパイル対象を決めるオプションではない
  • rootDirで指定したディレクトリ以外の場所に.tsという拡張子を持つファイルが存在するとエラーが生じるので注意
    • 例えば、jestのテスト用ファイルをtestsディレクトリに、ソースコードをsrcディレクトリに分けて配置し、roodDirを./srcのみ指定すると、jest用のtsファイルに対してエラーになるので、後述のincludeと組み合わせる必要がある

 

outDir

  • tscコマンドでトランスコンパイルした時のファイルの出力先を指定する
  • webpackを使用しており、outputにパスを指定している場合はこちらの設定は本質的には不要

sourceMap

trueを指定することで、出力されたJavaScriptファイルに対応する元のTypeScriptソースを表示できるようになる

importsNotUsedAsValues

interfaceやtypeなど型の定義だけを持つのtsファイルのインポートは、import type の形式での記述を強制できる(コンパイルエラーにする)

resolveJsonModule

  • JSONファイルのimport、型の抽出や生成が可能になる
  • moduleResolution(基本的には、nodeを指定すればOK)も併せて指定していないと使用できないので注意

baseUrl

相対パスによるimportを行う際の起点となるパス

paths

  • 特定のディレクトリをエイリアスで表現できる(@など)ので、相対パスのimport(../../../)地獄を解消してくれる
  • baseUrlの指定がないと使用できないので注意

declaration

  • コンパイルするtsファイルについて、exportしているもの全ての型定義ファイルをファイルごとに生成する
  • 何もexportされてなくてもファイル自体は生成される

include

-

  • コンパイルの対象ファイルを指定
  • src/**/*.tsと指定した場合、src配下のtsファイル全て(ディレクトリのネストが深くなっても再帰的に全て)をコンパイル対象にすることが可能
  • 例えば、A.tsが指定されている場合、対象となるのはA.tsだけではなく、A.tsでimportしているB.tsやB.tsでimportされている・・・.tsも含まれます

exclude

-

コンパイルの非対象ファイルを指定(node_modulesなど)

node.js(ver16)の環境かつ、フロントエンドでstrictモードで使用するという前提に立つと、以下のようになった

tsconfig.json

{
    "compilerOptions": {
        "target": "es2021",
        "module": "esnext",
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "strict": true,
        "skipLibCheck": true,
        "rootDir": ".",
        "outDir": "./dist", //明示的に記載
        "sourceMap": true,
        "importsNotUsedAsValues": "error",
        "moduleResolution":"node",
        "resolveJsonModule": true,
        "baseUrl": ".",
        "paths": {
          "@/*": ["./src/*"]
        }
    },
    "include": [
        "src/**/*.ts",
        "tests/**/*.ts", // testsディレクトリのファイルからのimportがmodule not foundになるため
    ],
    "exclude": [
        "node_modules"
    ]
}

ちなみに、毎回設定ファイルを記載するのは面倒であれば、厳密な方チェックモードでtsconfigを自動生成してくれる便利なパッケージもあります   @tsconfig/strictest

Jsプロジェクトに部分的にTsを導入したい

このような場合、以下の設定が必要となります。

分類

項目

内容

compilerOptions

allowJs

  • JavaScript ファイルをプロジェクトへインポートできるようにするための設定
  • allowJsをtrueで指定しないと、tsからjsをimportできない

compilerOptions

checkJs

  • checkJsをtrueにすると、既存のjavascriptに対しても型チェックが行われるようになる
  • javascriptのファイル数にもよるが、基本的には大量のエラーが表示されるので注意。
  • allowJsの設定が必須

Webpack

ツールの役割

  • 現代のフロントエンド開発には欠かせないモジュール(主にjsファイル)のバンドラー
  • 開発用サーバーやホットリロードが実現できる
  • 便利なプラグインやローダーを適用させることで、画像やcssも処理することが可能

設定ファイル

webpack.config.js

const path = require('path')
const ESLintPlugin = require('eslint-webpack-plugin')

module.exports = {
  entry: {
    bundle: path.join(__dirname, 'src', 'index.ts'),
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js', // [name]はentryで記述した名前(=bundle)
  },
  devtool: 'source-map',
  resolve: {
    extensions: ['.ts', '.js'],
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'ts-loader',
      },
    ],
  },
  plugins: [
    new ESLintPlugin({
      extensions: ['.ts', '.js'],
      exclude: 'node_modules',
    }),
  ],
  devServer: {
    hot: true,
    host: 'localhost',
    port: 8009,
    static: {
      directory: path.join(__dirname, 'dist'),
    },
    open: true,
  },
}

主要な設定

分類

項目

内容

entry

bundle

  • バンドルを行う起点となるファイルの指定
  • webpackがビルドする際に開始点となるJSファイル

output

path

バンドル後のファイルを出力するファイルパスの指定

 

filename

バンドル後のファイルを出力するファイル名の指定

devtool

-

  • ビルド時にソースマップを出力するための設定
  • マップファイルの出力と併せて、バンドル後のjsの末尾にマッピングurlが追記される。

    //# sourceMappingURL=bundle.js.map

resolve

extensions

import文でファイル拡張子を省略して名前解決するための設定

import @/hoge/foo/bar.ts

import @hoge/foo/bar

 

alias

特定のディレクトリをエイリアスで表現できる(@など)ので、相対パスのimport(../../../)地獄を解消してくれる

module

rules

  • モジュールに適用するルールの設定(ローダーの設定を行う事が多い)
  • testに条件を、loaderに条件に一致する際に適用するローダーを指定する

plugins

-

webpackビルドプロセスをカスタマイズするためのプラグインを指定する

devServer

-

  • webpack-dev-serverは、webpackを用いたプロジェクトにおける開発用サーバ
  • webpack-dev-serverは内部的にはexpressで実装されている

 

hot

HMRが有効になる(ソースコードを一部修正した場合に、ブラウザリロードなしに変更内容を反映させる)

 

open

trueを指定すると、初回ビルド完了時にブラウザを自動起動する

 

static

directory

webpack-dev-serverの公開フォルダ(ドキュメントルート)

余談ですが、babel-loaderがなくても、ts-loaderのみで、Typescriptのトランスコンパイルは可能です。また、webpackでビルド時にeslintを走らせるためには、別途以下のライブラリが必要です。(後述します

npm install --save-dev eslint eslint-webpack-plugin @typescript-eslint/eslint-plugin @typescript-eslint/parser

ESLint

ツールの役割

  • コードの静的解析が可能になる
  • 一定のコーディング規約に沿ってコードが書かれているかどうか自動でチェックすることができる
  • 規約に沿っていない場合にはエラーが表示され、 コードの一貫性を高めながら、バグを回避できる

設定ファイル

.eslintrc.js

module.exports = {
  root: true,
  plugins: ['@typescript-eslint'], //eslint-plugin-prettier非推奨のため指定しない
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'prettier',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    sourceType: 'module',
    project: './tsconfig.json',
  },
  env: {
    browser: true,
    es2021: true,
  },
  rules: {
    'no-console': 'warn',
    'no-var': 'error',
    '@typescript-eslint/adjacent-overload-signatures': 'warn',
    '@typescript-eslint/no-unnecessary-type-assertion': 'error',
  },
};

主要な設定

分類

項目

内容

root

-

  • trueにすると、プロジェクトのルートに配置した設定ファイル(.eslintrc.js)を参照するように強制できる
  • プロジェクト内に1つしか設定ファイル(.eslintrc.js)がなければ、特に意識する必要はない
  • eslintのルール設定はカスケードされる特徴があるため、このような設定が存在している
    • より深い階層にある設定ファイルを階層をたどっていきながら、最終的に、ルートディレクトリかroot:true が書かれた設定ファイルのあるディレクトリに到達するまで、設定をマージしていく
    • 要するに、ディレクトリを限定して設定ファイルを置けば、その階層と同じ階層にあるソースに対してのみ設定を適用できる

plugins

 

  • typescriptやjestなどの個々のライブラリに適したeslint用のプラグイン(ルールセット)を指定
  • eslint-pluginというプレフィックスは省略して記述できるというルールがある
  • イメージ的には、pluginsで使用するルールを指定し、後述のextendsで適用するルールを指定する、ような感じ

extends

-

  • pluginsで指定したルールセットから実際に適用する項目を指定する
  • 後から指定したものが優先される
  • eslint-config-というプレフィックスを省略できる
  • plugin:プラグインの省略名/コンフィグ名で指定する

parser

 

ESLintは標準でJavaScriptのパースに対応していますが、TypeScriptも扱えるように(構文解析できるように)するには、@typescript-eslint/parserが必要

parserOptions

sourceType

  • ESLintがプログラムの構文解析する際のオプションを指定
  • moduleを指定することで、ES Modules形式のモジュールシステムを有効にする

 

project

  • TypeScriptの静的解析に使用するconfigファイルを指定
  • プロジェクト内の型認識に使用(明示的にtsconfigファイルを指定する必要がある)

env

browser

  • env = 静的検証をどのような環境で行うかの前提条件を指定する
  • browserは、どのようなグローバルオブジェクトを参照可能にするかを ESLint に知らせるための設定
  • trueにすると、alertとかdocumentとかwindow(ブラウザで実行されるコードを静的検証してくださいということになる)

 

es2021

すべての ECMAScript 2021の構文や組込みオブジェクトを追加し、parserOptionsのecmaVersion: 2021に設定してくれる(ESLint のデフォルトパーサーは ECMAScript 5 の構文で記述されたコードを想定している)

※parserOptionsのecmaVersionの指定は不要になる

rules

-

  • extends による共有設定で大まかなルール設定を行い、rulesで個別ルールを細かく調整できる
  • 各ルールに対して、error, warn, offのレベルを指定可能

余談ですが、eslint-plugin-prettierの使用は、非推奨となっています。(2020年6月以降)

ESLintで静的解析を行い、ESLintのフォーマットは無効にしつつ、Prettierでフォーマットを行うというのが一般的なすみ分けかと思いますが、eslint-plugin-prettierは、

ESLintとPrettierを一緒に使う場合にeslintの実行時にprettierの実行も行ってくれるようにするものです。
(prettierの実行をeslintが行うので、prettierのエラーもeslintのエラーとして出力される仕組み)

※なお、eslint-config-prettierは従来通り、eslintの設定ファイルのextendsにprettierとして指定する必要があります(ESLintにもフォーマット機能があり、prettierと競合しないようにするための機能なので、一番最後に指定すること)

eslintの設定とprettierのルールが衝突していないかどうかは以下のコマンドで確認可能

npx eslint-config-prettier 'src/**/*.{js,ts}'

一括修正コマンド

npm scriptsを活用して、eslintのエラー箇所を一括で修正することが可能です

masayan

上述の通り、これまでは、eslint-plugin-prettierによりeslint実行時にprettierが自動処理されていましたが、このプラグインを使用しないので、別途prettierも併せて実行するように指定してあげる必要があります

"scripts": {
  "lint:fix": "eslint --cache --fix src && prettier --write src",
 ・・・

上記を追加し、以下を実行すると、

npm run lint:fix

eslintのルールに反しているコードは、自動で修正してくれます。ただし、自動で修正されるものとされないものがあり、arrow-body-styleやno-varなどのルールは自動で修正されますが、no-consoleなどは自動で修正されないので注意が必要です。

エディタの設定

なお、上記のようなコマンドを毎回実行するのは手間なので、VsCodeでコードを保存したタイミングでeslintの修正とprettierを実行したい場合は拡張機能のインストール後、setting.jsonに以下を追加します

※フォーマットはprettierが担うので、eslint.format.enableがtrueになっている場合はfalseにすること。

https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint

https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode

"[typescript]": {
  "editor.defaultFormatter": "esbenp.prettier-vscode", // prettierを使用する場合に必要な設定
  "editor.codeActionsOnSave": [
    "source.fixAll.eslint"
  ]
},

Prettier

ツールの役割

  • コードフォーマッター。プロジェクト単位でコードのフォーマットを統一できるので、レビューの際などに人によってセミコロンがないとかで論争になる必要がなくなる

設定ファイル

.prettierrc

{
  "printWidth": 120,
  "tabWidth": 2,
  "semi": true,
  "singleQuote": true,
  "trailingComma": "es5",
  "endOfLine": "lf"
}

主要な設定

分類

項目

内容

printWidth

-

折り返す行の長さ(def:80)

tabWidth

-

インデントのスペースの数

semi

-

ステートメントの最後にセミコロン

singleQuote

-

ダブルクォートの代わりにシングルクォート

trailingComma

-

オブジェクト、配列などの末尾にカンマを自動的に追加

endOfLine

-

改行の文字コードLFとする

エディタの設定

VsCodeでコードを保存したタイミングでprettierを実行したい場合は拡張機能のインストール後、setting.jsonに以下を追加します

https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode

  • formatOnSaveをtrueにして保存時にフォーマットが効くように
  • フォーマッターにprettierを指定
    以下のように、言語ごとに指定するのがおすすめ
{
  "editor.formatOnSave": true,
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
   },
}

Jest

ツールの役割

  • js, tsの単体テストが可能になり、コードの品質が向上する

設定ファイル

jest.config.js

module.exports = {
  roots: ['<rootDir>/tests'],
  testMatch: ['**/tests/**/*.test.ts'],
  preset: 'ts-jest',
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
  },
};

主要な設定

分類

項目

内容

roots

-

  • testファイルが配置されているディレクトリを指定する(src内にテスト対象のファイルと一緒に配置している場合は、<rootDir>/srcなど)

testMatch

-

  • テストファイルを検出するのにJestが使用するglob パターン(今回は
  • test専用のtestsディレクトリに配置しており、そこにはテスト以外の他のファイルがないのであれば、指定しなくてもOK)

preset

-

  • TypeScriptをjestでテストするための前処理をしてくれるプリプロセッサ(transformという設定でも可能だが、こちらを指定していればは不要)

moduleNameMapper

-

  • 特定のディレクトリをエイリアスで表現できる(@など)ので、相対パスのimport(../../../)地獄を解消してくれる
  • 例えば、@/domain/geography/jp/prefecture/Prefecturesと書けば、@以降がマッチするので、実際のファイルパスは、<rootDir>/src/domain/geography/jp/prefecture/Prefectures としてマッピングされる

eslintの適用

eslint-plugin-jestをインストールして、eslintの設定ファイルに追記することでテストの書き方などに対して、一定のルールを強制することが可能

module.exports = {
  root: true,
  plugins: ['@typescript-eslint', 'jest'],
  extends: [
  ・・・
    'plugin:jest/recommended', //Jestの書き方に関する推奨ルール一式
    'plugin:jest/style', //Jestのスタイルルール系
  ],
  ・・・
  rules: {
    ・・・
    // jest関連
    'jest/consistent-test-it': ['error', { fn: 'it' }], //testとitのうち、itを使うように強制する
    'jest/require-top-level-describe': ['error'], //describe内に必ず配置するようにする(itやtestをむき出しで配置しない)
  },
};

インストールしたライブラリと用途

package.json

{
  ・・・・
  "devDependencies": {
    "typescript": "^4.8.4",
    "webpack": "^5.74.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.11.1",
    "ts-loader": "^9.4.1",
    "eslint": "^8.27.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-jest": "^27.1.4",
    "eslint-webpack-plugin": "^3.2.0",
    "@typescript-eslint/eslint-plugin": "^5.42.0",
    "@typescript-eslint/parser": "^5.42.0",
    "jest": "^29.2.2",
    "@types/jest": "^29.2.2",
    "ts-jest": "^29.0.3",
    "prettier": "^2.7.1",
  }
}

項目

内容

リポジトリ

typescript

typescript本体

https://github.com/Microsoft/TypeScript

webpack

webpack本体

https://github.com/webpack/webpack

webpack-cli

webpackを実行するためのコマンドラインインターフェイス

https://github.com/webpack/webpack-cli

webpack-dev-server

webpackを使用した開発用ローカルサーバー

https://github.com/webpack/webpack-dev-server

ts-loader

  • webpackでtypescriptを扱うことができるようにするためのライブラリ
  • webpackは本来、JavaScriptのデータしか扱うことができないが、CSSや画像などをJavaScriptのオブジェクトにして、webpackで扱えるようにするのがローダー
  • ts-loaderはtypescript用のローダー

https://github.com/TypeStrong/ts-loader

eslint

eslint本体

https://github.com/eslint/eslint

eslint-config-prettier

ESLintのルールの内、Prettierのルールと競合するものをOffにするライブラリ

https://github.com/prettier/eslint-config-prettier

eslint-plugin-jest

jestを用いたテストファイルに関してeslintのルールを適用できるライブラリ

https://github.com/jest-community/eslint-plugin-jest

eslint-webpack-plugin

webpackの処理時に、eslintを実行できる

https://github.com/webpack-contrib/eslint-webpack-plugin

@typescript-eslint/eslint-plugin

 typescript用のeslintルールセット

https://github.com/typescript-eslint/typescript-eslint

@typescript-eslint/parser

 typescriptの構文をeslintが解析できるようにするためのパーサー

https://github.com/typescript-eslint/typescript-eslint

jest

 js, tsの単体テストツール

https://github.com/facebook/jest

@types/jest

 jestの型定義

https://github.com/DefinitelyTyped/DefinitelyTyped

ts-jest

jestでtypescriptを扱えるようにするためのライブラリ

https://github.com/kulshekhar/ts-jest

prettier

 コードフォーマッター

https://github.com/prettier/prettier

インストール手順

Typescript、Webpack、ESLint、Jest、Prettierを使用したモダンフロントエンド開発環境の構築手順をざっと紹介します。

初期化

  • プロジェクト用のディレクトリ作成
  • npm初期化
  • indexファイル作成
$ mkdir frontend-package-sample cd frontend-package-sample
$ npm init -y
$ mkdir src && touch src/index.ts

TypeScript, Webpack

関連パッケージ・設定ファイル追加

$ npm install -D typescript ts-loader webpack webpack-cli
$ touch tsconfig.json webpack.config.js

※tsconfig.jsonおよびwebpack.config.jsの内容は割愛します。

ビルド

package.jsonにbuildコマンドを追加

"scripts": {
  "build": "webpack --mode=development",

ビルドおよびバンドルされたjsを実行し問題なく動くことを確認する

$ npm run build
$ node dist/bundle.js

ESlint

Eslint関連のパッケージ・設定ファイル追加

※.eslintrc.jsの内容は割愛します。

$ npm install -D eslint @typescript-eslint/eslint-plugin eslint-config-prettier
$ touch .eslintrc.js

Prettier

Prettier関連のパッケージ・設定ファイル追加

※.prettierrcの内容は割愛します。

$ npm install -D prettier 
$ touch .prettierrc

Lint用コマンド追加

package.jsonにコマンドを追加

"scripts": {
  "lint": "eslint --ext .js,.ts --ignore-path .gitignore",
  "lint:fix": "eslint --cache --fix src && prettier --write src",

Lintの実行

$ npm run lint

Lintエラーの修正とフォーマット

$ npm run lint:fix

Jest

Jest関連のパッケージ・設定ファイル追加

※jest.config.jsの内容は割愛します

$ npm install -D jest ts-jest @types/jest eslint-plugin-jest
$ touch jest.config.js

テスト用コマンド追加

package.jsonにコマンドを追加

"scripts": {
  "test": "jest",

テストファイルを書いて、実行

$ touch tests/hoge.test.ts
$ npm run test

以上です。

まとめ

いかがでしたでしょうか。本記事では、Typescript、Webpack、ESLint、Jest、Prettierの設定サンプルと主要な各設定項目とその内容を列挙しています。この辺りの情報が体系的にまとまった記事等があまりないので、これらを参考にしていただければ、適切な開発環境を構築・設定することができるのではないかと思います