Create React App を使わずに React & TypeScript 環境を作る(2021 年 5 月) その 2

Create React App を使わずに React & TypeScript 環境を作る(2021 年 5 月) その 2

みなさまこんにちはゴリさんです。
今日は Create React App 未使用の環境作り続きを書いていきたいと思います。

前回の記事はこちらです。
https://enjoyworks.jp/tech-blog/6889

今回使用するライブラリ類のバージョン

環境は macOS Big Sur(11.2.1)です。
前提として node.js(v14.15) と npm(v7.5) が必要です。

今回使用する主要なライブラリのバージョンは以下の通りです。

  • webpack(v5.28)
  • react(v17)
  • Babel(7.13)
  • typescript(4.3.2)

typescript は babel でトランスパイルします。

最終的には redux-toolkit、material-ui の導入まで行う予定ですが、似た様な記事がたくさんあるので私は自分の勉強のためにも step by step で少しづつ記事にしていこうかと考えています。

今日のゴール

typescript の導入です。

typescript の環境セットアップ

早速 npm で必要なパッケージを入れていきましょう。

$ npm i -D @babel/preset-typescript typescript @types/react @types/react-dom

babel の typescript プリセット、typescript、react の型定義ファイルですね。

次はwebpack.config.js を編集し、モジュール解決と loader 部分を以下の様に変更して下さい。

  resolve: {
    modules: [path.resolve(__dirname, "node_modules")],
    extensions: [".ts", ".tsx", ".js"], // ts, tsx追加、jsx削除
  },
  module: {
    rules: [
      {
        test: [/\.ts$/, /\.tsx$/], // js -> ts
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: [
                "@babel/preset-env",
                "@babel/preset-react",
                "@babel/preset-typescript",  // <- 追加
              ],
            },
          },
        ],
      },
    ],

続けて typescript の初期設定コマンドを叩き、tsconfig.json を作りましょう。

$ npx tsc --init

アプリケーションのルートディレクトリに tsconfig.json が作成されたと思います。

コメントを削除した版がこちらです。

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

基本 babel が変換、typescript は型チェックのみという構成なのでこんな感じに変更します。

{
  "compilerOptions": {
    "target": "esnext",
    "jsx": "react",

    /* ファイル名の大文字小文字を区別 */
    "forceConsistentCasingInFileNames": true,

    /* 型チェック関係のオプション */
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,

    /* Module解決方法 */
    "moduleResolution": "node",
    "esModuleInterop": true,
    "isolatedModules": true,
    "allowSyntheticDefaultImports": true,

    /* 型チェックだけさせたいので出力なし */
    "noEmit": true,
  },
  /* tscコマンドで読み込むファイルを指定 */
  "include": ["src/**/*.ts", "src/**/*.tsx"],
  "exclude": ["node_modules"]
}

設定項目の詳細については以下を参照ください。
https://www.typescriptlang.org/ja/tsconfig

コードの変更

javascript で書いていたコードを typescript にしていきましょう。

ファイル名を変更します。

mv ./src/app.js /src/app.tsx
mv ./src/Hello.js /src/Hello.tsx

少しだけファイルの中身も変えていきます。

app.tsx

import * as React from "react";
import ReactDOM from "react-dom";
import Hello from "./Hello";

ReactDOM.render(
  <React.StrictMode>
    <Hello />
  </React.StrictMode>,
  document.getElementById("app")
);

Hello.tsx

import * as React from "react";

const Hello: React.FC = () => <h1>おはようございます!</h1>;

export default Hello;

ファイル名が変わったので webpack.config.json のエントリポイントも変更です。

module.exports = {
  mode: "development",
  entry: path.resolve(__dirname, "src/app.tsx"), // app.js -> app.tsx
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "app.js",
  },
  resolve: {

npm スクリプトの変更

npm-script も変えていきます。
win/mac の考慮に加え、並列実行させたいので npm-run-all というパッケージを導入します。

$ npm i -D npm-run-all

package.json を開いて scripts のところを以下の様にしてください。

"scripts": {
  "tsc": "tsc",
  "tsc:watch": "tsc -w",
  "webpack:build": "webpack --config webpack.config.js",
  "webpack:watch": "webpack --watch --config webpack.config.js",
  "webpack:start": "webpack serve  --watch-content-base --config webpack.config.js",
  "build": "run-s tsc webpack:build",
  "watch": "run-p tsc:watch webpack:watch",
  "start": "run-p tsc:watch webpack:start"
},

開発サーバで起動

開発サーバーを上げてみましょう。

$ npm run start
[12:15:59] Starting compilation in watch mode...

ℹ 「wds」: Project is running at http://localhost:8080/
ℹ 「wds」: webpack output is served from /
ℹ 「wds」: Content not from webpack is served from /Users/sumishin/Documents/work/system_blog/exampleApp/dist
...
  ./src/Hello.tsx 208 bytes [built] [code generated]
webpack 5.28.0 compiled successfully in 4764 ms
ℹ 「wdm」: Compiled successfully.

Web ブラウザで「http://localhost:8080」アクセスして「おはようございます!」と表示されていれば成功です。

型チェックの確認

tsc の型チェックが機能しているか確認してみます。
Hello.tsx を開き、以下の様に時間によって挨拶を変更する様にコードを変更します。

import * as React from "react";

const Hello: React.FC = () => {
  const buildGreetingText: (date: Date) => string = (date) => {
    // 0 ~ 23 の範囲なので+1
    const hours = date.getHours() + 1;
    if (5 < hours && hours < 11) {
      return "おはようございます!";
    } else if (11 < hours && hours < 16) {
      return "こんにちは!";
    } else {
      return "こんばんは!";
    }
  };

  return <h1>{buildGreetingText(new Date())}</h1>;
};

export default Hello;

開発サーバーを立ち上中だと思いますので、ブラウザでアクセスすると時間に合わせた挨拶が表示されると思います。

続けてtsconfig.json に設定した noUnusedParameters 違反となる様、こんな感じに変更してみましょう。

import * as React from "react";

const Hello: React.FC = () => {
  const buildGreetingText: (date: Date) => string = (date) => {
    // 0 ~ 23 の範囲なので+1
    //const hours = date.getHours() + 1;   // <- コメントアウト
    const hours = 6;                       // 追加
    if (5 < hours && hours < 11) {
      return "おはようございます!";
    } else if (11 < hours && hours < 16) {
      return "こんにちは!";
    } else {
      return "こんばんは!";
    }
  };

  return <h1>{buildGreetingText(new Date())}</h1>;
};

export default Hello;

開発サーバーを立ち上げたターミナルの出力が以下の様になると思います。

[12:32:26] File change detected. Starting incremental compilation...

ℹ 「wdm」: asset app.js 1.24 MiB [emitted] (name: main)
asset index.html 267 bytes [emitted]
cached modules 1.19 MiB [cached] 40 modules
runtime modules 891 bytes 4 modules
./src/Hello.tsx 552 bytes [built] [code generated]
webpack 5.28.0 compiled successfully in 78 ms
ℹ 「wdm」: Compiled successfully.
src/Hello.tsx:4:54 - error TS6133: 'date' is declared but its value is never read.

4   const buildGreetingText: (date: Date) => string = (date) => {
                                                       ~~~~

[12:32:26] Found 1 error. Watching for file changes.

webpack の方は正常終了していますが、tsc でちゃんとエラーになってますね!


今回はここまでとします、お疲れ様でした!

一覧へ戻る