0
2

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.

create-react-appコマンド無しでReact + TypeScript環境をつくる

Last updated at Posted at 2020-11-21

create-react-appコマンド無しでcreate-react-appっぽいreact + typescriptの環境構築していきます。 今回、create-react-appぽいとは次のようなことを指します。

  • とりあえずts,tsxが動く
  • yarn buildでbuildファイルを生成する。
  • yarn startでローカルサーバーが自動で起動する。
  • ローカルサーバーが起動中、編集すると、自動でリロードされる(ホットリロード)

登場人物ややこしすぎ問題

とにかく構築にいろいろなパターンが多い + デファクトがよくわからない。1
本記事ではwebpack + ts-loaderの構成で構築していこうと思います。(babel-loaderを使わないパターンです)
そのため、対象となる読者は以下のとおりです。

・始めたてで、とにかく動かしてみたいだけ。
・細かいpolyfillは考えていない。
・作るものが小規模だ。(個人の練習アプリ程度) 

##環境
環境は以下の通りです。yarn使います。

$ node -v
v13.11.0
$ yarn -v
1.22.4 

init

まずはじめにpackage.jsonを生成します。

$ yarn init -y                //-yで対話をスキップ

##パッケージのインストール
次にwebpackともろもろのインストールを行います。

$ yarn add -D webpack@4.43.0 webpack-cli@3.3.12 webpack-dev-server@3.11.0 html-webpack-plugin typescript ts-loader

正常な動作を確認しているのは上記のバージョンのwebpack,webpack-cli,webpack-dev-serverのみです。バージョンを指定しない場合webpack v5系がインストールされるので注意してください。(2020年11/21日現在)2

  • webpack  ・・・・みんな大好きモジュールバンドラーの本体
  • webpack-cli ・・・・webpackコマンドがshellで使える様になる。package.jsonのscriptsにこのコマンドを割り当てることが多い
  • webpack-dev-server ・・・・開発サーバー用
  • html-webpack-plugin ・・・・必須ではないです。webpackがバンドルと一緒に.htmlも吐き出してくれます。自前でhtmlファイルを用意してもいいですが、使い方がとても簡単かつ楽なので筆者はいつもwebpackにまかせてます。
  • typescript ・・・・いつものあいつ
  • ts-loader ・・・・webpackがバンドルを作成するときにtsx—> jsx —> jsとコンパイルしてくれます。babel-loaderとごっちゃになってハゲそうになった。

scriptsの設定

先にpackage.jsonにscriptsを設定しておきましょう。

"scripts":{
   // dev-serverをdevelopmentモードで起動
   "start": "webpack-dev-server --config ./webpack.config.js --mode development”,   
   // productionモードでbuildファイルの出力
   "build":"webpack --mode production"
  } 

reactのインストール

次にreactと型定義ファイルをインストールします。こちらの詳細は割愛します。

$ yarn add react react-dom
$ yarn add -D @types/react @types/react-dom

ここから諸々のファイルを作成していきます。最終的なディレクトリ構成を載せておきます。

├── build       //buildディレクトリ
│   ├── bundle.js
│   └── index.html
├── package.json
├── src
│   ├── index.tsx  //エントリーポイント
│   └── template   // htmlpluginのテンプレート
│       └── index.html       
├── tsconfig.json
├── webpack.config.js
└── yarn.lock

webpack.config.js

webpack.config.jsを作成します。

// webpack.config.js
const path = require("path");

//htmlプラグインのための呪文
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  mode: "development",
  entry: {
    bundle: "./src/index.tsx", // エントリーファイルの位置
  },
  output: {
    filename: "[name].js",   // 今回はbundle.jsで吐き出される(entryで指定)
    path: path.join(__dirname, "build"), // buildという名前のbuildディレクトリを吐き出す
    chunkFilename: "[name].js",//今回は触れません 
  },
  devServer: {
    contentBase: path.join(__dirname, "build"),
    compress: true,
    port: 8080,
    open: true,        //yarn start コマンドを入力すると自動でブラウザに遷移します。
    historyApiFallback: true,
  },
  module: {
    rules: [
      {
        test: /\.ts(x?)$/,    //.ts または.tsxに対して
        loader: "ts-loader",  // ts-loaderを使用
      },
    ],
  },
  resolve: {
    extensions: [".ts", ".js", ".tsx", ".jsx"],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: `${__dirname}/src/template/index.html`, //テンプレートファイルの場所
      filename: "index.html",                                                      //テンプレートファイルの名前
      inject: "body",                                                             //bodyタグの直前でwebpackのバンドルを埋め込み
    }),
  ],
};

おまけ: 本当はwebpackのprodモードとdevモードの環境は個別に設定することが推奨されています。詳しくは公式ドキュメントを参照してください。今回はscriptsで無理やり分けてます。

tsconfig.json

次にtsconfig.jsonを作成します。ts-loaderはこのファイルの設定に従います。
必ず "jsx":"react"を指定しましょう。
ほぼデフォルトのコピペです。細かいのはお好みで。

// tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "module": "esnext",
    "resolveJsonModule": true,
    /* Basic Options */
    "allowJs": false /* Allow javascript files to be compiled. */,
    "jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,
    "sourceMap": true /* Generates corresponding '.map' file. */,
    "outDir": "/build" /* Redirect output structure to the directory. */,
    "isolatedModules": true /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */,
    /* Strict Type-Checking Options */
    "strict": true /* Enable all strict type-checking options. */,
    "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
    "strictNullChecks": true /* Enable strict null checks. */,

    /* Additional Checks */
    "noUnusedLocals": true /* Report errors on unused locals. */,
    "noUnusedParameters": true /* Report errors on unused parameters. */,
    "noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
    "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
    /* Module Resolution Options */
    "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
    relative to the 'baseUrl'. */
    structure of the project at runtime. */
    "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */,
    "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,

    /* Advanced Options */
    "skipLibCheck": true /* Skip type checking of declaration files. */,
    "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
  },
  "include": ["src"]
}

仕上げ

.tsxとhtmlのテンプレートを作成します。

// src/index.tsx
import React from "react";
import ReactDOM from "react-dom";
ReactDOM.render(<h1>hello</h1>, document.getElementById("root"));
// src/template/index.html
// ! + tab キーで作ってます。
// <div id = "root"></div>を忘れずに

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id='root'></div>
</body>

</html>

ここで、

$ yarn start 

するとindex.tsxの内容が描画されると思います。
ソースコードはこちら

  1. ts-loaderでjsxまでコンパイル + 型チェックしてbabel-loaderでjsにコンパイルするのがいいのでしょうか?詳しい方いらっしゃったらご教示頂ければ幸いです。

  2. 現状webpack v5系だとちょくちょくcliやdev-serverがエラー起こします。ググると大体バージョン落としたら治るパターンが多いです。

0
2
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
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?