概要
React公式サイトのチュートリアルでは、React入門者に対してcreate-react-app
コマンドによりReactのプロジェクトを作成することを勧めています。このコマンドを実行することで簡単にReactの実行環境が整います。しかし、このコマンドの裏では沢山の処理が動いており、Reactやフロントエンド初心者にとって、Reactの内部がブラックボックスになる原因になっていると思います。
そこで、この記事ではcreate-react-app
コマンドを使わずにcreate-react-app
を使うのと変わらないような開発環境を構築することを目指します。
事前準備
Node.JSのインストール
npm
コマンドが使えるようにNode.JSをインストールして下さい。Node.JSのインストールは良い解説が他に沢山あるので、この記事では解説しません。
npmのプロジェクトの作成
これから作業を行うnpmのプロジェクトを作成します。
npm init
コマンドを使うことで、カレントディレクトリをnpmのプロジェクトにすることができます。ディレクトリの名前は何でも構いません。
例ではmy-react-sample
という名前にしています。
mkdir my-react-sample
cd my-react-sample
npm init
webpackの導入と動作確認
以下の手順ではwebpackの公式チュートリアルを参考にwebpackの導入を進めます。
webpack
とはJavaScript言語用の依存関係解決ツールのようなものです。Javaでのgradle/groovy
やC++でのCMake
に近いと思います。
基本的にReactはwebpackとセットで使われます。
webpackのインストール
webpack
とwebpack-cli
をインストールします。
npm install --save-dev webpack webpack-cli
ファイルの作成
webpackの動作確認のために以下のようにindex.html
とindex.js
とディレクトリを作成します。
myReactSample
|- package.json
+ |- /dist
+ |- index.html
+ |- /src
+ |- index.js
このような階層になるように作ります。
index.htmlの内容を作成
index.html
を以下のようにしてください。
<!doctype html>
<html>
<head>
<title>Getting Started</title>
</head>
<body>
Hello!
</body>
</html>
index.html
ファイルをブラウザで開くと、当然Hello!
と表示されます。
index.jsの内容を作成
index.jsを以下のようにしてください。
function component() {
const element = document.createElement('div');
element.innerHTML = "Webpack!"
return element;
}
document.body.appendChild(component());
body
に<div>Webpack!</div>
を追加しているだけですね。
index.htmlからmain.jsを読み込む
main.jsを読み込むために、index.htmlに以下のように<script src="main.js"></script>
を追加しています。
<!doctype html>
<html>
<head>
<title>Getting Started</title>
</head>
<body>
Hello!
<script src="main.js"></script>
</body>
</html>
webpackではデフォルトでsrc/index.js
を入力としてdist/main.js
に依存関係が解決されたJavaScriptファイルを出力します。これをwebpackによるビルドと言います。
dist/index.html
からビルド成果物であるdist/main.js
を読み込むことでプログラムを動かすことが出来ます。
index.html
とmain.js
の両方ともdist
ディレクトリ内であるため、相対パスでmain.js
を指定して読み込めばよいです。
webpackでのビルド
以下のコマンドを打ち込むと、src/index.js
がdist/main.js
にビルドされます。
npx webpack
myReactSample
|- package.json
|- /dist
|- index.html
+ |- main.js
|- /src
|- index.js
このような階層になっているはずです。この状態でindex.html
をブラウザで開くとHello!
の下にWebpack!
が表示されるはずです。
正しく表示されたなら、Webpackの導入は成功です。おめでとうございます!次にWebpack DevServerの導入を行います。
Webpack DevServerの導入と動作確認
Webpack DevServerとは、プロントエンド開発用に開発PC上で立ち上げる、ローカルのHTTPサーバーです。JavaScriptファイルを更新した際に自動でWebPackのビルドの実行とページの更新を行ってくれるので非常に便利です。ちなみに、create-react-app
コマンドを使った際は自動で入ります。
Webpack DevServerのインストール
以下のコマンドでWebpack DevServerをインストールします。
npm install --save-dev webpack-dev-server
プロジェクトのルートにwebpack.config.js
を作ります。
myReactSample
|- package.json
+|- webpack.config.js
|- /dist
|- index.html
|- main.js
|- /src
|- index.js
webpack.config.js
を以下のように編集します。
var path = require('path');
module.exports = {
mode: 'development',
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000
}
};
これはwebpackの設定ファイルです。
まず、webpackのビルドをdevelopment
モードに指定しています。
また、devServer
内でWebpack DevServerがホストするコンテンツのディレクトリの指定やportの指定などをしています。
Webpack DevServerの動作確認
コンソールでWebpack DevServerを起動します。
npx webpack-dev-server
localホストでサーバーが起動します。9000
番ポートを指定してブラウザで開いて下さい。
うまく行かない場合はwebpack.config.js
でコロンが足りないなどでエラーになっている事があります。
正しく設定が出来ると、index.js
を編集して更新した時に自動でリビルドとページの更新処理が行われます。
コンテンツ監視の設定
デフォルトの設定では、JavaScriptファイルを更新した時のみページの更新が行われます。HTMLファイルやCSSファイルの更新時にもページの更新が行われるようにするために、コンテンツ監視の設定をします。
以下のようにdevServer:
の中にwatchContentBase: true
を追記してください。
var path = require('path');
module.exports = {
mode: 'development',
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000,
watchContentBase: true
}
};
追記した後、コンソールでWebpack DevServerを再起動します。Ctrl + c
してから、以下のコマンドを実行して起動します。
npx webpack-dev-server
すると、jsファイルだけでなく、htmlファイルを更新した際も自動でページの更新が行われるようになります。
ここまで上手く行けばWebpack DevServerの導入は成功です!次にbabelの導入を行います。
babelの導入
babelのインストール
ReactではJSXという特殊なJavaScript拡張構文を使います。JSXを使えるようにするためにJSトランスパイラであるbabelを導入します。
npm install --save-dev @babel/core babel-loader @babel/polyfill @babel/preset-env @babel/preset-react
webpack.configの変更
babelの利用をwebpack.configファイルのrules
内で指定します。
var path = require('path');
module.exports = {
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: "babel-loader",
options: {
presets: [
"@babel/preset-env",
"@babel/react"
]
}
}
]
}
]
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000,
watchContentBase: true
}
};
この状態でnpx webpack
コマンドを使ってビルドすることが出来れば、babelの導入は成功です!
Reactの導入
いよいよReactを導入します!ReactはJavaScriptのライブラリとして提供されています。まずはインストールします。
Reactのインストール
Reactはdevelopment
環境だけでなくproduction
環境でも必要であるため、--save-dev
オプションではなく--save
オプションを適用します。
npm install --save react react-dom
Reactを使う!
Reactは指定したidを持つDOM要素とその子要素を支配するという形で動作します。今回はroot
というid名を指定することにします。
index.htmlに<div id="root"></div>
を追加します。
<!doctype html>
<html>
<head>
<title>Getting Started</title>
</head>
<body>
<div id="root"></div>
<script src="main.js"></script>
</body>
</html>
index.jsでも同じidを指定します。ファイルの最後の方にある、ReactDOM.render内で指定しています。
import React from 'react'
import ReactDOM from 'react-dom'
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
)
}
}
function App() {
return (
<div>
<Clock />
<Clock />
<Clock />
</div>
)
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
このコードはReactの公式チュートリアルのstateとライフサイクルで紹介されているものです。時刻が更新され続ける文字が表示されたらReactの導入は成功です!お疲れ様でした!
TypeScriptの導入
静的言語で開発したくなる時があるのでTypeScriptでReactを使えるようにします。
TypeScriptのインストール
npm install --save-dev typescript ts-loader
tsconfigの作成
TypeScriptの設定ファイルであるtsconfig.json
ファイルを作成します。
myReactSample
|- package.json
|- webpack.config.js
+|- tsconfig.json
|- /dist
|- index.html
|- main.js
|- /src
|- index.js
以下のように編集します。
{
"compilerOptions": {
"sourceMap": true,
"target": "es5",
"module": "es2015",
"jsx":"react"
}
}
webpack.configの編集
TypeScriptトランスパイラの利用などをwebpack.configファイルで指定します。
var path = require('path');
module.exports = {
mode: 'development',
entry: "./src/index.tsx",
module: {
rules: [
{
test: /\.tsx$/,
use: "ts-loader"
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000,
watchContentBase: true
}
};
index.jsのリネーム
拡張子を".tsx"とすることで、TypeScriptのトランスパイラがJSX構文を扱うことが出来るようになります。
myReactSample
|- package.json
|- webpack.config.js
|- tsconfig.json
|- /dist
|- index.html
|- main.jsx
|- /src
+ |- index.tsx
- |- index.js
型定義ファイルのインストール
reactとreact-domをTypeScriptから使うために、それぞれの型定義ファイルをインストールします。
npm install --save-dev @types/react @types/react-dom
JavaScriptファイルをTypeScriptファイルに書き換える
- import文の書き換え
-
Props
,State
インターフェースの定義 -
Clock
クラスが継承するクラスをReact.Component
からReact.Component<Props, State>
へ変更
などを行っています。
import * as React from 'react';
import * as ReactDOM from 'react-dom';
interface Props {
}
interface State {
date: Date
}
class Clock extends React.Component<Props, State> {
timerID: any
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
)
}
}
function App() {
return (
<div>
<Clock />
<Clock />
<Clock />
</div>
)
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
webpackビルド
npx webpack
ビルドでエラーが出る場合はエラーメッセージを元に修正して下さい。
Webpack DevServerでのホスト
ビルドエラーが出なくなったらWebpack Devserverを起動します。
npx webpack-dev-server
TypeScript導入前と同じように、時刻が更新され続ける文字が表示されたらTypeScriptの導入は成功です!お疲れ様でした!
導入完了!
以上でReact、Webpack、Webpack DevServer、Typescriptの導入が完了しました!モダンなWeb開発はブラックボックスになりがちですが、一つずつ順番に導入することで裏側で何が動いているのか少しは明らかに出来たのではないかと思います!
Reactの初心者の方は、この後Reactの公式チュートリアルを進めてReactに慣れると良い思います。
既にある程度Reactに詳しい人は、WebpackやTypescriptのconfigファイルの設定一覧を見てみると良いと思います。今回の記事ではシンプルな設定にしましたが、設定できる便利な機能が沢山あります。