二重の意味でAngularにハマってきた今日このごろですが、ようやく年末から年度末にかけての地獄のような日々から開放されました。ずっと頭の中でマクロスFのライオンをリピート再生して「い”ぎたいっ」て思ってました。
そんなこんなで余裕がでて来たものの、「休日の休み方忘れたな〜何しようかな〜」と思っていたらブログの存在を思い出した次第です。
Angular CLIの概要
Angular CLIはコマンドラインからAngularのコンポーネントを作成したりビルドしたりするツールです。いまのところNode.js v6.9.0以上で動きます。
AngularやReactなど最新のJavaScriptのフレームワークやライブラリはビルド環境を構築しないと使えないのですが、この環境構築もNode.jsを使用したGulpやWebpackなどを使用することが多く初めての人はこの段階でヒィヒィ言わされることになります。なりました。
Angular CLIはそういった環境構築の部分をコマンド一発で済ませたり、Angularで使用するコンポーネントやサービスなどを作ることができます。
ローカルでのプレビューやプロダクト環境用のビルドなども出来るのでかなり便利です。
コマンドラインでの操作に慣れていた方がいいですが、慣れていなくてもGithubのREADME.mdの通り使えばサクッとAngularが動いてくれます。
サブディレクトリにビルドしたい
そんなAngular CLIですが、ビルドするとフォルダごと再生成されるためビルド先にAngularとは関係のないファイルあると削除されてしまいます。
想定としてはLaravelなどバックエンドのフレームワークを使用する場合に、Angularはpublicフォルダ(Document Root)に置く必要がありますが、publicフォルダにはフレームワーク用のindex.phpや.htaccessが置いてあったりしますので、これらのファイルがビルドするときに消えることになります。
こういった場合にはビルド先をpublicフォルダのサブディレクトリにしてフォルダを分けて管理した方がいいでしょう。
なお、URLにサブディレクトリを含める場合と含めない場合とで少し方法が変わるようなので、その2パターンを紹介します。
サブディレクトリにビルドしてURLにサブディレクトリ名を含める場合
この場合はng build
のオプションとして--output-path
と--base-href
を指定します。
1 2 |
ng build --output-path=./dist/sub --base-href=/sub/ |
これだけでOKですが、オプションと注意点の説明ちょこっとしておきます。
–output-pathオプションについて
ビルド先のディレクトリを指定します。
ビルド先はデフォルトだと.angular-cli.json
に記載されている"outDir": "dist/"
となりますが、このオプションを付けることで変更できます。
ちなみに.angular-cli.json
の方を書き換えてもいいのですが、今回はオプションの方を採用します。
ビルド先のパスはng build
を実行したフォルダがカレントとなる(プロジェクトフォルダになるはず)ため、プロジェクトフォルダ/dist/sub
を指定したい場合は./
からパスを開始して--output-path=./dist/sub
とします。
–base-hrefオプションについて
これはHTMLタグの<base href="{path}">
のpathを指定します。
Angularの動作にはbaseタグの設定が必須で、Angular CLIを使用してプロジェクトを作成すると<base href="/">
が初期設定としてプロジェクトフォルダのindex.html
に記述されています。
baseタグのhrefが/
のままだと、リソースなどをドキュメントルートからのパスで読み込もうとするため、ファイルが見つからずエラーとなります。
このオプションはドキュメントルートからのサブディレクトリのパスを指定するため--base-href=/sub/
とします。
注意点について
通常、base hrefをサブディレクトリに指定してもCSSのbackground-image
のパスには適用されません。そのため、Angular CLIでは--base-href
の値に合わせてbackground-image
のパスを直接書き換えているようです。
しかし、HTMLのimgタグのsrc属性は書き換わらないため、パスの記述をカレントディレクトリからの開始を示す./
から始める必要があります。
続いてもう1パターンの紹介です。
サブディレクトリにビルドしてURLはドキュメントルートにする場合
この場合は少しややこしいことになりますが、まずはとにかく動かしてみましょう。
Angular CLIではビルドすると依存関係のjsファイルを読み込むscriptタグを自動的にHTMLへ挿入します。
サブディレクトリにビルドしてURLはドキュメントルートという場合、index.htmlはドキュメントルートへ配置することになりますが、scriptタグのsrcはカレントディレクトリから開始となるため、パスが繋がりません。そこで--deploy-url
を使用してパスを変更します。
以上のことを踏まえて、次のコマンドでパスの変更を行ったファイルをサブディレクトリへビルドします。
1 2 |
ng build --deploy-url=/sub/ --output-path=./dist/sub/ |
このままではindex.htmlが/sub/index.html
に存在するため、/index.html
に移動します。
これでドキュメントルートのURLにアクセスするとAngularが実行されます。
が、ng build
ではなくng build --prod
でプロダクト環境用のビルドを行うと依存関係ファイルの名前がハッシュ化されるため、毎回index.html
を移動することになります。
この問題はPHPのget_file_contentsやincludeを使用して解決したり、Gulpを使ってファイル監視して移動させるなどいくつかアプローチがありますので自分の環境に合わせて決めるといいでしょう。
開発サーバと実サーバが両立できない問題
Angular CLIではng serve
というコマンドで開発サーバを立ち上げてそこでプレビューすることが基本的な使い方となっていますが、この場合はビルドされたファイルはディスクではなくメモリー上に存在する状態になります。
このコマンドでは--output-path
オプションを使うことができない(Wikiには載ってますが・・・)ようで、ビルドしたときとディレクトリが変わってしまい、開発サーバと実サーバとで表示が両立できませんでした。
解決策として.angular-cli.json
で画像などのアセットを開発サーバ用と実サーバ用と2重に書き出す方法もありますが、同じファイルが存在してしまうため格好悪く、あまりよろしくありません。
そこでng serve
での開発サーバは使用せずbuildコマンドの--watch
オプションでファイル変更を監視して自動ビルドを行い、サーバの用意やブラウザの自動更新はNode.jsのBrowserSyncで代用します。
–watchオプションの使い方
使い方は簡単でng build
の後ろにくっつけます
1 2 |
ng build --watch |
これでファイルの更新があると自動的にビルドされるようになります。差分ビルドなので初回より短時間で済みます。
Browser Syncの用意
1.インストール
npmやyarnをコマンドでインストールします。
1 2 |
npm install browser-sync --save-dev |
1 2 |
yarn add browser-sync --dev |
2.設定ファイル(bs-config.js)の作成
以下のコマンドで設定ファイル(bs-config.js)を作成します。
1 2 |
browser-sync init |
3.ドキュメントルートと監視ファイルの設定
bs-config.jsを開くといろいろと設定が書いてありますが、files
とserver
のところを変更します。
files
が監視ファイルの設定で、server
がドキュメントルートなどの設定になります。
1 2 3 4 5 |
module.exports = { …省略 "files" : './dist/**/*.*', 省略… } |
1 2 3 4 5 6 7 8 |
module.exports = { …省略 "server" : { "baseDir" : "./dist", "index" : "index.html", }, 省略… } |
4.package.jsonにコマンドを追加する
npm run
で実行できるようにpackage.jsonのscripts
にコマンドを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ …省略 "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build --deploy-url=/sub/ --output-path=./dist/sub/", "build-watch": "ng build --deploy-url=/sub/ --output-path=./dist/sub/ --watch", "browser-sync": "browser-sync start --config bs-config.js" "test": "ng test", "lint": "ng lint", "e2e": "ng e2e", }, 省略… } |
build-watch
とbrowser-sync
が追加したコマンドです。
5.実行する
これで準備ができたので、さきほど追加したコマンドを実行します。
1 2 |
npm run build-watch |
1 2 |
npm run browser-sync |
2つ実行するのが面倒な場合はnpmパッケージのconcurrentlyを使ってもいいと思います。
6.実体ファイルがない場合のフォールバックを設定する
5番まででとりあえず動作はしますが、AngularなどのSPAでは下層ページのURLには実体ファイルが存在しないため、ブラウザを更新するとファイルが見つからずnot foundになります。
そのため、実体ファイルがない場合には/index.htmlにフォールバックするようにします。
フォールバックにはconnect-history-api-fallbackを使用します。これもnpmで配布されているため、Browser Syncと同じようにnpmかyarnででインストールします。
1 2 |
npm install connect-history-api-fallback --save-dev |
1 2 |
yarn add connect-history-api-fallback --dev |
インストール終わったらbs-config.js
でrequireしてserverのmiddlewareとして加えます。
1 2 3 4 5 6 7 8 9 10 11 12 |
var historyApiFallback = require('connect-history-api-fallback'); module.exports = { …省略 "files" : './dist/**/*.*', "watchOptions" : {}, "server" : { "baseDir" : "./dist", "index" : "index.html", "middleware": [historyApiFallback()], }, 省略… } |
これで実体ファイルがないURLにアクセスした場合に/index.htmlへフォールバックするようになります。
おわりに
最後の方で紹介した–watchとBrowser Syncを使った方法を使うとExternal URLが発行されるため、他のパソコンや仮想環境のWindowsでクロスブラウザチェックしやすくなるのでおすすめです。
サブディレクトリにビルドしてURLはドキュメントルートにする場合の方法がややこしいので、本当はもっと簡単な方法があるんじゃないか。と疑ってますが、GithubのWikiを眺めてる感じでは見当たらず、紹介した方法で解決しました。
もっと簡単な方法があれば誰か教えてください。
ではでは ( ͡° ͜ʖ ͡° )ノシ