前提条件
予めnode.jsをインストールしておいてください。
npmの初期化とモジュールのインストール
適当なプロジェクトディレクトリを作ったらnpm init
でpackage.json
を作ります。
$ npm init -y
次にWebpack関係のモジュールからインストール
$ npm i -D webpack webpack-cli typescript ts-loader
React関係をインストール
$ npm i -S react react-dom
TypeScriptを使用するので定義ファイルもインストールします。
$ npm i -D @types/react @types/react-dom
package.jsonの確認と編集
2020年8月現在インストールされるバージョンは次のようになります。
また、scripts部分に追加して、webpackを実行できるようにします。
package.json
{ "scripts": { "build": "webpack --mode=production", "start": "webpack -w --mode=development" }, "devDependencies": { "ts-loader": "^8.0.2", "typescript": "^4.0.2", "webpack": "^4.44.1", "webpack-cli": "^3.3.12" }, "dependencies": { "@types/react": "^16.9.46", "@types/react-dom": "^16.9.8", "react": "^16.13.1", "react-dom": "^16.13.1" }, "private": true }
TypeScriptの設定ファイル
TypeScriptの設定を記述するファイルを作成します。
$ touch tsconfig.json
中は次のようにします。必要に応じて追記してください。
tsconfig.json
{ "compilerOptions": { "sourceMap": true, "target": "es5", "module": "es2015", "strict": true, "strictNullChecks": true, "noUnusedLocals": true, "noUnusedParameters": false, "noImplicitReturns": true, "moduleResolution": "node", "esModuleInterop": true, "allowSyntheticDefaultImports": true, "jsx": "react", "lib": ["es2020", "dom"] } }
Webpackの設定ファイル
次はWebbpackの設定ファイルを作成します。
$ touch webpack.config.js
今回は編集ファイルをpublic_html/assets/src
ディレクトリにいれて、書き出したディレクトリはpublic_html/assets/dist
に設定します。
プロジェクトのディレクトリ構成によって変更してください。
webpack.config.js
const path = require('path') const assetsDir = path.resolve(__dirname, 'public_html/assets'); module.exports = { entry: assetsDir + "/src/app.tsx", output: { path: assetsDir + "/dist", filename: 'app.js' }, module: { rules: [ { test: /\.tsx?$/, use: "ts-loader", }, ], }, resolve: { extensions: [".ts", ".tsx", ".js"] }, };
これでWebpackの準備は完了です。
ビルドしてみる
簡単なファイルを作ってjsにビルドできるか確認してみましょう。
webpack.config.js
で設定したディレクトリを作成しましょう。
$ mkdir -p public_html/assets/src
エントリーポイントで指定したファイルの作成。
$ touch public_html/assets/src/app.tsx
ファイルを次のように編集します。
public_html/assets/src/app.tsx
import React from 'react' import { render } from 'react-dom' const App = () => { return ( <div> <div>Hello React</div> </div> ) } render(<App/>, document.querySelector('#app'))
ビルドを実行します。
$ npm run build
start
を実行することでファイルを監視して、編集するたびに自動的にビルドを実行することもできます。
$ npm run start
ここまで設定できているのであれば、public_html/assets/dist
ディレクトリにapp.js
が生成されているはずです。
次にindex.html
を作成し、ビルドしたapp.js
を実行してみます。
public_html/index.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>部分React</title> </head> <body> <div id="app"></div> <script src="assets/dist/app.js" charset="utf-8"></script> </body> </html>
ブラウザでindex.html
を開いてください。
「Hello React」が表示されていれば成功です。
複数のコンポーネントを扱う
これで好きなディレクトリにソースを配置したり、書き出したりということはできるようになりましたが、ルートのAppコンポーネントを表示しているだけなのでSPAと変わらないですね。
複数のコンポーネントをhtmlで自由に表示したいことがあると思います。
components
ディレクトリを作り表示したいコンポーネントを作成しましょう。
ここではHeader.tsx
とFooter.tsx
を作成します。
public_html/assets/src/components/Header.tsx
import React from 'react' const Header = () => { return ( <header> <h1>Header</h1> </header> ) } export default Header
public_html/assets/src/components/Footer.tsx
import React from 'react' const Footer = () => { return ( <footer> <p>Footer</p> </footer> ) } export default Footer
app.tsx
を次のように編集します。
public_html/assets/src/app.tsx
import React from 'react' import { render } from 'react-dom' import Header from './components/Header' import Footer from './components/Footer' const headerDOM = document.getElementById('header') if (headerDOM !== null) render(<Header />, headerDOM) const footerDOM = document.getElementById('footer') if (footerDOM !== null) render(<Footer />, footerDOM)
これでhtmlファイルでidにheader
やfooter
を指定することでコンポーネントを表示することができるようになります。
public_html/index.html
<body> <div id="header"></div> <div id="footer"></div> <script src="assets/dist/app.js" charset="utf-8"></script> </body>
React本体をWebpackしない
実際のソースコードは10Kでも、ビルドしたファイルはReact本体(大きいのはReactDOM)を含むので100Kくらいになっていると思います。
SPAとしてならすべて一つのファイルにまとめるのが一般的ですが、この記事の用途だと作成したソースだけビルドしたいとうケースもあると思います。
その場合webpack.config.js
のexternals
にReactとReactDOMを指定します。
webpack.config.js
const path = require('path') const assetsDir = path.resolve(__dirname, 'public_html/assets'); module.exports = { entry: assetsDir + "/src/app.tsx", output: { path: assetsDir + "/dist", filename: 'app.js' }, module: { rules: [ { test: /\.tsx?$/, use: "ts-loader", }, ], }, resolve: { extensions: [".ts", ".tsx", ".js"] }, externals: { 'react': 'React', 'react-dom': 'ReactDOM', } };
この場合、app.jsを読み込む前にReactとReactDOMは別途読み込む必要があります。
<script src="https://unpkg.com/react@16/umd/react.production.min.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js" crossorigin></script> <script src="assets/dist/app.js" charset="utf-8"></script>
React外の関数にアクセスする
すでに運用しているサイトの場合はなんらかのJavaScriptの処理だったりjQueryのプラグインが入っていると思います。
Reactから外部のJavaScriptの関数を実行したいケースもあると思います。
既存のJavaScriptの修正
既存のJavaScriptもそのまま使えるわけではなく、修正の必要があります。
JavaScriptにはwindowというグローバルで使用できるオブジェクトがあるので、Reactで使用したい処理をここに登録しておきます。
window.hoge = function() { // ここに処理を書く console.log('外部のJS'); }
Reactの修正
次にReact(TypeScript)で実行できるようにインターフェイスを作成します。
Window.ts
interface IWindow extends Window { hoge: () => void } declare const window: IWindow export default window
あとは使用したいコンポーネントで次のように記述すれば実行できます。
tsx
import window from '../../Window' window.hoge()
windowに登録しておけばどこからでもアクセスできますよという例でした。
参考サイト
最新版TypeScript+webpack 4の環境構築まとめ(React, Vue.js, Three.jsのサンプル付き) – ICS MEDIA
既存のウェブサイトに React を追加する