本日はcreate-react-app(CRA)を使用せずにReactアプリを構築したいと常に思っていた初心者様向けの入門記事となっております。
注意点として、この記事を読んで下さってる皆様はReactをすでに精通していると思います、なのでこの記事ではReactコードについては説明は致しません、ご了承下さいませ。
事前準備と条件
・ 当ブログの記事ではWindowsとなります。
・ VS Codeを使用します。
・ Node.js
・ JavascriptおよびES6からES8の構文に関する基本的な知識
・ React.jsの基礎に精通している
まずWebpackとは何かを理解してもらわなければいけません。
詳しくはこちらで解説しておりますので、まずはWebpack
とBabel
の基礎知識をある程度学びこの記事にお戻り下さい。
それではwebpackとbabelを使ってReactプロジェクトをセットアップしていく方法を解説していきます。
プロジェクト作成
プロジェクトをご準備下さい。
mkdir webpack-react cd webpack-react
このプロジェクトwebpack-react
フォルダの直下にまた新しくフォルダの作成をします。
フォルダ名は任意でも構いません。
下記フォルダ名とし、この中で管理していきます。
mkdir react_test cd react_test
プロジェクトの初期化をします、プロジェクトフォルダを作成しnpmを使用してプロジェクトを初期化する必要があります。
npm init
ではいくつかの質問をされます、そのままEnterで流すかnpm init -y
で質問をスキップさせます。
npm init -y
これにより、ルートフォルダにpackage.json
が作成されます。
プロジェクトの初期化が完了したので、Reactプロジェクト内でいくつかの必要のあるパッケージをインストールします。
npm i react react-dom --save npm i --save-dev webpack webpack-cli html-webpack-plugin webpack-dev-server babel-loader @babel/core @babel/preset-env
沢山インストールしましたがどれも欠かせないものとなります。
それぞれのパッケージを1つずつ説明致します。
npm i react react-dom --save
Reactで開発の際に欠かせないものです、JSX
コードを使用してReactを記述できます。
webpack webpack-cli
Webpack 4.0以降では、コマンドライン操作用のパッケージはwebpack-cli
という別パッケージで提供されておりますのでこちらをインストールします
WebpackライブラリですべてのJavaScriptコードを単一にバンドルし、アプリケーションを構築するためのものです。
html-webpack-plugin
WebpackでバンドルされたJS、HTML、CSSを表示する為に自動で生成するプラグインとなります。
設定などで独自のHTMLファイルテンプレートを指定も可能となります。
webpack-dev-server
開発目的でのみローカルWebサーバーでアプリケーションを提供するために必要となっており、リロードする機能を備えたクライアント側サーバーです。
babel-loader
WebpackでBabelを使用するのに必要なモジュールをインストールします。
ローダーは、webpack用に構築されたNodeベースのユーティリティであり、ソースコードの変換やモジュール化をするためのツールです。
@babel/core
Babel本体のモジュールとなります。
@babel/preset-env
BabelがES6、ES7、およびES8コードを(ブラウザが理解できるように)ES5にコンパイル(変換)するのに役立つプリセットとなります。
Babelでは複数のモジュールをインストールし組み合わせて扱います。
Webpack用のBabel loader
には@
がありません。
先頭に@
が付いてるのと付いていないのがあるので気をつけて下さい。
package.jsonの設定
まずpackage.jsonの設定を先にする必要があります。
package.jsonでの設定はそこまで難しくはありません
本日は必要最低限の設定でいきます。
下記のようにpackage.jsonファイルのオブジェクト内にあるscripts
にコードを追加します。
"scripts": { "start": "webpack-dev-server --mode development", "build": "webpack --mode production" },
"start": "webpack-dev-server --mode development",
npm start
またはnpm run start
で実行されるスクリプトとなります。
Webpackの開発ローカルサーバーをdevelopment
モードで実行致します。
Webpackを実行する際は必ずモードである(developmentやproduction)の設定はするようにしてください。
"build": "webpack --mode production",
mode
オプションは現在どのモードにあるかをwebpackに通知し、webpackに通知するために渡さなかった場合はデフォルトでproduction
になります。
npm run build
で実行されるスクリプトでproductionモードで実行しバンドリングします。
Webpackの設定
Webpackではwebpack.config.js
という設定ファイルで対象のファイルなどを指定していきます。
この設定ファイルは、拡張子が.js
となっていることからも分かるように、JavaScriptファイルとして処理されます、このファイル内でmodule.exports
オブジェクトにプロパティを定義することで設定を行う仕組みとなっております。
Webpack構成を追加する必要があるため、ルートフォルダにwebpack.config.js
ファイルを追加します。
ファイル名は必ずしもこのwebpack.config.js
ではなくても大丈夫です。
本日ではよくあるこのファイル名でいきます。
下記のように記述下さい。
// webpack.config.js const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: path.resolve(__dirname, './src/index.js'), module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: ['babel-loader'], }, ], }, output: { path: path.resolve(__dirname, 'dist'), publicPath: '/', filename: 'bundle.js', }, resolve: { extensions: ['*', '.js', '.jsx'], }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', }), ], }
こちらも1つずつ解説致します。
const path = require('path');
path
はNode.jsネイティブユーティリティモジュールです。
通常のnpmモジュールとは異なり、すでにNode.js内にあるためインストールする必要はありません。
絶対パスを参照する為にpath
を読み込みます。
require()
はJavaScriptのプログラムをブラウザ上で動作させるには このrequire()
によるモジュールの参照を解決した単一のJavaScriptファイルに変換する必要があるので使用します。
const HtmlWebpackPlugin = require('html-webpack-plugin');
HtmlWebpackPlugin
はWebpackでバンドルされたJSなどを表示させるためにHTMLファイルを自動で生成させるプラグインです。
基本的にはrequire()
を使用しプラグインhtml-webpack-plugin
を読み込んであげます。
entry: path.resolve(__dirname, './src/index.js'),
バンドルファイルを作るためentry
を設定します。
path.resolve
では、ファイルへのパスを表す適切な文字列を作成するメソッドを使用します。
ファイルのパスを指定し基準となるファイルになります。
Reactアプリケーションの最上位ファイルになり、アプリをDOMにレンダリングします。
index.js
が別のJavaScriptファイルをインポートすると、それらもバンドルされます。
ファイルは./src/index.js
を元にしてバンドルを行います。
または任意のファイルを指定可能です。
module: { rules: [ { test: /\.(js|jsx)$/, use: ['babel-loader'], exclude: /node_modules/, }, ], },
ここの設定を詳しく知るには、Loader(ローダー)
を知る必要があります。
Webpackでは、Loader
を使用してファイルを事前に処理します。
デフォルトでは、WebpackはJavaScriptファイルとJSONファイルのみを理解するため、それ以外の他のファイルはバンドルすることはできません、例えばCSSやJSXファイルなどです。
他の型のファイルを処理し有効なモジュールに変換するために、WebpackはこのLoader
を必要とします。
ローダーを使用するにはwebpack.config.js
を編集して設定します、今回の設定はモジュールプロパティであるrules
内のtest
およびuse
プロパティを使用し設定します。
この2つのプロパティ以外にも複数あり設定は複雑となっております。
test
は処理対象であるファイルの指定です、今回でしたら( js | jsx )ファイルです。
use
は変換を行う為にどのLoaderを使用するかを決める場所です。
本日は、'babel-loader'`を使用するのでこちらを指定します。
exclude: /node_modules/
は処理対象のファイルに使用するLoaderやオプションを指定します。
モジュール生成時にマッチしたとき、ルールを適用させるものです。
Reactファイルであるjsx
とjs
はbabelを使ってビルド致します。
output: { path: path.resolve(__dirname, 'dist'), publicPath: '/', filename: 'bundle.js', },
output
は出力先であるビルドディレクトリ(フォルダ)とバンドルされたファイルを設定する場所となります。
基本的によく扱うプロパティはこのpath
でパスを指定します。
本日では、path.resolve
での指定です。
OSごとにパスが異なることを防ぐために設定します。
絶対パスとして変換をしてくれます。
絶対パスでの指定がなく、絶対パスがまだ生成されていない場合は、現在の作業ディレクトリが使用されま ます。
publicPath
はパッケージによって生成されたindex.html
ファイル内の参照されたリソースのプレフィックスを示します。
ビルド時にHTMLファイル内のURLを更新していきます。
filename: 'bundle.js',
はビルド時にバンドルされたファイル名の指定となります。
resolve: { extensions: ['*', '.js', '.jsx'] },
このオプションで指定された拡張子のファイルは import の際に拡張子を省略することが可能となるのでこちらを設定しました。
import test from "test.js" ↓ import test from "test" //省略
HtmlWebpackPlugin
の設定をしなければいけません。
plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', }), ],
先程のは読み込みですが、こちらはnew
演算子で HtmlWebpackPlugin
のインスタンスを生成し必要に応じて引数にオプションを指定していきます。
本日はHTMLのtemplate
を指定します。
src
にあるindex.html
ファイルとなります。
Babelの設定
Babelの設定をしなければいけません。
.babelrc
という名前のBabelファイルを生成し、下記のように記述してください。
{ "presets": [ "@babel/preset-env", "@babel/react" ] }
Webpack用ローダーを追加します。
Webpackには、ファイルを前処理するためにローダーと呼ばれるものが必要となります。
ReactはすべてJavaScriptではないため、.jsx
ファイルであるReact構文をサポートする必要性があります。
したがって、コードをトランスパイルするために、これら依存関係を追加してあげます。
HTMLファイルの生成
下記のように、Reactで使用するHTMLファイルを./src/index.html
として生成して下さい。
// index.html <!DOCTYPE html> <html lang="ja"> <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>Hello</title> </head> <body> <div id="root"></div> </body> </html>
当記事では<div id="root"></div>
内にReactを追加していきます。
それでは、最上位ファイルとなる、エントリポイントのindex.js
ファイルを生成します。
下記ファイルがReactアプリの起点となるルートファイルです。
// React v18のルートファイル // index.js import React from 'react'; import { createRoot } from 'react-dom/client'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.ScriptMode> <App /> </React.ScriptMode> );
HTMLで指定したid のroot
を取得し、React DOMで管理をしレンダリングされます。
つまり、createRoot
はアプリのroot
を作成するために使用され、render
メソッドを呼び出してroot
をレンダリング致します。
Reactのバージョンがv18以前の場合は、ルートファイルは異なりますので気を付けて下さい。
// React v17 // index.js import React from 'react'; import ReactDOM from 'react-dom'; import App from './App' ReactDOM.render(<App />, document.getElementById('root'));
Reactバージョンの確認は、package.jsonで確認ができます。
"react": "^17.0.2", "react-dom": "^17.0.2" // または "react": "^18.2.0", "react-dom": "^18.2.0"
バージョンのダウングレードおよびアップグレードを検討する場合は当記事の下記を参考下さい。
それでは親コンポーネントであるReactの関数コンポーネントファイルApp.jsx
作成しましょう。
// App.jsx const App = () => { return( <div><h1>My new React App</h1></div> ) } export default App;
ここまでのディレクトリ構成は下記の通りです。
/📁webpack-react /📁react_test ├📁node_modules ├依存関係 /📁src ├ App.jsx ├ index.html ├ index.js .babelrc package.look.json package.json webpack.config.js
下記コマンドを使用し、これまで設定してきたのがしっかり動作するか確認致します。
npm start
DEMO
package.josnのscripts
で設定した"start": "webpack-dev-server --mode development",
にオプションとして--open
の設定を追加すればnpm start
実行時に自動でブラウザが起動するようになります。
localhost: 8080
で表示されてるか確認がとれましたらpackage.josnのscriptsで設定した
"build": "webpack --mode production",
このbuildコマンドを使用します。
buildする前に開発サーバーは一度止めておきましょう。
npm run build
ビルドディレクトリの設定はoutput
の設定でdist
として指定したので
buildすると自動でdist
フォルダが生成されます。
このdist
フォルダは公開用となります。
dist
内にはHTMLファイルと1つのJSファイルとしてバンドルされたのを確認できたかと思います。
// dist/index.html <script type="text"src='/react_test/dist/bundle.js'></script>
これらは非常に基本的な設定ですが、ローダーとプラグインを追加して、必要に応じて設定する方法がわかります。
下記でも、基本的な設定をここよりも詳しく解説しておりますので参照下さい。
これらをさらにご自身でカスタマイズしたい場合は、Webpackのドキュメントから詳細を確認して、その方法について得ることができます
本日は以上となります。
最後まで読んで頂きありがとうございました。