webpackとBabelによるモダンなフロントエンド開発環境構築方法 React編
高橋 まり
JavaScriptに強くなる!……その前に簡単な記述から。
WEB工房しずおかの高橋です。
jQuery編に引き続き、今回はReactの開発環境構築の方法をご紹介いたします。
今回、皆様にご紹介するための「作例」に取り組んだのですが、私自身がまだまだ初級者。ということで恥ずかし~い失敗もいたしました。その失敗に気付く過程もご紹介することで、反面教師にしながら学習を進めてほしいと思います。
package.jsonの生成と、npmによる必要なモジュールのインストール~React編
今回も、ics.media様によるこちらの記事を参考にいたしました。
まずは、任意のディレクトリをカレントディレクトリに設定し、コマンドプロンプトで下記のコマンドを打ちます。
npm init -y
npmを使う前のお馴染みの「初期化処理」であり、「package.json」を生成してくれるコマンドです。
続いて、以下のコードを打ち込んで、必要なモジュールのインストールを行います。
npm install -D webpack webpack-cli babel-loader @babel/core @babel/preset-env @babel/preset-react
- 「webpack」
- 「webpack-cli」
上記のふたつが、webpackを操作するために必要なモジュール。
Babelのために必要なのが、下記の3つのモジュール。
- 「babel-loader」(webpackと組み合わせるために必要)
- 「@babel/core」(Babel本体)
- 「@babel/preset-env」(Babel本体)
上記の5つはjQuery編でご紹介しましたが、今回はもう一つ、
- 「@babel/preset-react」
なるモジュールが必要です。
これは、Reactで使われる、特有の**「JSX」**をBabelに解釈してもらうために必要なものです。
JavaScriptは、そのままではJSXのコードの中のHTMLがわかりません。それをわかるようにしてくれるのがこのモジュールです。
npmを作って管理してくれる人たち、Reactを設計して作った人たちって、凄いなぁ。
そして忘れてはいけない、実行するためのReact本体のモジュールも必要です。
npm install react react-dom
上記の計7つのモジュールをインストールすると、package.jsonはこのような内容になっているかと思います。
「script」の部分には「build」でwebpackをスタートさせるように記述しています。(例によって必要じゃない箇所は省いて記載しております)
{
"scripts": {
"build": "webpack"
},
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"@babel/preset-react": "^7.10.4",
"babel-loader": "^8.1.0",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12"
},
"dependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1"
}
}
2.webpackの設定ファイル(webpack.config.js)を用意する
続いて、webpackの挙動を制御するJavaScriptファイル「webpack.config.js」が必要です。
jQuery編とさほど大きく変わってはいないものの、「presets」内に@babel/preset-envだけでなく、@babel/preset-reactも記載いたします。
こうすることで、JavaScriptの新しい記述方法だけでなく、JSXの記述ぶりもBabelが理解してトランスパイルしてくれるようになるんですね!
module.exports = { // モード値を production に設定すると最適化された状態で、 // development に設定するとソースマップ有効でJSファイルが出力される mode: "production", // メインとなるJavaScriptファイル(エントリーポイント) entry: "./src/index.js", // ファイルの出力設定 output: { // 出力ファイルのディレクトリ名 path: `${__dirname}/dist`, // 出力ファイル名 filename: "main.js", }, module:{ rules:[ { // 拡張子 .js の場合 test:/\.js$/, use:[ { // Babel を利用する loader: "babel-loader", options: { presets: [ // プリセットを指定することで、ES2020 を ES5 に変換 "@babel/preset-env", // React の JSX を解釈 "@babel/preset-react" ], }, }, ], }, ], }, };
3.Reactを使った簡単な作例
今回も、簡単な作例を用意したうえで、ご紹介いたします。この作例から、ReactによるWebページの表示される過程と様子をイメージしていただければと思います。
まずは、HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>React</title>
<script src="./dist/main.js"></script>
</head>
<body>
<main>
<h1>webpack+Babel+Reactの作例</h1>
<div id="root">
Wait...
</div>
</main>
</body>
</html>
ReactはJavaScript(JSX)の中に必要な内容を記述していくので、読み込ませるためのHTMLはシンプルにしております。
mainタグの中にdiv#root
なる部分がございます。この中に、次に紹介するsrc/index.js内に書いた「コンポーネント」が表示されることになります。
let dom = document.querySelector('#root');
const msg1 = {
fontSize: "24px",
fontWeight: "bold",
padding: "16px",
backgroundColor: "royalblue",
marginBottom: "16px"
};
const msg2 ={
fontSize: "14px",
fontWeight: "nomal",
padding: "16px",
backgroundColor: "orchid"
};
function Welcome(props){
return <p style={props.style}>いらっしゃい!{props.name}さん</p>;
}
function Ara(props){
return <p style={props.style}>あら、{props.name}さんも来てたの……?</p>;
}
let el = (
<div>
<Welcome style={msg1} name="良彦" />
<Ara style={msg2} name="良子" />
</div>
);
ReactDOM.render(el, dom);
こちらが、webpack実行のベースになる「src/index.js」です。
掌田津耶乃・著『React.js&Next.js超入門』を参考にしながらひねり出した記述です。現段階での私の理解が至らないこともあり、コンポーネントはシンプルなpタグを出力するものにいたしました。(唐突に嫁いびり?する姑さん?が登場するのには特に意味はありません)
これがReactの記述……!そしてJSX……!
解説していくと、
- document.querySelector('#root')で、HTML内の
div#root
部分のオブジェクトを取得する。そして変数domに代入。 - 配列「msg1」「msg2」の中にJSXの仕様に沿ってスタイルを記述。ハイフンではなく「キャメルケース」によって書き、値はクオートで囲む。オブジェクトの「リテラル」として記述する、とも言われる。
- 続いて関数によるコンポーネントの定義。「大文字で始まる名前」であることが大事。小文字だとコンポーネントとして認識されません。
- 「Welcome」「Ara」の二つの関数に、「props」という引数を付与しておくことで、後でコンポーネントに「style」「name」など属性が付与できる。
- 変数elは、画面上に表示させたい「エレメント」である。中に「コンポーネントタグ」を記載しておき、属性に配列を指定したり、名前の文字列を渡す。するとコンポーネント側でそれを取り入れて解釈される。
- 最後に「ReactDOM.render()」で引数に指定したエレメントをレンダリングすることで、HTMLに読み込まれた際にコンポーネントが画面に表示される。
- 「ReactDOM.render()」の二番目の引数である変数domは、
div#root
、つまりレンダリングする「場所」を指定するものである。 - 「ReactDOM.render()」のもう一つの注意点。それは「ひとつのエレメントしかレンダリングできない」こと。なので、
<div></div>
で囲ってひとつのエレメントにまとめます。
そして最後に、
- 「package.json」ファイル
- 「webpack.config.js」ファイル
- index.jsを含んだ「src」ディレクトリ
- 「node_modules」ディレクトリ
上記のファイルやディレクトリが、全てカレントディレクトリ内の同じ階層に存在していることを確かめたうえで、いよいよコマンドプロンプトに下記のコードを記述します。
npm run build
コマンドプロンプトが何やら働きだして、webpack.config.jsに記載したとおり、カレントディレクトリ内に「dist」ディレクトリが作成され、中に「main.js」が存在していればトランスパイルとバンドルが成功です。
本来だったら「Wait...」という文字列が表示されるところですが、コードの中に唐突に登場した嫁いびり?する姑さん?のセリフが画面上に現れたら成功です!
4.ところが!?~私の失敗を反面教師にしてください。
夜更けに今回の作例のコードを模索し、「package.json、オッケー!webpack.config.js、オッケー!index.js、オッケー!」とワクワクしていた矢先のことです。
「よし、npm run build
をした!」
しかしながら、生成されたdist/main.jsを読み込んだindex.htmlをブラウザで開くも、設定した嫁いびり姑さんのセリフは表示されませんでした。何度微調整しても「Wait...」のままです。
おかしいな!?ということで、困った私は、エンジニアの皆様にお馴染みの質問サイト「teratail」に投稿いたしました。
こちらがその投稿質問記事でございます。
マークダウン方式による記事の書き方、スクリーンショット画像、コードの記載も問題ないと思った翌日。親切なユーザー様から回答をいただけ、解決に至りました。
その原因というのがですね……!
** index.html内の、dist/main.jsを読み込むためのscriptタグの記述位置 **なのです。
先ほどのindex.htmlをもう一度ご覧ください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>React</title>
<script src="./dist/main.js"></script> <!-- ←この行にご注目 -->
</head>
<body>
<main>
<h1>webpack+Babel+Reactの作例</h1>
<div id="root">
Wait...
</div>
</main>
</body>
</html>
scriptタグを、headタグの後半に記述しておりました。
dist/main.jsの中には、コンポーネントをレンダリングすべきエレメント、div#root
を指定する記述があります。
しかしながら、scriptタグがHTMLの上部にあることから、dist/main.jsが読み込まれた時にはブラウザ上でページが読み込まれていません。
つまり、dist/main.jsで指示されたdiv#root
が存在しないものとプログラムが判断したためエラーが発生、画面上にコンポーネントが表示されなかったのでした!
回答を見た私は慌てて、index.htmlの内容を編集いたしました。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>React</title>
</head>
<body>
<main>
<h1>webpack+Babel+Reactの作例</h1>
<div id="root">
Wait...
</div>
</main>
<script src="./dist/main.js"></script> <!-- ←この行にご注目 -->
</body>
</html>
bodyタグの直前です。
そして再度ブラウザで開いたところ……!
無事、姑さんのセリフが画面に表示されました。
JavaScriptで要素を表現するReactですが、うかうかしてたらこのようなミスが現れるのですね。
初歩的なミスをやらかしてしまい、お恥ずかしい限りです。
是非とも、反面教師にしてお気を付けください!
さいごに
私がスクールでWeb制作を学んだのは、2018年の頃でした。
JavaScriptに関して、要約すると「変数はvarで宣言する。でもその書き方は徐々に古くなっており、letで宣言するようにもなった。しかしながら今でもvarは使われているけどね。」というカリキュラム内容に、「なんだそりゃ」と思ったものです。
その後、ProgateのJavaScript講座で「ES5」「ES6」などの概念を理解して腑に落ちましたけど、その当時からJavaScriptは恐ろしく進化を遂げているのですね。
「クラス」の概念にはおののくし、「オブジェクト指向」などの概念もまだまだ触れたばかりで、理解が浅いです。
でも、だからこそワクワクいたします。
モダンなフロント開発環境を構築のうえで、生き馬の目を抜くようなWeb業界で生き残っていきたいところですね。
高橋でした!