借り物の React を卒業して Web開発へ
前回は Next.js のドキュメントにある「React Foundations」というコースを辿りながら React にどんな機能があるのかを学びました。
その中で最も手軽に React をWebページに組み込む方法として、JavaScript のライブラリのように CDN を読み込む手順を学びました。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/jsx">
const app = document.getElementById('app');
ReactDOM.render(<h1>Develop. Preview. Ship. 🚀</h1>, app);
</script>
</body>
</html>
JavaScript のライブラリを読み込んでDOMの要素を操作するのは、Web 制作の現場では馴染みのあるやり方ですよね。
ブラウザの開発者ツールは静かに警告する
こちらにあるコードをブラウザで確認すると「Develop. Preview. Ship. 🚀」というメッセージが表示されるのですが、実は開発者ツールのコンソールには警告が表示されています。
You are using the in-browser Babel transformer. Be sure to precompile your scripts for production - https://babeljs.io/docs/setup/
こわっ
警告の意味は「読み込んでいる Babel はブラウザ用にカスタマイズされたものなので、本番環境で使うときには必ずコンパイルしたスクリプトを使ってね。」というものです。
身に覚えのない警告ほど怖いものはないですね。
最新の仕様とブラウザによるサポートをつないでくれている Babel さん
そもそも Babel は仕様の異なる JavaScript をブラウザで解釈できる形に変換するトランスパイラと呼ばれるツールで、Web 開発の現場で使われているツールのひとつです。
なぜ Web 開発の現場で Babel が必要かと言うと、毎年のように更新されている最新仕様の JavaScript をブラウザが解釈できる形に変換する必要があるからです。
最新仕様の JavaScript は「ブラウザ越しに提供できるサービスをより良く」できるよう日夜改良が続けられているので開発上は便利で都合が良いものの、その仕様を必ずしもすべてのブラウザがサポートしている訳じゃないので、変換を必要とするわけです。
そもそも React は JavaScript で書かれている訳ではなく、JSX という JavaScript の構文拡張機能で記述されているので JSX で記述した React をそのままブラウザで確認しようとしても失敗してしまいます。
そこで CDN で読み込まれた Babel さんが「JSX で記述された React を JavaScript に変換してブラウザで表示」しているわけですね。
そんな Babel さんが「本番で使うんだったらちゃんとコンパイルしなよ。」と警告してくる訳なので、無視していて良いことがあるはずありません。
CDN 版 React からの卒業と Web 開発の始まり
開発者ツールの警告にある https://babeljs.io/docs/setup/というリンクを開くと、驚くほどいろんな方法で Babel を使ったトランスパイルの方法が提供されているのがわかります。
今回は webpack で babel をトランスパイルする方法を試そうと思います。
webpack は、複数の JavaScriptファイルを1つにまとめるモジュールバンドラーというツールです。JavaScript ファイルを1つにまとめることで、
ページの HTTP リクエストの数を減らす。
変数の競合を防ぐ。
変数のグローバル汚染を防ぐ。
コードの可読性を上げ、開発作業の分担やテストがしやすくなり、結果的にコードの再利用性、保守性、開発の安全性を高めることができるようになるみたいです。
「複数の JavaScriptファイルを1つにまとめる」こと自体に、上記のようなメリットが生じることの方が驚きですよね。
個人的にはここが「コーダー」と「エンジニア」を分ける分水嶺だと思っています。
webpack + babel 構成でつくる React の開発環境
ここからは私が愛してやまない ICS MEDIA の記事を参考にしながら開発環境をつくっていこうと思います。
元の記事では webpack + babel + React 構成のほか、jQuery や Three.js 、 Vue と組み合わせた場合など多様な組み合わせの環境について解説してくださっているので、本格的な環境構築はそちらで学習してみてください。
また、ICS MEDIA では webpack の使い方から解説してくださっているので、webpack にピンと来ていない方はそちらから始めると良いと思います。
手順1. 作業ディレクトリを npm で初期化
作業ディレクトリ `/mnt/d/virtual-environment/_dev/practice-webpack-01` へ移動し、`npm init`コマンドで `package.json` ファイルを生成します。
mkdir practice
cd practice
npm init -y
手順2. 開発に必要なモジュールをインストール
開発用に必要なモジュールをインストールします。
webpack
webpack-cli
babel-loader
@babel/core
@babel/preset-env
@babel/preset-react
npm install -D webpack webpack-cli babel-loader @babel/core @babel/preset-env @babel/preset-react
手順3. React をインストール
React と React DOM をインストールします。
npm install react react-dom
手順4. ソースコードをビルドするコマンドを設定
package.json ファイルを編集し、`npm scripts` を記述します。
{
"scripts": {
"build": "webpack",
}
}
手順5. webpack の設定ファイルを作成
package.json ファイルと同じ階層に webpack の設定ファイル( webpack.config.js )をつくります。
touch webpack.config.js
手順6. webpack の挙動を設定
webpack.config.js ファイルを以下のように編集します。
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
path: __dirname + '/dist',
filename: 'main.js',
},
module: {
rules: [
{
// 拡張子 .js の場合
test: /\.js$/,
use: [
{
// Babel を利用する
loader: 'babel-loader',
// Babel のオプションを指定する
options: {
presets: [
// プリセットを指定することで、新しいESをES5に変換
'@babel/preset-env',
// React の JSX を解釈
'@babel/react',
],
},
},
],
},
],
},
// ES5(IE11等)向けの指定
target: ['web', 'es5'],
};
記述した設定内容は、以下のとおりです。
スクリプトの起点になる JavaScript ファイルを指定する。
ビルドしたスクリプトを保存するディレクトリとそのファイル名を指定する。
新しい仕様のスクリプトと JSX をプリセットに沿って変換する。
ビルドコマンドで生成したスクリプトを圧縮する。
手順7. ページとエントリーポイントを準備
作業ディレクトリにエントリーポイントと表示用のページを用意する。
エントリーポイントとは、webpack を使ったバンドル処理とbabelを使った変換処理の起点になる JavaScript ファイルのことです。
mkdir src
touch src/index.js
mkdir dist
touch dist/index.html
`src/index.js`ファイルを編集する。
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component {
render() {
return (
<div>
<h1>Develop. Preview. Ship. 🚀</h1>
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector('#app'));
`dist/index.html`ファイルを編集する。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Practice 02</title>
</head>
<body>
<div id="app"></div>
<script src="./main.js"></script>
</body>
</html>
手順8. ソースコードをビルド
ターミナルから `npm run build` コマンドを実行し、トランスパイルされた JavaScript を生成します。
npm run build
先に設定されたエントリーポイントを起点に処理を行い、最終的に変換した JavaScript ファイルを出力します。
出力された JavaScript ファイルを HTMLファイルから読み込めば、JavaScript に変換された React が表示できるようになります。
冒頭でつくったページと同様「Develop. Preview. Ship. 🚀」と表示されるページが最終的に生成されますが、そこには Babel からの警告はありません。
まとめ
CDN で構成された借り物の React を、webpack + babel でビルドされた JavaScript に変換して、React のあるべき形にしてみました。自分なりに解釈して説明したつもりですが、その過程で何度も挫けそうになるくらいには複雑ですし、ある程度のリテラシーがないと難解だと思います。
難解ついでにトドメを刺すわけではありませんが、実は webpack + babel という構成は選択肢のひとつに過ぎず、手軽さにおいては vite (rollup) の方がとっつきやすいかもしれません。
さらに言えば「(今回取り扱ったような)面倒なところ全部請け負うからさ、俺使いなよ。」とNext.js や Remix や Astro といったフレームワークは囁いてくるわけです。
ブラウザで実行されている JavaScript は目の前にあるにも関わらず「ゆく河の流れは絶えずして、しかも、もとの水にあらず。」みたいな気分になりますよね。
この記事が気に入ったらサポートをしてみませんか?