- 投稿日:2020-06-28T17:51:43+09:00
日本一わかりやすいReact-Redux入門#1~#3
はじめに
この記事は、Youtubeチャンネル『トラハックのエンジニア学習ゼミ【とらゼミ】』の『日本一わかりやすいReact-Redux入門』の学習備忘録です。
前回講座で学んだ React に続き、大規模アプリ開発の必須のライブラリである Redux についても勉強をしていきます。
前回シリーズ『日本一わかりやすいReact入門【実践編】』の記事はこちらからどうぞ。
#1...講座の概要【ECアプリを作ろう】
講座の目標
- React と Redux で SPA の開発ができるようになる
- ECアプリの開発方法を学ぶことができる
- トランザクション処理を入れた決済機能を実装できるようになる
講座の最終成果物
服飾系を商品として取り扱うECアプリを作っていきます。
- 店舗:ユーザー = 1:n(ユニクロやZOZOのように、商品の「出品者」と「購入者」が明確に分かれている設計)
- 店舗は出品、在庫管理、売上管理ができる
- ユーザーは、商品閲覧、カートへの追加、購入、注文履歴の確認ができる使用技術
- Javascript(JSX)
- React
- react-dom: 画面遷移(ルーティング)を実装
- react-router: 画面遷移(ルーティング)を実装
- Redux
- react-redux: reactとreduxをつなげ、stateを一元管理
- redux-thunk: データベース通信に欠かせない非同期処理を実装
- Material-UI
- Firebase
- Auth: アカウント認証機能
- Firestore: データベース
- Functions: データベースに対する処理(商品の検索機能に使用)
- Storage: 画像のアップロード
- Hosting: アプリの本番環境へのデプロイ
- Stripe(API): アプリへ決済機能を導入するSaaS
講座のAdvanced版
本講座の最後のトピックとなる「決済機能」に関わる部分の講座は、トラハックさんが運営する有料コミュニティ「とらゼミ」から視聴可能です。(そこまではYoutube上で無料公開)
本Qiita記事では無料公開される範囲の講座のみを取り扱います。
Redux に関わる内容については無料範囲で十分に学べると思います。
#2...CRAとFirebaseで環境構築
動画に倣ってreactアプリとFirebaseの設定をすればOKです。
流れは前回講座の「日本一わかりやすいReact入門【実践編】#2...サクッと環境構築しよう」とほぼ同様です。(Redux など、インストールするnpmパッケージには違いがあります)
#3...Fluxフローは絶対に知っておいて
Redux とは?
Reactアプリの state を一元管理するためのライブラリ。
Redux のない純Reactアプリでは、stateはコンポーネント内で定義され、親コンポーネント→子コンポーネントと、バケツリレーの要領で渡されていく。アプリが小さいサイズのときは純Reactでも問題にはならないが、アプリが大きくなってくるについて、バケツリレーがどんどん複雑かつ高階層になる(親→子→孫→ひ孫→...)。
また、特定のコンポーネントで使用しているstateが「そもそもどのコンポーネントで定義されたものか」などの見通しも悪くなり、管理がとても大変になる。
この state 管理問題を解決するために、Reduxが用いられる。Redux を導入することで、アプリ全体の state を保存しておく
Store
という場所が作られる。Reactアプリ側は、この
Store
と通信することで、どのコンポーネントからでも state を扱うことができるようになり、無駄なバケツリレーを防ぐことができる。また、 state自体の定義も全てRedux側で行うことになるので、「このstateどのコンポーネントから来てるんだっけ?」という問題が起こらなくなる。
Fluxフローとは
データフロー設計の1つ。
- 1. データが常に1方向に流れる
- 2. 何らかのイベントをきっかけにデータの状態が変化する(イベント駆動)。Reduxは、「Reactの状態管理をFlux思想で行う」ことを念頭に開発されたライブラリであり、Flux思想で扱われる単語がしばしば用いられる。
Reduxの登場人物
Reduxの中でのデータの受け渡しは、Fluxフローに則り、いくつかの役割に分担されている。
例えば、「現在
1
という値が格納されているcount
という state の値が、画面に描画されているCOUNT_UP
ボタンが押されることで、2
に変更される」というストーリーを通じて、Reduxにおける登場人物を整理する。Components
いわゆる普通の React のコンポーネント。ReduxのFluxフローにおいては、イベントが最初に走る発火点という位置付け。
COUNT_UP
ボタンが定義されており、「count
の値を+1したい」といった趣旨の命令が実行される記述が、ボタンのonClickイベントとして定義されている。Container
Store(=stateが保存されている場所)と接続された、特殊なコンポーネント。個々のComponentsの取りまとめ役。
通常の Components は Redux とは直接接続されていないため、いったんContainerが「
COUNT_UP
ボタンが押された」のようなイベントの情報を受け取る必要がある。Components「
count
を+1したいです」
Container「分かった。Reduxに聞いてみる」Action
Containerからの要求を受け、変更をさらに次へ依頼する。Fluxフローにおいては窓口の役割。
変更を依頼すること自体は、dispatchと言う。
Container「
count
を+1したいらしいです」
Action「分かりました。担当につなぎます(dispatch)」Reducer
変更を管理する役割。現在の state の状態と、Action から受けた依頼の内容から、実行すべき処理を解釈する。
Action「
count
を+1したい、とのことです」
Reducer「分かりました」
↓
Reducer「現在のcount
の値が1、依頼内容は『count
の値を+1したい』だから、count
の値を2にすればいいんだな」Store
状態を保存する倉庫の役割。Reducerの命令により、stateを取り出すor変更する。
Reducer「
count
の値を2に変更した上で、再度アプリ側に出してください」
Store「分かりました(ここでstateの変更が実行される)」mapStateToProps・mapDispatchToProps
変更された state を、再度 Containerに渡す
mapStateToProps・mapDispatchToProps「
count
の値を2に変わったから、Componentsに渡しておいて」
Container「分かりました」この後、ContainerからComponentsに、変更後の
count
が反映される。Container「
count
が+1できたみたいよ」
Components「やったぜ」大切なのは、
- 1. データが常に1方向に流れる
- 2. 何らかのイベントをきっかけにデータの状態が変化する(イベント駆動)。
というFlux思想がしっかりと守られている点。例えば、Reducer→Actionのような方向のデータの受け渡しは絶対に起こらない。おわり
今回はここまで。
次回からは実際にコードを書く内容になっていく予定です。
- 投稿日:2020-06-28T17:31:16+09:00
Rails のデータを React から参照するアプリケーション作成 ( Rails + React + MySQL )
はじめに
他の方の記事を参考に自分なりに Rails + React + MySQL の環境を作ってみたので、その時のやり方をまとめました。
上からコピペするだけで動くようにまとめてみたので、はじめてだけどやってみたいという方がいらっしゃれば、試していただきたいです。コマンド
こちらの項目で実施することは以下となります。
上から順番にターミナルで実行していただければと思います。
- やること
- rails アプリケーションの作成
- webpacker インストール
- react インストール
- MVC作成
- migration
$ rails _5.2.4.2_ new react_sample_app --webpack=react -d mysql $ cd react_sample_app # Webpackを有効にする $ rails webpacker:install # Reactを有効にする $ rails webpacker:install:react # sample モデルを scaffold にて作成 $ rails g scaffold sample title:string body:string # migrate $ rails db:create $ rails db:migrate※routeなどの細かい設定が面倒だと思ってscaffoldを使いましたが、scaffoldが必須というわけではありません。
View
続いては、Viewの設定をしていきます。
application.html.erb
全体へ反映させたいことをこちらに記載していきます。
- やること
javascript_include_tag
→javascript_pack_tag
へ変更する- view のファイル毎に読み込む javascript(React) を指定するために、
<%= yield :javascript %>
を追記app/views/layouts/application.html.erb<!DOCTYPE html> <html> <head> <title>ReactSampleApp</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <!-- javascript_include_tag を下記へ変更する --> <!-- javascript_include_tag 'application', 'data-turbolinks-track': 'reload' --> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <%= yield %> <!-- view のファイル毎に読み込む javascript(React) を指定するために必要 --> <%= yield :javascript %> </body> </html>個別のerbファイル
ここでは例えとして、
app/views/samples/index.html.erb
上に変更を加えますが、他の画面で実装していただいも何も問題ありません。
- やること
- Rails から React へ渡すデータを作成(content_tagにより)
- view のファイル毎に読み込む javascript(React) を指定する
app/views/samples/index.html.erb<!-- 省略 --> <!-- 一番下の行に以下を追記 --> <!-- content_tag の data 属性を React へ渡す --> <%= content_tag :div, id: "resources-container", data: { q: params, resources_path: samples_path, }.to_json do %> <% end %> <!-- view のファイル毎に読み込む javascript(React) を指定することができる --> <% content_for :javascript do %> <%= javascript_pack_tag 'hello_react' %> <% end %>javascript
ここでは、コマンド入力時に作成した
app/javascript/packs/hello_react.jsx
を用いますが、個々にファイルを設定していただいて問題ありません。
- やること
- Hello コンポーネントの作成
- props を state に格納する
- state.name を更新する関数を作成する
- レンダリングする HTML要素を作成する
- Rails から読み込みたい & React からレンダリングしたい要素を指定
- 指定した要素(node)から、data を取得する
- Hello コンポーネントを呼び出し
- data を Hello コンポーネントの props として渡す
- node へ React からレンダリングする
app/javascript/packs/hello_react.jsximport React from 'react' import ReactDOM from 'react-dom' import PropTypes from 'prop-types' // Hello コンポーネントの作成 class Hello extends React.Component { constructor(props) { super(props) // props を state に格納する this.state = { q: this.props.q || '', resources_path: this.props.resources_path || '', name: this.props.name || 'David' } } render() { // state.name を更新する関数を作成する const setName = e => { this.setState({ name: e.target.value }) } // レンダリングする HTML要素を作成する return ( <div> <div>Hello {this.state.name}!</div> <input type="text" defaultValue={this.state.name} onChange={setName}/> </div> ) } } document.addEventListener('DOMContentLoaded', () => { // Rails から読み込みたい & React からレンダリングしたい要素を指定する const node = document.getElementById('resources-container') // 指定した要素(node)から、data を取得する const data = JSON.parse(node.getAttribute('data')) ReactDOM.render( // Hello コンポーネントを呼び出し // Rails から取得した data を Hello コンポーネントの props として渡す <Hello {...data}/>, // node へ React からレンダリングする node ) })rails s と webpacker 起動を一括して実行する方法
以下に、
scripts
の部分を追記します。
すると、yarn start
をターミナル上で実行するたけで、rails s & bin/webpack-dev-server
を実行してくれます。package.json{ "name": "react_sample_app", "private": true, "dependencies": { "@babel/preset-react": "^7.10.1", "@rails/webpacker": "5.1.1", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "prop-types": "^15.7.2", "react": "^16.13.1", "react-dom": "^16.13.1" }, "devDependencies": { "webpack-dev-server": "^3.11.0" }, // 以下を追記する "scripts": { "start": "rails s & bin/webpack-dev-server" } }$ yarn startまとめ
いかがでしたか。
間違いなどがあれば、お手数をおかけしますがご指摘いただけると嬉しいです。React を理解しているとスマホアプリを作れる React Native への導線が引けるかなーと思い勉強中です。
まずは、Rails と連携していけているアプリケーションを作れるようになりたいなーと思っています。
- 投稿日:2020-06-28T15:13:21+09:00
setStateをちょっとだけ工夫した話
最近PRレビューした中でこんな感じのstateがあった。
const start = type === 'start' ? argumentNumber : this.state.start; const end = type === 'end'? argumentNumber : this.state.end; this.setState({ start, end, info: { hoge: 'textChanged' } })infoの中身は必ず変更されるけど、startとendはtypeによって変更有無が変わる。
なんかsetStateに不要な値入るの気持ち悪いと思いました。let newState = { info: { hoge: 'textChanged' } } if (type === 'start') { newState = { ...newState, ...{ start: argumentNumber} } } else { newState = { ...newState, ...{ end: argumentNumber } } } this.setState(newState)こうしたほうが綺麗かも。
ただ変数の中身が動的に変化していくから、多用するとnewStateの中身がカオスになる。
できれば関数に分けたほうがメンテしやすそう。function newPositionState(type) { if (type === 'start') { return { start: argumentNumber} } else { return { end: argumentNumber } } } let newState = { info: { hoge: 'textChanged' } } newState = { ...newState, newPositionState() } this.setState(newState)こうすれば読みやすい。
更新対象のstateが増えたとしても、特に問題なさそう。
もっといい方法があれば教えていただきたい。
- 投稿日:2020-06-28T11:33:58+09:00
Learning React #3 yarn startは何をしている?
一旦は実行できるようになった最初のReactアプリケーション"hello-world"ですが、実行する時には何やらバックエンドでウニュウニュ動いてますね。
これって何を実行しているんでしょうかね。
探ってみたいと思います。yarn startは何をしている?
それでは実行時のコンソール出力を見てみましょう。
前回同様にメッセージに括弧付きの番号"()"を付けてから1つ1つ確認していきます。yarn_startsatom@W1007018N182 MINGW64 ~/src/react-app/hello-world (master) (1) $ yarn start (2) yarn run v1.22.4 (3) $ react-scripts start i 「wds」: Project is running at http://192.168.3.8/ i 「wds」: webpack output is served from i 「wds」: Content not from webpack is served from C:\Users\satom\src\react-app\hello-world\public i 「wds」: 404s will fallback to / (4) Starting the development server... Compiled successfully! (5) You can now view hello-world in the browser. Local: http://localhost:3000 On Your Network: http://192.168.3.8:3000 (6) Note that the development build is not optimized. To create a production build, use yarn build.(1) React開発サーバーの実行
単純に、yarnからReact開発サーバーを実行しています。内部的には(3)で説明している通り
react-script start
が実行されています。
何故yarn start
が`react-script start
になるのかは、別の記事で説明しますね。(2) 実行したyarnコマンドのバージョン
単純なので割愛します。
(3) React開発サーバー(webpack-dev-server)起動時のステータス表示
内部的には"webpack-dev-server"(wds)という、フロントエンド開発時に使用できるWEBサーバーが起動しているようです。
参考までに、公式のwebpack-dev-serverの情報はこちらです。
https://github.com/webpack/docs/wiki/webpack-dev-server複数メッセージが表示されていますが、開発サーバー起動時以下の内容をコンソールに出力しています。
- wds実行時のURLを通知
- webapckにより生成されたコンテンツのURL
- webpackに存在しない静的コンテンツのURL
- 404エラー発生時はエラーとせずに"/"へフォールバックする
このように設定されるのは分かりました。ですが、これってどこで指定されているんでしょうね。これも別の記事で確認結果を書きたいと思います。
今は先に進みましょう。と、その前に、
webpack
というキーワードが気になりますので、少しだけ調べてみました。webpackとは
クライアント側のパッケージツールでした。私たちが作成したJavaScriptファイル(jsファイル)から参照している他のjsファイルやcssファイルやimageファイルをまるっと1つのjsファイルにまとめるためのJavaScriptライブラリです。(イメージファイルはbase64に符号化されて保存されるようです)
これを使うメリットは、
- ネットワークトラフィックの負荷を軽減
- レンダリングが高速化
- モジュール管理が容易
デメリットは、CSSやイメージもパックされるので、デザイナーとの協業で苦労するようです。
とりあえず調べた内容をザックリ紹介しましたが、詳細は別の記事で書きたいと思います。(4) WDSの起動
先ほど説明したwdsがここで起動されています。
(5) ReactアプリケーションへのアクセスURL
起動したReactアプリケーションにアクセスするためのローカルURLとネットワークURLが表示されます。
ただ、便利なことにwdsが実行されると、デフォルトブラウザが自動起動され、ここに表示されたURLにアクセスしてくれます。(6) ビルドオプションの注意書き
最後に、開発用ビルドなので最適化されていないよーって通知してくれてます。
最終的に別環境にデプロイする時はyarn build
を使う事で配布用パッケージという形で生成されるようです。以降の記事では、作成されたReactアプリケーションのプロジェクトファイルを1つ1つ確認していきたいと思います。Reactアプリケーションというのがどのようなファイル構成になっており、どのような原理で動作しているのか、あまり深く入りすぎず、理解できる程度の深度で追ってみたいと思います!
- 投稿日:2020-06-28T08:29:07+09:00
TypeScript の何が役に立つのか?
TypeScript を使ってみて何が役に立つか考えてみたことを初心者向けに解説する。
TypeScript ではプログラマーが型を記述する。JavaScript では必要なかった型を記述することによって手間がかかるが、ビルドやエディターが型情報を使ったらプログラマーにとっていろいろと役に立つ。
型情報を使うと何が役に立つのか?それは TypeScript を使ってみないと想像がつかないものだった。
TypeScriptのインストール方法
Node.jsをインストールするとnodeやnpmが使えるようになる。
グローバルで typescript をインストールし
%APPDATA%\npm
にパスを通す。> npm -g install typescriptまたは
npm init
で package.json を作成してから typescript をその場所にインストールする。.\node_modules\.bin
にパスを通す。> npm init -y > npm install typescripttsc が使えるようになる。
ビルドが型情報を使うと役に立つ
TypeScript のプログラムを JavaScript に翻訳することをビルドと呼ぶ。翻訳と言っても主に付けた型情報を削除するだけだが、TypeScript はビルドするとき型が合わないものをエラーで弾く。
たとえば TypeScript は次のプログラム test.ts をエラーで弾く。
test.tsfunction sum(a: number, b: number): number { return a + b; } sum(1); sum(1, 2, 3);数値を 2 つ受け取って数値を返すという関数の型を記述した。このプログラムは数値を 2 つ渡すべき所に数値を 1 つまたは 3 つ渡しているので、正しく動作しない。関数の型が合わないので型エラーになる。
次のようにしてビルドする。
> tsc --init message TS6071: Successfully created a tsconfig.json file. > tsc test.ts:5:1 - error TS2554: Expected 2 arguments, but got 1. 5 sum(1); test.ts:7:11 - error TS2554: Expected 2 arguments, but got 3. 7 sum(1, 2, 3);TypeScript のビルド方法は特殊だ。tsconfig.json でオプションを設定するが、tsc コマンド上でファイルを指定すると tsconfig.json を読み込まない。そこで tsconfig.json を作って tsc でビルドする。
JavaScript のプログラマーは目で見てわかるから型検査はいらないと思うかもしれない。わざわざ型定義を記述してビルドするのが手間だ。
短いプログラムのときは TypeScript の必要性を感じない。しかし、長いプログラムのとき型検査が役に立つことを感じる。
プログラムの一部を変更したとする。TypeScript がなければ、長いプログラムのどこに影響するかプログラマーが目で見て探さなければならない。
TypeScript は影響する箇所を型エラーとして報告する。プログラマーが探さなくていい。
エディターが型情報を使うと役に立つ
エディターはマイクロソフト製の Visual Studio Code を使う。マイクロソフト製の TypeScript と相性がいい。
この例は文字型の name プロパティと数値型の age プロパティを持つオブジェクトとして Person 型を記述した。
型情報がわかるので、プロパティの補完が正確に効く。
JavaScript のプログラムでもプロパティを補完するが、可能性のある候補を多めに挙げて正確ではない。
npmパッケージを使うときもパッケージの型定義が役に立つ。
パッケージのhttp-link-headerとは別に型定義ファイル
@types/http-link-header
をインストールするとhttp-link-headerをimportできるようになる。header.Link型にget2がないので型エラーが表示される。JavaScriptではエラーが表示されない。
header.Link.Reference型にrelとuriがあるので補完が正確に効く。JavaScriptも補完が効くが正確ではない。
http-link-headerの型定義はF12を押すと型定義ファイルの場所へジャンプして調べられる。
React と相性がいいらしい
次の型エラーのない React のプログラム test.tsx を考える。Visual Studio Code で編集する。
const MyButton の text_bb を書き間違えてみると間違えた所に型エラーが表示された。
ReactDOM.render の text_aa を書き間違えてみると間違えた所に型エラーが表示された。
test.tsx を test.js に変えて型情報を削除して同じ箇所を書き間違えてみたらエラーが表示されなかった。React は TypeScript がないとエラーを発見できない。
React を使うのなら TypeScript を使うべきだ。React の何が役に立つのかという疑問はあるが。
行の関係性に注目してみた
プログラムの不具合は行と行の関係性が原因で発生する。
行と行の関係性は行数の二乗の数だけある。それで長いプログラムほど不具合発生の関係性が増大する。
プログラムが長くなるとすべての関係性を調べる負担をプログラマーが負いきれなくなる。
TypeScript は型を調べることですべての関係性が合っているかを自動的に調べられる。それでプログラマーの負担を軽減できる。
まとめ
型情報があることでプログラミング検査の自動化が進む。
短いプログラムのときは型の記述とビルドに手間がかかるだけだが、型の記述は長いプログラムで真価を発揮する。
TypeScript の型検査はエラーの発生箇所を自動的に調べるので、プログラミングが楽になる。
- 投稿日:2020-06-28T06:25:44+09:00
Remote ContainersでReactのDocker開発環境を構築
概要
更新内容
- ※emvファイルをdocker-compose内に変更しました。
環境
- React
- TypeScript
- storybook
- DockerImage
- node:13.12.0-slim
開発環境は下記のリポジトリにあるのでお好きに使って下さい。
- react-docker-development-environment
- そのままpushをすると、私のリポジトリの内容が変更されてしまうので、pushとかは自分のリポジトリを作成して行って下さい。
- 使用して気に入ったのなら☆を付けてくれると励みになります。
前提
Docker
- いまさらだけどDockerに入門したので分かりやすくまとめてみた
- 自分はWSL2+Docker for windowsで環境構築しました
Remote Containers
- VSCode Remote Containerが良い
- この記事にDockerやRemote Containersで環境構築することの良さが書かれてます
なぜDockerでReactの開発環境を作るのか
- プロジェクトでnodeのバージョンなどを固定できる
- ホストマシンにNodeを入れなくてOK
- プロジェクトメンバーが増えてもコンテナを開くだけで環境構築が完了
なぜRemote ContainersでReactの開発環境を作るのか
- Remote Containersならコンテナを開くときに拡張機能をインストールしてくれるのでプロジェクトで環境を統一可能。
- VSCodeの設定もプロジェクト単位で統一可能。(フォーマッターなど)
- プロジェクトメンバーが増えてもコンテナを開くだけで環境構築が完了(超重要)
使い方
- react-docker-development-environmentを git clone
- VSCodeの拡張機能でRemote Containersを追加する
- VSCodeで「Ctrl + Shift + p 」と入力
- Remote-Containers: Open Folder in Container と入力
- プロジェクト配下のdockerという名前のフォルダを選択する(.devcontainer配下が展開される)
- 実際に開発環境として使用する場合、ssh-agentを有効にしないとPushできません
CreateReactApp
今回の環境はReactでTypeScriptを使用し、storybookの環境構築を済ませた環境になっております。
自分で環境構築を行う場合、以下の手順でできます。
- Nodeを使用可能なコンテナを起動
コンテナ内で以下のコマンドを実行
npm install -g create-react-app ## TypeScriptでReactのApplication構築を行う(テスト環境も配備) create-react-app sample --typescript cd sample # Reactのプロジェクトフォルダ配下で実行することでstorybookの環境構築を行う npx -p @storybook/cli sb init --type react_scripts実装した内容
実際に環境変数で使用している内容の解説をします。
Dockerfile# ベースとするDockerImage FROM node:13.12.0-slim WORKDIR /usr/app # パッケージの依存関係に関するファイルをホストからDocker内にコピー COPY package.json yarn.lock tsconfig.json ./ # yarn install する RUN yarn # yarn install 後、全ファイルをコピーすることで、パッケージ関連がコピーされ、キャッシュが効くようになり高速化 COPY . . CMD [ "yarn", "start" ]docker-compose.yaml# compose fileのフォーマットバージョン(バージョンによって使える記法が違う) version: '3.7' services: node: build: # 使用するDockerFileのDirectoryを指定 context: ../../ # 使用するDockerFileの名前を指定(Dockerfile.Nodeはdocker-compose.yamlと同じディレクトリにあるが、contextで2階層上を使用すると指定している、だからわざわざdocler/.devcontainer/ という風にしてDockerfile.Nodeを指定) dockerfile: docker/.devcontainer/Dockerfile.Node volumes: # ローカルのディレクトリが接続(マウント)する作業ディレクトリを指定(srcフォルダをusr/app/src にマウントしている) - ../../src:/usr/app/src # 外部に対して公開するポート番号 ports: - "3000:3000" # コンテナを起動させ続けるか管理するフラグ tty: true # 環境によってはDockerでHotReloadが効かなくなるので環境変数により有効化する environment: - CHOKIDAR_USEPOLLING=truedevcontainer.json{ "name": "Existing Docker Compose (Extend)", "dockerComposeFile": [ "docker-compose.yml" ], "service": "node", "workspaceFolder": "/usr/app/", // VSCodeのTerminalが開くディレクトリを設定 "settings": { "terminal.integrated.shell.linux": null, "files.trimTrailingWhitespace": true, // ファイル保存時に行末の空白自動削除 "editor.formatOnSave": true // ファイル保存時に自動フォーマットが実行される }, // Remote Containers で起動した際にVSCodeの拡張機能をインストール "extensions": ["eamodio.gitlens","chakrounanas.turbo-console-log","visualstudioexptteam.vscodeintellicode","esbenp.prettier-vscode","dbaeumer.vscode-eslint","shardulm94.trailing-spaces","msjsdiag.debugger-for-chrome","christian-kohler.path-intellisense","usernamehw.errorlens","gizak.shortcuts","coenraads.bracket-pair-colorizer-2"], // Remote Containers で起動した際にgitをインストール "postCreateCommand": "apt-get update && apt-get install -y git", }苦戦した点
コンテナ内でホットリロードが効かない
- docker-compose内でCHOKIDAR_USEPOLLINGを設定することで解決
yarn start が遅い
- 一番苦労した点、コンテナ内だと5分かかることもありました。(ローカルだと10秒で終わる)
- 原因はyarn がキャッシュされておらず一々node_modulesを作成してたから
- 下記の記事の内容で解決しました
- Docker for Macは遅いらしいのでMacの方は注意が必要らしいです。
経緯
- Excelや社内Wikiなどで書かれた環境構築資料の通りにやってもエラーが出て環境構築できない
- 結果、環境構築だけで時間が消える
- プロジェクトメンバーが増える度に同じ時間が無駄になる
- 溜まっていく疲労と虚無感
- Remote Containersなら秒で終わる!
- これからはコンテナが入っていれば環境構築が秒で終わる
- みんな幸せ
参考資料
Docker Composeの仕様について混乱しがちな箇所を整理した
- 投稿日:2020-06-28T06:25:44+09:00
Remote ContainerでReactのDocker開発環境を構築
概要
更新内容
- ※emvファイルをdocker-compose内に変更しました。
環境
- React
- TypeScript
- storybook
- DockerImage
- node:13.12.0-slim
開発環境は下記のリポジトリにあるのでお好きに使って下さい。
- react-docker-development-environment
- そのままpushをすると、私のリポジトリの内容が変更されてしまうので、pushとかは自分のリポジトリを作成して行って下さい。
- 使用して気に入ったのなら☆を付けてくれると励みになります。
前提
Docker
- いまさらだけどDockerに入門したので分かりやすくまとめてみた
- 自分はWSL2+Docker for windowsで環境構築しました
Remote-Container
- VSCode Remote Containerが良い
- この記事にDockerやRemote-Containerで環境構築することの良さが書かれてます
なぜDockerでReactの開発環境を作るのか
- プロジェクトでnodeのバージョンなどを固定できる
- ホストマシンにNodeを入れなくてOK
- プロジェクトメンバーが増えてもコンテナを開くだけで環境構築が完了
なぜRemote-ContainerでReactの開発環境を作るのか
- Remote-Containerならコンテナを開くときに拡張機能をインストールしてくれるのでプロジェクトで環境を統一可能。
- VSCodeの設定もプロジェクト単位で統一可能。(フォーマッターなど)
- プロジェクトメンバーが増えてもコンテナを開くだけで環境構築が完了(超重要)
使い方
- react-docker-development-environmentを git clone
- VSCodeの拡張機能でRemote Containerを追加する
- VSCodeで「Ctrl + Shift + p 」と入力
- Remote-Containers: Open Folder in Container と入力
- プロジェクト配下のdockerという名前のフォルダを選択する(.devcontainer配下が展開される)
- 実際に開発環境として使用する場合、ssh-agentを有効にしないとPushできません
CreateReactApp
今回の環境はReactでTypeScriptを使用し、storybookの環境構築を済ませた環境になっております。
自分で環境構築を行う場合、以下の手順でできます。
- Nodeを使用可能なコンテナを起動
コンテナ内で以下のコマンドを実行
npm install -g create-react-app ## TypeScriptでReactのApplication構築を行う(テスト環境も配備) create-react-app sample --typescript cd sample # Reactのプロジェクトフォルダ配下で実行することでstorybookの環境構築を行う npx -p @storybook/cli sb init --type react_scripts実装した内容
実際に環境変数で使用している内容の解説をします。
Dockerfile# ベースとするDockerImage FROM node:13.12.0-slim WORKDIR /usr/app # パッケージの依存関係に関するファイルをホストからDocker内にコピー COPY package.json yarn.lock tsconfig.json ./ # yarn install する RUN yarn # yarn install 後、全ファイルをコピーすることで、パッケージ関連がコピーされ、キャッシュが効くようになり高速化 COPY . . CMD [ "yarn", "start" ]docker-compose.yaml# compose fileのフォーマットバージョン(バージョンによって使える記法が違う) version: '3.7' services: node: build: # 使用するDockerFileのDirectoryを指定 context: ../../ # 使用するDockerFileの名前を指定(Dockerfile.Nodeはdocker-compose.yamlと同じディレクトリにあるが、contextで2階層上を使用すると指定している、だからわざわざdocler/.devcontainer/ という風にしてDockerfile.Nodeを指定) dockerfile: docker/.devcontainer/Dockerfile.Node volumes: # ローカルのディレクトリが接続(マウント)する作業ディレクトリを指定(srcフォルダをusr/app/src にマウントしている) - ../../src:/usr/app/src # 外部に対して公開するポート番号 ports: - "3000:3000" # コンテナを起動させ続けるか管理するフラグ tty: true # 環境によってはDockerでHotReloadが効かなくなるので環境変数により有効化する environment: - CHOKIDAR_USEPOLLING=truedevcontainer.json{ "name": "Existing Docker Compose (Extend)", "dockerComposeFile": [ "docker-compose.yml" ], "service": "node", "workspaceFolder": "/usr/app/", // VSCodeのTerminalが開くディレクトリを設定 "settings": { "terminal.integrated.shell.linux": null, "files.trimTrailingWhitespace": true, // ファイル保存時に行末の空白自動削除 "editor.formatOnSave": true // ファイル保存時に自動フォーマットが実行される }, // Remote-Container で起動した際にVSCodeの拡張機能をインストール "extensions": ["eamodio.gitlens","chakrounanas.turbo-console-log","visualstudioexptteam.vscodeintellicode","esbenp.prettier-vscode","dbaeumer.vscode-eslint","shardulm94.trailing-spaces","msjsdiag.debugger-for-chrome","christian-kohler.path-intellisense","usernamehw.errorlens","gizak.shortcuts","coenraads.bracket-pair-colorizer-2"], // Remote-Container で起動した際にgitをインストール "postCreateCommand": "apt-get update && apt-get install -y git", }苦戦した点
コンテナ内でホットリロードが効かない
- docker-compose内でCHOKIDAR_USEPOLLINGを設定することで解決
yarn start が遅い
- 一番苦労した点、コンテナ内だと5分かかることもありました。(ローカルだと10秒で終わる)
- 原因はyarn がキャッシュされておらず一々node_modulesを作成してたから
- 下記の記事の内容で解決しました
- Docker for Macは遅いらしいのでMacの方は注意が必要らしいです。
経緯
- Excelや社内Wikiなどで書かれた環境構築資料の通りにやってもエラーが出て環境構築できない
- 結果、環境構築だけで時間が消える
- プロジェクトメンバーが増える度に同じ時間が無駄になる
- 溜まっていく疲労と虚無感
- Remote-Containerなら秒で終わる!
- これからはコンテナが入っていれば環境構築が秒で終わる
- みんな幸せ
参考資料
Docker Composeの仕様について混乱しがちな箇所を整理した