0からReact+TSの開発環境を構築する
フロントエンド開発の環境構築は大変ややこしいことで有名ですが、とりあえず一回やっておけば最低限流れくらいは理解できるだろうということで、今回はReactとTypescript(以下TS)の開発環境を0からやってみる
Node.jsのインストール
まずはNode.jsがなければ何も始まらないので、nodenvやnvmなどでインストールする
nodenv install 14.17.6
npmプロジェクトの作成
以下のコマンドでpackage.jsonを作成する
(途中の質問は全部エンター)
npm init
すると以下のような内容でpackage.jsonが生成される
{
"name": "react-ts-sample",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"typescript": "^4.4.3"
}
}
TSの導入
TSはdev向けなので -D
オプションをつける
npm install -D typescript
これで npx tsc
コマンドが使えるようになるので、設定ファイルを生成する
npx tsc --init
これで以下のような設定ファイルが生成される
ほとんどコメントアウトされているので、コメントアウトされていない箇所だけを表示している
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"jsx": "react"
}
}
今回はReactを使うので、jsxオプションにreactを指定しているところだけが初期値との違い
https://qiita.com/ryokkkke/items/390647a7c26933940470#jsx
TSはトランスパイラとしての側面もあるため、Babelと同じようにレガシーなブラウザに向けた変換を行う役割も担える
従って今回はBabelを導入せず、コンパイルはTSに任せる(ここではES5向けに変換されるように設定している)
ただし、近年状況が改善してきたとはいえ、Babelのように preset-env
と .browserslistrc
による対象ブラウザの細かな指定までは行うことができないので
https://kangax.github.io/compat-table/es6/ などを参考に target
の設定を行うと良い
...ES5への変換はともかく、ポリフィルとかまで考えるとやっぱりBabel入れて併用するのがいいんだろうか
IEサポートしてなくても、ポリフィルは必要になる可能性は十分にある気がする
webpackの導入
webpack本体とcliを入れる
npm install -D webpack webpack-cli
これでwebpackコマンドが使えるようになったので、まずはTSをビルドできるようにするためts-loaderを入れる
npm install -D ts-loader
続いてwebpackの設定を書いていくが、npx webpack init
コマンドだと対話形式で一気に色々(lintの設定とかまで)やろうとしてくる
今回は1つ1つ確認しながら進行したいので、初期化コマンドは利用しないで進める
touch webpack.config.js
で空のファイルを生成し、以下の内容を書く
const path = require('path')
module.exports = {
mode: process.env.NODE_ENV,
entry: "./src/index.tsx",
output: {
path: path.resolve(__dirname, "./dist"),
filename: "build.js",
},
module: {
rules: [
{
test: /\.(ts|tsx)$/,
use: [
{
loader: "ts-loader",
},
],
},
],
},
}
ビルドの準備ができたので、Reactを入れていく
Reactの導入
reactとreact-domパッケージを入れる
npm install react react-dom
さらにTSの型定義ファイルも入れる(本番で不要なので-Dをつける)
npm install -D @types/react @types/react-dom
webpackのビルドのエントリポイントに指定したファイルにReactのコードを書き、ビルドを実行してみる
src/index.tsx
import React from 'react'
import ReactDOM from 'react-dom'
ReactDOM.render(
<div>Hello world</div>,
document.getElementById('root')
)
NODE_ENV=development npx webpack
asset build.js 1010 KiB [emitted] (name: main)
/ 略 /
webpack 5.53.0 compiled successfully in 1987 ms
無事にビルドできて、成果物がdistディレクトリに出力された
しかし、まだこのファイルをhtmlに埋め込んで確認できないので、jsの出力と同時にjsが埋め込まれたhtmlも生成してもらえるよう html-webpack-plugin
を使う
元となるテンプレートを指定すれば、バンドルされたファイルを読み込んだhtmlを出力先に同時に作成してくれるというもの
npm install -D html-webpack-plugin
テンプレートは以下のように用意した
src/index.tsxではrootというIDを持つ要素にマウントするようにしたので、rootというIDを持たせている
src/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react ts sample</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
webpackの設定も書き換える(追記したところだけ表示している)
html-webpack-pluginはデフォルトテンプレートとしてsrc/index.ejsを使うが、今回は違うのでtemplateオプションで指定している
https://github.com/jantimon/html-webpack-plugin#options
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
output: {...},
module: {...},
plugins: [
new HtmlWebpackPlugin({ template: './src/index.html' })
]
}
再度ビルドする
NODE_ENV=development npx webpack
成果物に src/index.html
が含まれるようになったので、ブラウザで開いてみるとちゃんとReactが動作し、Hello worldが表示されている
webpack-dev-serverの導入
ビルド確認のために毎回htmlを開くのは大変面倒なので、webpack-dev-serverで開発用のサーバーを立てる
npm install -D webpack-dev-server
から NODE_ENV=development npx webpack-dev-server
で起動する
これで http://localhost:8080/ で表示することができる
静的なファイルをReactで扱えるようにする
CSS
まずはよくあるreset.css的なものを読み込めるようにする
そのためにはJSファイル内で読み込まれるCSSを文字列としてJSの世界に持ち込むことができるようになるcss-loaderと
JSの世界に持ち込まれたCSS文字列をDOMに挿入する役割を担うstyle-loaderの2つを利用する
npm install -D css-loader style-loader
ローダーを有効にする
ローダーはどういうわけか後ろから読み込まれるので、文字列としてCSSを読み込むcss-loaderを後に書く必要がある
useの部分の指定の順番は非常に大切
module.exports = {
output: {...},
module: {
rules: [
{...},
{
test: /\.(css)$/,
use: [
"style-loader",
"css-loader"
]
}
],
},
plugins: [...]
}
設定が完了したので、今回はmodern-css-reset( https://github.com/andy-piccalilli/modern-css-reset/blob/e7500a6c7fa35be8d23f95b6e85f2cde0203f422/dist/reset.css )を読み込んでみる
src/reset.css
に配置し、 src/index.tsx
に import './reset.css'
の一文を追加すると、反映されていることが確認できる
画像
次は file-loader
を使って画像を読み込んでみる
npm install -D file-loader
webpackの設定に追加する
module.exports = {
output: {...},
module: {
rules: [
{...},
{...},
{
test: /\.(png)$/,
use: ["file-loader"]
}
],
},
plugins: [...]
}
コンポーネントで読み込む
import React from 'react'
import ReactDOM from 'react-dom'
import './reset.css'
import Img from './example.png'
ReactDOM.render(
<div>
Hello world
<img src={Img}></img>
</div>,
document.getElementById('root')
)
しかし、このままでは以下のようなTSのエラーが発生し、webpackのビルドが通らない
Cannot find module './example.png' or its corresponding type declarations.
これは自分で型定義ファイルを作成する必要があるらしい(アンビエント宣言)
https://typescript-jp.gitbook.io/deep-dive/type-system/intro/d.ts
好きな場所に image.d.ts
のようなファイルを作成し、以下の内容で保存する
declare module '*.png'
これでwebpackのビルドが通るようになり、TS+React+webpackの設定が完了した
TS導入の際に、TSはトランスパイラとしての役割を担えると書いたが、ビルド後のjsファイルを見てみるとちゃんとアロー関数などがES5向けにコンパイルされていることも確認できる
今回のコードはここに置いておいた