どうも、ぽっぽです。
今まで調査してきた情報をもとにアプリケーションを開発してみました。
簡素な写真アプリケーションです。たんにTodoアプリに写真を登録できるようにしてみました。1から構築した手順とソースを紹介します。
写真の扱いはWEBアプリケーションでは要件になることが多いです。シンプルな方法としては画像ファイルをWEBサーバーで配信します。今回はデータベースから取り出してbase64でエンコードした文字列に変換し、フロントエンドでその文字列を画像として表示させる方法をとりました。HTML5の機能にあるので分かってさえいれば簡単です。
WEBサーバに画像として配信する方法だと、データベースから取り出したファイルを使わなくなったら消したり、使わないという要件をどのように定義するか考えたりやることが増えるので避けました。
ReactでTypeScriptが使えるように環境を構築
npx create-react-app photo-apli --template typescript
npm i redux react-redux @types/react-redux @reduxjs/toolkit redux-thunk
npm i --save-dev redux-devtools
npm i office-ui-fabric-react
ReactでTypeScriptが使えるように環境を構築し、ReduxとUI Fabricをインストールします。
コンポーネントの設計
コンポーネントはTodoアプリと同じ構成にします。あまり複雑なことを一度に取り入れると問題が起こったときに切り分けるのが一苦労だと思いました。
- PhotoHeader
- PhotoList
- PhotoListItem
- PhotoFooter
今回は写真を登録・表示するため、PhotoHeader
とPhotoListItem
に手を加えています。
Todoアプリではidはuuidを使ってフロントエンドで採番していました。今回はデータベースで採番して取得し、Stateを更新することにしました。採番はデータベースにまかせます。
UI Fabricにはファイルアップロードのためのコンポーネントは見つかりませんでした。そこで通常の<input type=file>
を用意して別のコンポーネントから操作するようにしています。
Expressのインストールとその他のライブラリ
npx express-generator --view=pug server
npm i
npm i multer
npm i --save-dev cors nodemon npm-run-all
expressをインストールするときにview
を指定しないとテンプレートエンジンがjadeになります。jadeは非推奨のテンプレートエンジンで現在はpugとなっています。そこで明示的にpugを指定します。詳細は公式ドキュメントを参照してください。
フロントエンドはReactを使うのでview
は必要ないのですが、開発時にエラーが起こるとエラーページを表示するようにexpress-generatorが段取りしてくれているのでview
をそのまま利用しています。
multer
はファイルアップロードのためのミドルウエアです。
セキュリティ上の理由で、ブラウザはスクリプトによって開始されるオリジン間のHTTPリクエストを制限しています。(参照)
cors
によってその制限を許容するようにしています。
フロントエンドはlocalhost:3000
、バックエンドはlocalhost:4000
でローカルの開発環境で動作させています。このようにドメインが異なっても、cors
があるとフロントエンドとバックエンドでajaxによる通信が出来るようになります。
nodemon
は指定したディレクトリ配下のファイルの更新状態を監視して変更があるとデプロイしてくれます。Express側のソースの更新があると自動でデプロイされるので、いちいちnpm start
をせずに済みます。
npm-run-all
はフロントエンド側とバックエンド側で別々で同時に起動させるためインストールしています。package.json
のscriptsでrun-p
というコマンドで同時起動しています。
"scripts": {
"start:client": "react-scripts start",
"start:express": "nodemon -w server bin/www",
"start": "run-p start:express start:client",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Sequelizeのインストール
npm install --save sequelize
npm install --save pg pg-hstore
npx sequelize-cli init
npx sequelize-cli model:generate --name Photos --attributes title:string,photo:blob,kind:string,complete:boolean
npx sequelize-cli db:migrate
Sequelizeのインストールとモデルを定義します。
pgとpg-hstoreはデータベースにPostgresを使う場合です。他のデータベースを使う場合は公式ドキュメントを参考に必要なアプリケーションを指定してください。
Photos
テーブルにphoto
というカラムを定義したのは作っていて後から後悔してしまいました。フロントエンドとバックエンドでオブジェクト定義を揃えたのですが、たまに混乱してしまいます。名前はちゃんとつけないとだめですね。
photo
はバイナリデータを格納するカラムなのでblob型にしています。
サンプルアプリケーションのソース
サンプルアプリケーションをこちらからダウンロード出来ます。
npm install
npm start
Todoアプリを動作させる場合、NodeJSのコマンドプロンプトを開いて、ソースをダウンロードして展開した場所(package.json
ファイルがある)に移動します。1行目のコマンドを実行します。package.json
のパッケージをインストールして、インストールが終わるまで数十秒ほど待ちます。
2行目のコマンドを実行するとブラウザにTodoアプリが表示されます。
終わるときは、コマンドプロンプト上でCtrl + C
をタイプします。
npx sequelize-cli init
で生成される「config/config.json」ファイルは含まれていません。各自の環境に合わせて編集する必要があります。
所感
他の方のソースを読んで動かして理解した気になっていました。実際1から作ってみると手が動かないものですね。また最初から作るとなっても何も見ずに書くのは難しいかもしれません。
フレームワークはホントは実装しないとならない機能を事前に実装してくれているので使わない手はないと思います。でもフレームワークのルールを覚える必要があり新規プロジェクトでいきなり使うと思った以上に調査時間を必要とします。
TypeScriptを使ってReactを使ってみようと思ったことから始まったのですが、Ajaxを使ってRest通信しようとするとRedux、Thunkなどのフレームワークも必要だったことが分かりました。使わなくてもよいのですが自ら実装するより使ったほうが安全・安心だと思いました。
フロントエンドとバックエンドはたいてい異なる言語となります。一人ですべて開発する場合シンタックスの違いで混乱することもあります。納期が近く急ぐとなおさらです。
そこでバックエンドはNodeJs環境で利用出来るExpress、Sequelizeを使いました。JavaScriptで記述できるからです。フロントエンドで調べたやり方がそのままバックエンドでも使えることは体験してみるとありがたいなと思えました。
フレームワークは使い方が分かってしまえばプログラミングのコード量が減ります。フレームワークを利用する初期段階は、その方法を調べるところに時間を使います。
エンジニアとしてはこの調査作業でまず答えにたどり着くかが最も大事だと思います。