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

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

みなさまこんにちは。
暖かくなってきましたね、桜も見頃でいい季節になりました。

さて今日はタイトル通り、Create React App を使わずに React & TypeScript 環境を作る記事を書きたいと思います。

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

今日のゴール

webpack を導入し Babel を使って React のアプリをビルドするまで。

Create React App とは

作業に入る前にまず「Create React App」 の説明を軽くしておきます。
Create React App とは Facrbook が提供している CLI ツールで用意されたテンプレートを元にアプリケーションの雛形を生成してくれるものです。

https://create-react-app.dev/

雛形を提供するだけでなくオプションを指定することで TypeScript や PWA など色々な用途に合わせたアプリケーションの雛形を作成してくれます。
ただ、元々が煩雑な webpack 等の設定を隠蔽化することを目的としたツールであるため、Create React App から直接 webpack の変更することは難しいです。

一応”eject”という手段を用いれば途中から素の webpack のプロジェクトにしてくれますが、出力される設定ファイル群はメンテナンスしやすい形ではないのでオススメはできまません。

要件的に create-react-app で実現可能であればベストプラクティスな設定が適用されるので問題ないのですが、もし webpack に特殊な loader やプラグインを組み込みたいのであればこの記事で取り扱う様な方法が良いと思います。

環境など

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

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

  • webpack(v5.28)
  • React(v17)
  • Babel(7.13)

TypeScript は Babel を通してトランスパイルする予定です。

Babel の環境セットアップ

まずは適当なディレクトリを作り npm を初期化、package.json を作ります。

$ mkdir exampleApp
$ cd exampleApp
$ npm init -y

次に webpack を入れていきまししょう。

$ npm install -D webpack webpack-cli webpack-dev-server html-webpack-plugin

webpack 本体と cli、デバッグ用の開発サーバー、webpack から html を生成するのを簡単にする為のプラグインの順番です。

続けて Babel を入れます。

$ npm install -D @babel/core @babel/runtime @babel/plugin-transform-runtime @babel/preset-env babel-loader

Babel のコア部分、ランタイム、ランタイムのコードを再利用してサイズを小さくするプラグイン、プリセットの設定、webpack の loader です。

ビルド設定

このまま TypeScript の環境をセットアップしても良いのですが、まずは javascript で React を組み込めることを確認したいと思います。

React を入れていきます。

$ npm install react react-dom
$ npm install -D @babel/preset-react

React 本体、DOM のライブラリ、Babel で React を扱う為のプリセット。

インストールはここまで、ではコードを書きましょう。
src ディレクトリを作り、index.html と app.js、hello.jsx を作ってください。

/exampleApp
├── node_modules/
├── package-lock.json
├── package.json
└── src
     ├── Hello.jsx
     ├── app.js
     └── index.html

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>exampleApp</title>
</head>
<body>
    <noscript>
      <strong>javascriptを有効にしてください</strong>
    </noscript>
    <div id="app" />
</body>
</html>

html のテンプレートですね。

app.js

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

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

エントリポイントとなる js です。

Hello.jsx

import React from "react";

const Hello = () => <h1>こんにちは!</h1>;
export default Hello;

React コンポーネントです。

続いて webpack の設定ファイル webpack.config.js を作成し、dist ディレクトリを追加します。

/exampleApp
├── dist/
├── node_modules/
├── package-lock.json
├── package.json
├── src
│   ├── Hello.jsx
│   ├── app.js
│   └── index.html
└── webpack.config.js

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  mode: "development",
  entry: path.resolve(__dirname, "src/app.js"),
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "app.js",
  },
  resolve: {
    modules: [path.resolve(__dirname, "node_modules")],
    extensions: [".js", ".jsx"],
  },
  module: {
    rules: [
      {
        test: [/\.js$/, /\.jsx$/],
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-env", "@babel/preset-react"],
            },
          },
        ],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "src/index.html"),
    }),
  ],
};

webpack の設定ですね、module.rules のところで js と jsx のファイルを babel-loader に読ませる設定をしてます。
babel-loader にはプリセットの設定を行いました。
また plugin に HtmlWebpackPlugin を追加して html のテンプレートを指定しています。

ビルドしてみましょう。

$ npx webpack --config webpack.config.js
...
webpack 5.28.0 compiled successfully in 3064 ms

成功です。

このままでは動作確認できないので開発サーバーの設定を webpack.config.js の末尾に追加します。

      template: path.resolve(__dirname, "src/index.html"),
    }),
  ],
  devServer: {
    contentBase: path.join(__dirname, "dist"),
  },
};

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

$ npx webpack serve --config webpack.config.js
「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/dist
...
「wdm」: Compiled successfully.

Web ブラウザで「http://localhost:8080」アクセスして以下の画面が表示されれば成功です。

ビルドや開発サーバーの立ち上げは npm-script にしておくと楽です。package.json を開き、scripts の部分を以下の様に編集します。

  "main": "index.js",
  "scripts": {
    "build": "webpack --config webpack.config.js",
    "start": "webpack serve --config webpack.config.js"
  },
  "keywords": [],
  "author": "",

うまく設定できているか確認しましょう。

$ npm run
Lifecycle scripts included in exampleApp:
  start
    webpack serve --config webpack.config.js

available via `npm run-script`:
  build
    webpack --config webpack.config.js
$ npm run build
...
webpack 5.28.0 compiled successfully in 2913 ms
$ npm run start
...
「wdm」: Compiled successfully.

大丈夫そうです。

長くなりましたので今回はここまでとします、お疲れ様でした!

一覧へ戻る