React とは
Web サイトを作成するときに React を採用すると、HTML をフラットな形でゴリゴリ記述していくのではなく、独自コンポーネント(例: <MyButton>
コンポーネント)を定義してまとまりのある単位でサイトを構築していくことができます。
Web Components という同様な技術の標準化が進んでいますが、しばらくは React のようなコンポーネントライブラリが使われるでしょう。
ここでは React を使った Web サイト開発用に、下記のようなツールを組み合わた環境を構築します。
- React … コンポーネントベースで Web サイト構築するためのライブラリ
- TypeScript … JavaScript を型付けできるようにした言語
- webpack … Web サイトのリソースをバンドルするためのツール
この環境構築方法を理解すれば、React を利用した Web サイトをどんどん作ることができます。 ちなみに、上記のすべてのツールは Node.js 上で動作するため、Node.js がインストールされていない場合は先にインストールしてください。
TypeScript、React、webpack のインストール
チュートリアルなどでは、create-react-app
を使って React アプリの雛形を生成する方法がよく載っていますが、よくわからないモジュールが勝手にインストールされるのは気持ち悪いので、ここでは自力で各モジュールをインストールしてきます。
create-react-app myapp --template typescript
のように実行します。
このコマンドによって作成された雛形をリファレンスにするのがよいかなと思ったのですが、少なくともバージョン 3.4.1 時点で生成される雛形はかなり怪しいです。
例えば、TypeScript の処理系や型定義ファイルが devDependencies
ではなく、dependencies
でインストールされるようになっていたりします。最終的に Web サーバーにデプロイするファイル群は webpack で生成(バンドル)することを想定しているので、npm
(or yarn
) でインストールするモジュールは、 すべて devDependencies
(開発用モジュール)としてインストール していきます(Web サーバー側で npm install
を実行することはないということです)。
プロジェクトの作成
プロジェクト用のディレクトリがなければ作成し、package.json
ファイルを作成しておきます。
$ mkdir myapp && cd myapp
$ npm init -y
各モジュールのインストール
TypeScript をインストールします。
$ npm install --save-dev typescript
React 関連のモジュール(react
、react-dom
)と、その型定義をインストールします。
本体の方は実行時にも使用するので、--save
オプションでインストールする必要があります。
$ npm install --save react react-dom
$ npm install --save-dev @types/react @types/react-dom
webpack 関連のモジュールをインストールします。
コマンドラインツールの webpack-cli
、TypeScript コードを認識させるための ts-loader
、HTML ファイルを生成するための html-webpack-plugin
も一緒にインストールします。
$ npm install --save-dev webpack webpack-cli ts-loader html-webpack-plugin
確認
ここまでで、package.json
内の依存定義 (devDependencies
) は次のようになっています。
{
// ...
"dependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"devDependencies": {
"@types/react": "^16.9.41",
"@types/react-dom": "^16.9.8",
"html-webpack-plugin": "^4.3.0",
"ts-loader": "^7.0.5",
"typescript": "^3.9.6",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12"
}
}
設定ファイル
ディレクトリ構成
下記のようなディレクトリ構成を想定して、各種ツールの設定を行っていきます。
myapp/
+-- package.json # Node プロジェクトの設定
+-- tsconfig.json # TypeScript の設定
+-- webpack.config.js # webpack の設定
+-- dist/ # webpack の出力先
+-- src/ # ソースコード
+-- index.html
+-- index.tsx
+-- ...
ソースコードや各種リソースファイルは src
ディレクトリ以下に作成し、webpack によるバンドル結果を dist
ディレクトリに出力します。
最終的に dist
ディレクトリの中身を Web サーバーにデプロイすることになります。
ルートディレクトリには、設定ファイル以外のファイルをなるべく置かないようにするとスッキリします。
webpack の設定
Web サイト用のコンテンツは webpack
コマンドにより生成するため、webpack の設定は重要です。
webpack は、ここで指定されたエントリーポイント(.js
あるいは .ts
ファイル)を起点にファイルの依存関係を認識し、それらのファイルをバンドルします。
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 開発用の設定
mode: 'development',
// エントリポイントとなるコード
entry: './src/index.tsx',
// バンドル後の js ファイルの出力先
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js'
},
// import 時に読み込むファイルの拡張子
resolve: {
extensions: ['.js', '.json', '.ts', '.tsx']
},
// ソースマップファイルの出力設定
devtool: 'source-map',
module: {
rules: [
// TypeScript ファイル (.ts/.tsx) を変換できるようにする
{
test: /\.tsx?$/,
use: "ts-loader",
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/
}
]
},
plugins: [
// HTML ファイルの出力設定
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
};
Web サイト用のクライアントスクリプトを TypeScript で作成する場合は、.ts
ファイルおよび、.tsx
ファイルを ts-loader
で処理するように指定しておく必要があります。
webpack はあくまでバンドルツールなので、HTML ファイルの出力などはオプショナルな振る舞いになります。
上記の例では、html-webpack-plugin
の機能を使って、src/index.html
から dist/index.html
を生成するように設定しています。
TypeScript の設定
webpack によりデプロイ用のファイル群を生成する場合、TypeScript のトランスパイルも webpack 経由で実行することになります(tsc
コマンドは直接実行しない)。
TypeScript の設定ファイルでは、基本的な変換ルールだけ定義しておきます。
ほとんど空っぽでも動くはずですが、.tsx
ファイル内の JSX コードを認識させるための設定は必須です。
{
"compilerOptions": {
"target": "ES2015",
"module": "commonjs",
"lib": ["esnext", "dom"],
"jsx": "react", // .tsx ファイル内の JSX 記述を認識
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
// 出力先などは webpack 側で指定するので本質的には必要なし
"sourceMap": true,
"outDir": "./dist",
"sourceRoot": "./src",
}
}
Hello World の実装
基本的な設定が終わったので、React を使って独自の <Hello>
コンポーネントを作る実装を行います。
src/index.html
トップページとなる index.html
ファイルを作成します。
script
要素は webpack が勝手に挿入してくれるので、最小限の要素だけ記述しておけば OK です。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>MyApp</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="root"></div>
</body>
</html>
src/index.tsx
Web アプリのエントリポイントとして設定したスクリプトを作成します。
ここでは、React コンポーネントとして Hello
コンポーネントを作成し、HTML のルートに配置した div
要素の内容として表示します。
import * as React from 'react';
import * as ReactDom from 'react-dom';
// Hello コンポーネントの属性(プロパティ)を定義
interface HelloProps {
name?: string; // オプショナルな name 属性
}
// Hello コンポーネントを定義
class Hello extends React.Component<HelloProps> {
public render(): React.ReactNode {
const name = this.props.name ?? 'Unknown';
return (
<b>Hello, {name}!</b>
);
}
}
// Hello コンポーネントを <div id="root"> に表示
ReactDom.render(
<Hello name="React" />,
document.getElementById('root')
);
ビルド
次のように webpack
コマンドを実行すると、dist
ディレクトリ以下に Web サイト用コンテンツが出力されます。
$ npx webpack
Web ブラウザで dist/index.html
を開いて、Hello, React! と表示されれば成功です。
あとは必要に応じて、npm run build
でビルドを実行できるようにスクリプトを定義しておきます。
{
"name": "myapp",
"version": "0.0.1",
"scripts": {
"build": "webpack"
},
"devDependencies": {
// ...
}
}
関連記事
- Electron で Hello World (2) TypeScript で開発できるようにする
- Node.js で GitHub REST API を使用する (@octokit/rest)
- TypeScriptの型: インタフェースのプロパティを読み取り専用にする (readonly)
- TypeScriptの型: インタフェースを定義する (interface)
- TypeScriptの型: 関数を定義する (function)
- Azure Table Stroage を使ってみる: TableService を Promise 化して使いやすくする
- TypeScript: 2つの変数の値をスワップする