はじめに
Webpack+Reactの構成を作成する際にJSXを使う場合そのままではブラウザでJSXが読み込めないのでエラーになりますので、JSXの変換にはBabelが必要ですが、 Babelを使用してもそのままではJSXの変換はできません。とりあえず@babel/preset-reactを入れると動くようになりますが、@babel/preset-reactがどういう構成になっているのか気になったので調べたメモ。
ドキュメントによると@babel/preset-reactは以下の3つのプラグインが常に追加されます。 なので以下のプラグインについて調べ てみます。
- @babel/plugin-syntax-jsx
- @babel/plugin-transform-react-jsx
- @babel/plugin-transform-react-display-name
下準備
とりあえず調べる用に最小構成でプロジェクトを作成します。
$ npm init -y
React関連
$ npm install react react-dom
webpack関連
$ npm install -D webpack webpack-cli webpack-dev-server
// 必要なファイルを作成
$ mkdir public src
$ touch webpack.config.js src/index.js src/App.jsx public/index.html
ファイルの中身はそれぞれ以下のように修正します。
package.json
{
"scripts": {
"serve": "webpack serve",
"build": "webpack"
}
}
webpack.config.js
const path = require("path");
module.exports = {
mode: "development",
entry: path.resolve(__dirname, "src/index.js"),
output: {
path: path.resolve(__dirname, "public/js"),
filename: "bundle.js"
},
resolve: {
extensions: [".js", ".jsx"]
},
target: ["web", "es6"],
devServer: {
open: true,
overlay: true,
contentBase: path.resolve(__dirname, 'public'),
publicPath: "/js",
hot: true
}
};
src/index.js
import React from "react";
import ReactDom from "react-dom";
import App from "./App";
ReactDom.render(<App />, document.getElementById("root"));
src/App.jsx
import React from "react";
const App = () => {
return (
<div>
<h1>Hello React</h1>
</div>
);
};
export default App;
public/index.html
<!DOCTYPE html>
<html lang="en">
<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>Simple React Webpack Babel</title>
</head>
<body>
<div id="root"></div>
<script src="/js/bundle.js"></script>
</body>
</html>
npm run build
でエラーになりました。JSXを解釈できていないみたいです。
ERROR in ./src/index.js 5:16
Module parse failed: Unexpected token (5:16)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| import App from "./App";
|
> ReactDom.render(<App />, document.getElementById("root"));
|
webpack 5.45.0 compiled with 1 error in 30 ms
Babelの設定
@babel/plugin-syntax-jsxから調べてみます。
@babel/plugin-syntax-jsx
とりあえずWebpackにBabelの設定を追加します。
$ npm install -D @babel/core babel-loader @babel/plugin-syntax-jsx
Webpackの設定に以下を追加してBabelが含まれるように修正します。
webpack.config.js
{
...,
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
plugins: ["@babel/plugin-syntax-jsx"]
}
}
]
}
]
},
...
}
$ npm run build
Uncaught Error: Module parse failed: Unexpected token (5:16)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| import App from "./App";
|
> ReactDom.render(<App />, document.getElementById("root"));
|
at Object../src/index.js (bundle.js:10)
at startup:5
at startup:5
はいエラーが発生しました。
@babel/plugin-transform-react-jsxの実行
@babel/plugin-transform-react-jsxに変更して実行してみます。
$ npm install -D @babel/plugin-transform-react-jsx
{
- plugins: ["@babel/plugin-syntax-jsx"],
+ plugins: [@babel/plugin-transform-react-jsx]
}
$ npm run start
ビルドができてレンダリングもされました。だとしたら@babel/plugin-syntax-jsxは何をしているのだろうか? とりあえずドキュメントに書いてる内容を参考に実行してみる。
Babelコマンドをインストールします。
$ npm install -D @babel/cli
$ npx babel --plugins @babel/plugin-syntax-jsx src/App.jsx
import React from "react";
const App = () => {
return <div>
<h1>Hello React</h1>
</div>;
};
export default App;
次は@babel/plugin-syntax-jsxの指定なしで実行してみる。
$ npx babel src/App.jsx
SyntaxError:...
構文エラーが発生しました。@babel/plugin-syntax-jsxは単なるjsxの構文の解釈だけをしているということみたい。
@babel/plugin-syntax-jsxがjsxの構文を解釈できるようにし、@babel/plugin-transform-react-jsxがjsxの変換を行う。
ところで@babel/plugin-transform-react-jsxだけ 指定してもエラーにならないのはなぜだろうか?
@babel/plugin-transform-react-display-name
@babel/plugin-transform-react-display-nameですが正直良くわかりませんでした。 Chrome拡張の React Developer Tools で調べてみるとコンポーネント名が正しく表示されない問題を解決するものかと思ったのですが、 React Developer ToolsのComponentsを確認すると正しく表示されていました。
サンプルが悪いのでしょうか? ひとまずWebpack+Reactの時は脳死で@babel/preset-reactで追加すると思うのでわかり次第追記したいと思います。
さいごに
Webpackはとても普及していてネットでも色々な記事を見かけますがBabelのプラグインに含まれているのに自分でプラグインを含めていて指摘されているものも良く見かけます。 重複して入っていたとしても大きな問題はない場合はあるとは思いますが少し恥ずかしいなと思っています。
そうならないためにもWebpackを使う身としては良く使うBabel Pluginはどういう設定が含まれているかなどは確認しておくのはありかなと思いました。勉強にもなる気がします。