はじめに
フロントエンドがあるからこそバックエンドがあり、バックエンドがあるからフロントエンドがある。
フロントエンドと言う新しい概念が生まれた時、そこにはバックエンドと言う概念が佇んでいた。それはまるで光と影の写し鏡であるかのように…。ぽえーん🥺
(いきなりポエム)
ブラウザの表現力の発展に伴い、”フロントエンド”と”バックエンド”と言うキーワードで、明確にレイヤーを分けて語られることが多くなっているWebアプリ開発の現場界隈。
そして、概念的な形にとどまらず、物理的な形においても、一つのWebアプリケーションに対して、フロントエンドサーバーとバックエンドサーバーを独立させて、相互連携するような構成を採用するようなケースが多々増えているかと思われます。
類義語として、”クライアントサイド”と”サーバーサイド”と言う用語もありますが、今は昔と言う趣でしょうか。
混乱しないように注意が必要ですね。
本記事は、フロントエンドの知識に明るくないけど、「バックエンドならお任せ!」な人向けの記事です。
フロントエンドを知り尽くしている人には、目新しい事は無いかもしれません。むしろ、何を今さら…、という感想を抱く人も多い事が予想されます。
フロントエンドの世界は、私が見た限りでは、「フロントエンドって言うのはね。バックエンドとこうやって組み合わせて…、こうするのがベターだよ!」と懇切丁寧に解説してくれている記事はほとんど見かけたことがありません。
また、Vue.jsの公式サイトを閲覧しても、公式サイトが語るのはあくまでも自身のライブラリの事だけであって、他の技術とどのように組み合わせて開発するのがベターなのか…、と言った事は語られていません。
フロントエンドとは、かくも険しい道なき道であり、あるいは万人を魅惑してやまない素敵な泉と思いきや底なし沼!であると言っても過言ではないのかもしれません。
そのような、何だかとても難しいようなフロントエンドの世界を知るためのヒントになるように、本記事を書きました。
本記事では、フロントエンドとバックエンドをプロジェクトとしてどのように構成していくかに焦点を当てて解説しています。
フロントエンド、バックエンドのディレクトリ構成の比較
フロントエンドのディレクトリ構成
さて、フロントエンド開発において勢いのあるライブラリには、Vue.js・Reactが挙げられますが、これらを使い、プロジェクトを作成すると、どのようなディレクトリ構成が生成されるのでしょうか。本記事では、Vue.jsをチョイスして話を進めます。
ここでは、『Vue CLI』(誤解を恐れずに言うなら、Vue.jsの全部乗せのような存在である)を使ってプロジェクトを新しく作成してみましょう。
(本題はディレクトリ構成の確認なので、詳細な説明は行いませんのであしからず)
まずは、以下のページを参考に『Vue CLI』のインストールを行います。
次に、vue create
コマンドを使いプロジェクトを作成します。ここでは、VueRouterをプラスした形でプロジェクトを作成しました。
プロジェクトを生成すると以下のようになりました。プロジェクト名は、『hello-frontend』としています。
hello-frontend
│ .gitignore
│ babel.config.js
│ package-lock.json
│ package.json
│ README.md
│
├─dist
│ │ ...省略
│
├─node_modules
│ │ ...省略
│
├─public
│ favicon.ico
│ index.html
│
└─src
│ App.vue
│ main.js
│
├─assets
│ logo.png
│
├─components
│ HelloWorld.vue
│
├─router
│ index.js
│
└─views
About.vue
Home.vue
はてさて、これを見てあなたはどう思いましたか?
私が最初に思った事。それは…。
「んーーー?バックエンドのソースってどこに格納するの?」って事でした。
バックエンドのディレクトリ構成
バックエンドのソースと聞いた時に、皆さんは何を思い浮かべるでしょうか?
MVCをコンセプトとしたフレームワークなら、コントローラー、ビュー、モデルの3種類のソースコードが含まれ、モデルであるDAOやらリポジトリのようなクラスに、DBにアクセスするためのSQLが所狭しと書かれている…、それなりに経験のあるエンジニアの方なら、そんな風景を思い浮かべている事ではないでしょうか?
そして、さらに加えるなら、利用する言語・フレームワーク次第で、推奨されているディレクトリ構成というものが大きく異なってくる事でしょう。
そんな訳で、お次はバックエンドプロジェクトのディレクトリ構成にフォーカスします。言語は正直何でも良いのですが、著者が慣れ親しんでいるものをチョイスします。ここでは、プログラミング言語に『PHP』・フレームワークは『Laravel』と言う構成で進めることにします。
Laravelのインストールは色々なやり方がありますが、ここではComposerを利用する方法を採用します。以下のページに従って新規プロジェクトを作成しましょう。
(本題はディレクトリ構成の確認なので、詳細な説明は行いませんのであしからず)
プロジェクト名は、hello-backendとします。
hello-backend
│ .editorconfig
│ .env
│ .env.example
│ .gitattributes
│ .gitignore
│ .styleci.yml
│ artisan
│ composer.json
│ composer.lock
│ package.json
│ phpunit.xml
│ README.md
│ server.php
│ webpack.mix.js
│
├─app
│ ├─Console
│ │ Kernel.php
│ │
│ ├─Exceptions
│ │ Handler.php
│ │
│ ├─Http
│ │ │ Kernel.php
│ │ │
│ │ ├─Controllers
│ │ │ Controller.php
│ │ │
│ │ └─Middleware
│ │ Authenticate.php
│ │ EncryptCookies.php
│ │ PreventRequestsDuringMaintenance.php
│ │ RedirectIfAuthenticated.php
│ │ TrimStrings.php
│ │ TrustHosts.php
│ │ TrustProxies.php
│ │ VerifyCsrfToken.php
│ │
│ ├─Models
│ │ User.php
│ │
│ └─Providers
│ AppServiceProvider.php
│ AuthServiceProvider.php
│ BroadcastServiceProvider.php
│ EventServiceProvider.php
│ RouteServiceProvider.php
│
├─bootstrap
│ │ app.php
│ │
│ └─cache
│ .gitignore
│ packages.php
│ services.php
│
├─config
│ app.php
│ auth.php
│ broadcasting.php
│ cache.php
│ cors.php
│ database.php
│ filesystems.php
│ hashing.php
│ logging.php
│ mail.php
│ queue.php
│ sanctum.php
│ services.php
│ session.php
│ view.php
│
├─database
│ │ .gitignore
│ │
│ ├─factories
│ │ UserFactory.php
│ │
│ ├─migrations
│ │ 2014_10_12_000000_create_users_table.php
│ │ 2014_10_12_100000_create_password_resets_table.php
│ │ 2019_08_19_000000_create_failed_jobs_table.php
│ │ 2019_12_14_000001_create_personal_access_tokens_table.php
│ │
│ └─seeders
│ DatabaseSeeder.php
│
├─public
│ .htaccess
│ favicon.ico
│ index.php
│ robots.txt
│ web.config
│
├─resources
│ ├─css
│ │ app.css
│ │
│ ├─js
│ │ app.js
│ │ bootstrap.js
│ │
│ ├─lang
│ │ └─en
│ │ auth.php
│ │ pagination.php
│ │ passwords.php
│ │ validation.php
│ │
│ └─views
│ welcome.blade.php
│
├─routes
│ api.php
│ channels.php
│ console.php
│ web.php
│
├─storage
│ ├─app
│ │ │ .gitignore
│ │ │
│ │ └─public
│ │ .gitignore
│ │
│ ├─framework
│ │ │ .gitignore
│ │ │
│ │ ├─cache
│ │ │ │ .gitignore
│ │ │ │
│ │ │ └─data
│ │ │ .gitignore
│ │ │
│ │ ├─sessions
│ │ │ .gitignore
│ │ │
│ │ ├─testing
│ │ │ .gitignore
│ │ │
│ │ └─views
│ │ .gitignore
│ │
│ └─logs
│ .gitignore
│
├─tests
│ │ CreatesApplication.php
│ │ TestCase.php
│ │
│ ├─Feature
│ │ ExampleTest.php
│ │
│ └─Unit
│ ExampleTest.php
│
└─vendor
│ autoload.php
│ …省略
うん。とりあえず長いです。Laravelを動かすには色々必要なんだなー、ぐらいに捉えてください。
フロントエンド・バックエンド、2つのディレクトリ構成を比較して
さて、ここに至るまでに、フロントエンド・バックエンドのプロジェクトを作成して、ディレクトリ構成をそれぞれ確認することが出来ました。
さて、これら2つを統合するとなると、統合の過程で色々と不具合が生じることは想像に難くありません。
「同名のディレクトリ名があったら変えなくちゃいけないの?名前変えたら動き変な風にならない?」
「ディレクトリ名だけでフロントエンド・バックエンドなのかが瞬時に判断できない。どうしよう?」
「SQLはどのディレクトリに格納されているの?」
「A画面のボタンの色を修正したいんだけど、どこ見ればいいの?」
一体、どのように折り合いを付け両者を統合して、ディレクトリ構成を決定するのが正しいのでしょう。
定石と言うものはあるのでしょうか?
「こんな事で悩むぐらいなら、いっそフロントエンド系のライブラリ(Vue.js・React)なんか使わずに、これまでと同じようにサーバーサイドでHTMLをレンダリングして、必要に応じてJavaScript使えばいいじゃないか!」
と、気持ちが傾いてしまう人も多かれ少なかれいたことではないでしょうか?
長々と解説してきましたが、ここまできて、ようやく答えを提示する準備が整いました。
この疑問の答えは…、そうなんです。タイトルでも述べている通りで…、『フロントエンドとバックエンドを個別に構築して相互連携させる』ことにあるのです。
従来のオーソドックスなWebアプリでは、1プロジェクトのソースに、DBにアクセスするプログラムやらHTML・CSS・JavaScriptを書いていましたよね。
そうではなく、フロントエンドとバックエンドという2層のレイヤーを切り口にして、それらを個別に構成(プロジェクトは2つ)して2つを組み合わせ、1つのWebアプリとする。
これが、フロントエンド・バックエンドでシステムを開発する際の、定石と言える手法です。
著者はReactをあまり知らないので、Reactにおいてこれが常に当てはまるかはわかりませんが、Vue CLI(Vue.js)においては、間違いなくプロジェクトを2つに分けるという手法が定石と言えます。
何故かと言うと、上述したように、Vue CLIで新規に作成したプロジェクトのディレクトリ構成は縦に長く、バックエンドのディレクトリ構成と統合するのは困難だから…、そのような理由により、プロジェクトの分割が正しいという結論に帰結するわけなのです。
そもそも『プロジェクト』って何だっけ?
ここでのプロジェクトは案件と言う意味ではなく、プログラムのソースファイルの集合体としての『プロジェクト』を指しています。
プログラミングの世界において、誰が決めたかは分かりませんが、数多のIDEや、Visual Studio Codeのようなエディタにおいて、ソースコードを管理する最小単位は『プロジェクト』と呼称されます。
1プロジェクトは、即ち1ビルド単位です。
静的型付け言語におけるビルドの成果物は、実行ファイルやライブラリとなります。
Javaならjarが作られて、Windowsアプリならexeやdllが作られることでしょう。
PHPなどのインタプリタには、ビルドという概念はありませんが、静的ソース解析ツールを入れているなら対象プロジェクトの範囲でチェックが行われますし、ユニットテストを導入しているなら、同じように対象プロジェクトの範囲でユニットテストが起動されます。
大規模システムであれば、プロジェクトが複数に分けられて管理される事もあります。これは単に、巨大なシステムであるが故に水平にプロジェクトを分割することもあれば、プログラムの種類別にプロジェクトを分割するというケースもあるかもしれません。
このような場合は、1つのWebアプリが、複数のプロジェクトで構成される事でしょう。その際は、クラスライブラリと言う形でプロジェクト同士を参照設定して構成を行ったりします。
フロントエンドとバックエンドに分けてWebアプリを開発する
それって本当においしいの?(メリットの話)🤤
フロントエンドとバックエンドに分けるということは、1つのWebアプリなのに、計2つのプロジェクトを作成することになります。
従来の開発に慣れ親しんだ人間であれば、以下のような疑問がもたげるのでは無いでしょうか?
- フロントエンドとバックエンドの2つに分けると、デプロイが面倒…
- IDE内で2つのプロジェクトを行き来するの面倒…
これらの疑問に答えますと…。
1つ目の答えは、そもそもデプロイは自動化されるべきなので、何かしら自動化できる仕組みを(バッチやらシェルやらを)作ればOK。
2つ目の答えは、実体験としては、IDEを行き来する面倒さは無い。画面のコーディング、ビジネスロジックのコーディングは、そもそも使う知識、思考方法が大きく異なるので、逆にレイヤーごとに独立していることで、自分が今どの領域に対してコーディングしているかが鮮明になり集中してコーディングができる(ような気がする)。
また、フロントエンドもバックエンドも技術領域は深いので、あえて領域を独立させて専門的なキャリアパスを敷いてあげることで、エンジニアの成長速度をより効率化させる…、という、組織的な戦略の採用も可能です。
また、近ごろのエンドユーザーは目が肥えているので、ハイクオリティなページ要件が求められがちですよね。どうせ、JavaScriptを使わなければいけないのだとしたら、フロントエンドのみでページレンダリングを完結できるのは、非常にシンプルな形です。これもメリットの1つ。
さらには、フロントエンドのみでページレンダリングを完結させられるという事は、サーバーサイドのテンプレートエンジンの習得が不要になります。
(サーバーサイドのテンプレートエンジンは、ASP.NET MVCならRazor、JavaのSpringBootならThymeleaf、PHPならsmarty、etc…。沢山あって大変です)
2プロジェクト構成の相互連携イメージ
これまでに、hello-frontendとhello-backendと言う2つのプロジェクトを作成しました。これら2つのプロジェクトは、デフォルトから何も変更していないので、現段階では両者が連携し合う事はありません。
両者がお互いに連携し合うための手順を一から説明すると長大になるので、その話は次回の記事に任せるとして…、かいつまんで説明すると、こんな流れでやり取りができれば良い訳です。
- フロントエンドがバックエンドに対してHTTPリクエストを発行して、何かしらのデータを返却してもらいそのデータを表示。
- 画面で何か操作があった際(保存ボタンが押されたなど)に、フロントエンドからバックエンドにHTTPリクエストを発行して、バックエンドで入力内容をDBに保存する。
言ってみれば別に何のことも無い、従来のWebアプリと考え方は同じです。違いは、プロジェクトが2つに分かれているというだけで。とは言え、従来とは異なる点もあり、レンダリングはVue.jsが担当する訳なので、Ajaxライブラリを用いてJsonデータをバックエンドとやり取りするという実装が主体になると言う点でしょう。
2プロジェクト構成のApacheデプロイイメージ
Vue CLIを使ったフロントエンド開発では、自動ビルドをオンにした状態(Node.jsを起動して)で開発します。これについては、次回の記事で詳しく解説して行きたいと思います。
本節は、開発時の話ではなく、実際に本番環境を想定してデプロイするという視点での話をします。その場合、WebサーバーにApacheを用いた際は、以下のような構成でデプロイすることになるでしょう。
フロントエンドにVue、バックエンドにPHPを使ってApacheにデプロイする
フロントエンドが、ビュー部分のリソースを返却する窓口であり、バックエンドが永続化データ(DB)の送受信を受け付ける窓口になります。
(バックエンドとのデータ送受信は必ずしもJsonである必要はありません)
フロントエンドにVue、バックエンドにJavaを使ってApacheにデプロイする
Javaをバックエンドで使う場合には、リバースプロキシを挟んだ形でデプロイすることになります。
Apacheではなく、NginxにPHPを組み込む場合にも、このリバースプロキシなる仕組みを用います。リバースプロキシの利用は多岐に渡るので要チェックな概念です。
2プロジェクト構成のApacheの設定ファイル
全体の構成図で示した、Vue+PHPの場合の設定例を示します。
設定方法は、色々と考えられます。Aliasモジュールを利用してURLに接頭辞を設けると言うのが、簡単に思いつく方法でしょうか。
<IfModule alias_module>
… 省略
Alias /hello-frontend "[hello-frontendのルートディレクトリ]\dist"
<Directory "[hello-frontendのルートディレクトリ]\dist">
AllowOverride All
Require all granted
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /hello-frontend
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
</Directory>
Alias /hello-backend "[hello-backendのルートディレクトリ]\public"
<Directory "[hello-backendのルートディレクトリ]\public">
AllowOverride All
Require all granted
</Directory>
</IfModule>
上記は、フロントエンドもバックエンドも接頭辞を付ける形にしています。以下のようなイメージです。
フロントエンドはルートURLにして、バックエンドだけエイリアスにする…、と言う設定も可能です。以下のようなイメージです。
ちなみに、フロントエンドにエイリアスを付ける場合には、hello-frontend/vue.config.js
を作成して、publicPathを上書きする必要があるので注意してください。
module.exports = {
publicPath: '/hello-frontend',
}
従来の形態に拘る(フロントエンドもバックエンドも1プロジェクト)
Vue CLIを使わないという選択肢もあります。本記事の別解となりますが、過去にこのような記事を書きましたので、こちらも参考にどうぞ。
おわりに
次回は、今回の続き物を想定しています。
Vue CLIとPHP(Laravel)を、それぞれフロントエンド・バックエンドにして、プロジェクトの作成からデプロイまでをハンズオン形式で解説する予定です。
よろしくお願いいたします。