文系プログラマによるTIPSブログスマートフォン用の表示で見る文系プログラマによるTIPSブログ文系プログラマ脳の私が開発現場で学んだ事やプログラミングのTIPSをまとめています。私は個人でGoogleAppEngine上でサービスを現状2つ開発していて、そのうちの1つをAngular5で構築しています。www.string-utility.comGAE+Angularで開発するにあたり、ちょっとしんどい事と、どうやってそれを乗り切っているのか(ごまかしているのか)を書いてみます。EnvironmentmにNode.jsがあれば万事解決なのです。Environmentmを使わないと実現できません。これはつまり、サーバサイドがnode.jsではないので、サーバ側がjavaでフロント側がjavascript等と言語が異なってしまうし、何よりビューのテンプレートエンジンの不一致が起きてしまいます。辛いのは、このテンプレートエンジンの不一致です。テンプレートエンジンが不一致になると、SEO(画面表示時のtitleの書き換え等)が非常に厄介になるのです。ビューのテンプレートエンジンの不一致の何が困るのかその前に、サーバサイドとフロントの状況を比較してみます。Angular標準こんな感じです。サーバとフロントでテンプレートエンジンが異なってしまうと、書き方が異なってしまいますよね。なると、同じhtmlをサーバ側とフロント側で共有する事ができなくなってしまいます。共有できないという事は、サーバ用とフロント用のビューを2種類必要になり、しょうもない2重管理になってしまいます。今回選んだThymeleafは優れていて、APサーバを通した場合は変数が展開され、APサーバを通さない場合は変数が展開されない、という事が可能になっています。Thymeleafでは以下のようにtitleタグを書きます。th:text="${seo.title}">StringUtility</title>APサーバ、例えばJettyやTomcatを通してこれを表示すると、seo.titleの値でStringUtilityという文字列を置換される、つまり変数が展開され、ついでにth:text属性は除去され、以下のようにレンダリングされます。<title>ほげほげ</title>APサーバを通さない場合は、このタグがそのまま表示され、titleタグは「StringUtility」となり、「th:title」の部分はhtmlの属性と判断されるので、無害(あっても何も起きない)になり、以下のようにレンダリングされます。th:text="${seo.title}">StringUtility</title>このように、Thymeleafを使う事で、サーバ側とフロント側で同じhtmlを共有する事ができるのでした〜、これにて一件落着!!・・・・とはいきません。これではSEO問題が解決しないのです。画面初期表示時はどっちのhtmlを出力する?一度画面を表示してからは、SPAなので画面遷移が発生しないので、Angular側でtitle・description等を置換します。これは問題ありません。初回の画面表示時は、サーバ側でレンダリングしたビューを表示しますか?それとも静的なhtmlを表示してAngularにSEO情報を書き換えさせますか?SEO的にも安全なのは前者で、極力サーバサイド側で描画済みのものを表示した方が、クローラに認識されやすいです。2017/08時点では、googleのクローラはGoogleChromeのv41相当だそうで、かなりのJavaScriptを解釈できるようです。www.suzukikenichi.comしかしSPAを完全に解釈できるかどうかは、googleのみぞ知る、というのが現状です。いう事で、やはりサーバサイド側で変数を展開済みのビューを初期画面に表示するのが良さそうです。「初期表示時はサーバサイド側のビューを使う」でこの話は終了?いえ、少し厄介な問題が残ります。SPA、しかも今のところAPIもほぼ無いので、ソースコードの割合はサーバサイド1割、フロント9割、という比率のソースコードになっています。いう事はフロントエンド側の方が頑張る量が多いので、フロントエンド側をサクサク開発できる環境が望ましいですね。ここでちょっと問題が起きます。serve」で開発します。これは簡易サーバを起動し、angular側のコードの変更を検知し、差分ビルド+ブラウザの自動リロードが行われ、非常に快適にフロントの開発を行う事が可能になります。serveの挙動にあります。ここまではいいのですが、問題なのはビルドされたファイルは実体としてファイル出力されず、メモリ上で展開される点です。serveした簡易サーバではなく、APサーバ経由でサイトを確認したい場合(GAEにデプロイした状態と同じ)、どうなでしょう。答えは簡単で、angularがビルドしたjsファイルが見つからないという事になります。実体がメモリ上にしかないので当然ですね。この挙動は、以下に影響を与える厄介なものです。本番環境(GAEにデプロイ)した状態での挙動これに対する解決策は2つあります。serve(port=4200)を同時に起動した状態にします。htmlには以下のようにしてjavascriptを読み込むようにします。'main.bundle.js'}"></script>ローカル環境の場合はassetsHost変数に「http://localhost:4200/」をセットし、本番環境の場合は空文字をセットするようにします。ローカル環境の場合は、メモリ上にしかjsが存在しないならば、4200ポートを見てしまえば良い、本番環境の場合jsは標準設定だとdistに配置されるので、「src="inline.bundle.js"」とすれば良いのです。serve中のjsを参照できますが、これは中々な酷いですね。buildした実体のあるファイルを参照できます。serveした場合はどうでしょう。serveによって自動生成されたscriptタグ(下側)があるのです。見ると解りますが、上部のThymeleaf側のscriptにはsrc属性がありません。serveが自動生成するsrcが2重に出力され、2回jsが読み込まれてしまいます。これを回避するため、トリッキーですが、Thymeleaf側には敢えてsrc属性を記述しない状態にしています。serve)したsrcが適用されるのです。一応はこれで何とかなるのですが、以下の問題が残ります。等という不格好な事をしないといけませんでした。簡易サーバの起動をやめつつ、ビルドしたファイルを実体化させてしまえばいいのです。serveと同様リアルタイムに差分ビルドしてくれます。buildもやはりscriptタグを自動出力するので、結局は2重にscriptタグが出力されないよう以下のようにする必要があります。th:src="main.bundle.js"></script>このやり方でも以下の問題は残ります。簡易サーバ無くなったのでAPサーバ経由でサイトの動作確認をする事になり、サクサク開発しにくくなる。angular側のコード変更時にSparkが変更を検知しないので都度Sparkの再起動が必要になる結局どうするのが良さそうかAPサーバ経由でのサイトの動作確認は、どうやっても何かしらの問題がある事が解りました。serveでサイトをライブリロードしながらサクサク開発していく」のがいいのではないかと思いました。サーバサイドはほぼSEO以外の処理は今はやっていないので、この際APサーバ経由での確認は必要な時にしかしなくていいのでは?と思ったわけです。serve経由での確認をバッサリ分けた事で、前述したAPサーバ経由の面倒臭さ(リソース変更時のSpark再起動)は無くせました。これにて一件落着!!・・・・とはいきません(2回目)。これではServiceWorkerのオフライン対応問題が解決しないのです。ServiceWorkerと検索エンジンのクローラここでようやく記事タイトルのServiceWorkerの話です。PWAでネイティブアプリのようにウェイウェイするのが最近の流行りなので(単純に高速化するしオフラインで動くし)、ビッグウェーブに乗ってみました。angularの場合はServiceWorkerの導入は目茶苦茶楽です。--service-worker」だけで初期準備が整います。プロジェクトが存在する場合は、以下のようにします。true」を追加する。root(main.tsがある場所)にngsw-config.jsonを作成する。environment.production})」を追加する。(--output-hashing=noneを付けないとSpark側でjsファイル名を特定できない)こうすると、ビルド時にngsw-config.jsonと同じディレクトリに「ngsw.json」と、それを読み込む「ngsw-worker.js」が生成されます。}}ngsw-config.jsonを元に、ngsw.jsonが生成されます。inline.bundle.js等、ngsw-config.jsonに設定したリソースをハッシュ値を取得し、登録しています。ハッシュ値を登録する理由は、ServiceWorkerのキャッシュ更新のためです。Storageにハッシュ値と共にオフライン利用できるようキャッシュされます。Storage側のハッシュ値と比較され、ハッシュ値が異なっていればFetchする、という挙動のようです。以下のような事をしているようです。Math.random()));ngsw-worker.jsによってServiceWorkerの登録やキャッシュの更新が行われているようです。ngsw-config.jsonにはオフライン時に表示するためのindexページ指定をするのですが、これはどこを指定しましょう。Thymeleaf側のindex.htmlでしょうか?「はい」と言いたいところですが、angular-cliには謎の挙動があります。--prodすると、何故かminifyされてしまうのです。dist側のindex.htmlではなく、src側のindex.htmlが、です。src/main/resources/templates/test.htmlは何故かminifyされます。"../templates/test.html",・・・略・・・この挙動がちょっと意味不明なので、力技で修正してしまいます。rootにコピーしてしまいます。package.jsonで以下のように感じですコピーを挟んでしまいます。./src/main/resources/client/sw-index.html"},index.htmlのままだとトップページ表示時に静的htmlが優先されてしまう等の面倒が起きそうなので、sw-index.htmlと変えてます。これで、ngsw-config.jsonにはsw-index.htmlを指定し、無事Thymeleaf側のindex.htmlに集約できるようになりました。長く、しょうもない試行錯誤でした。ngsw-worker.jsって誰がどこで動いてるの?ネット上でServiceWoekerについて調べると、登録処理でよく以下のようなコードを見かけます。navigator.serviceWorker.register("/sw.js");};これに当たるコードを今回書いてないのですが、一体どこで登録されているのでしょうか。environment.production})これはビルドするとmain.bundle.jsに格納されます。main.bundle.jsがロードされるとngsw-worker.jsが読み込まれ、ServiceWorkerの登録・更新処理等が実行されます。人間がサイトを表示した場合とクローラがサイトを表示した場合の違い人間がServiceWorkerに対応したブラウザ(現在だとChromeとFirefox、IE・Safariはこれから対応される)を使っていると、ServiceWorkerが登録され、リロードすると次回からはServiceWorkerのキャッシュからファイルが読み出されるようになります。動的ではないので、title・description等はサーバサイドでレンダリングされず、angularによって書き換えられます。検索エンジンのクローラですが、まだServiceWorkerに対応していないので、クローラがサイトにアクセスすると、必ず初回画面表示時はAPサーバ経由の動的表示になるので、title・descriptionはサーバサイドレンダリングされるので、SEO的な問題は発生しなくなります。ユーザはServiceWorkerでウェイウェイし、クローラはサーバサイド側でレンダリングされたtitle・descriptionを確実に参照できるわけです。今後クローラ側にServiceWorkerが搭載!なんて言われたらこの手法は使えなくなるわけですが、それは無さそうな予感がします。綺麗には解決していませんね。Spark側のホットデプロイに対応してないし、ビューのテンプレートの話はこれでいいものなのか。node.js以外でSPA+SEO対応する時のベストプラクティスが知りたいです。node.jsが利用可能なら、angular+angular/service-worker+angular/universalで綺麗に統一されたコードが書けただろうなあ・・・と、遠い目になってしまいますね。ReactもVueもですが、やはりフロントはnode.jsとセットで使えると絶対楽で、GAEで無理にSPAでSEOに対応しようとすると、結構しんどい目に合うのでご注意下さい。いうか、クローラがSPAを高い精度で認識できるようになれば、サーバサイドでのtitle・descriptionの書き換えが不要になるのですが、絶対無理でしょうね。こればっかりはずっと付き纏う問題なのかもしれません。週間)昔は業務系SIer、今はベンチャー企業でプログラムを書いています。INFILEを実行できるようにするmacのAutomatorでhomebrewのコマンドをFinderのサービスから実行できるようにするReactオススメ書籍React自体の基礎、AtomicDesignの適用、CSSの運用手法の歴史的な経緯とメリットデメリット、Reduxの基礎、redux-sagaによる非同期処理、サーバサイドレンダリング、テスト、lint、を学ぶ事ができます。単行本(ソフトカバー)この商品を含むブログを見るAngularオススメ書籍Angularを学ぶなら絶対以下がおすすめです!バインディング、ディレクティブ、パイプ、フォーム、コンポーネント、サービス、ルーティング、httpClientによる非同期httpリクエスト、テスト、angular-cli、を非常に丁寧な説明で網羅的に解説しています。大型本この商品を含むブログを見るSEOオススメ書籍SEOを学ぶなら絶対以下がおすすめです!クローラに対して何をどうすればサイトの巡回効率・速度を上げる事ができるのか、どういったマークアップをする事が標準仕様なのか。巷に溢れる業者による経験則に基づくオレオレSEO情報は一切無く、全てGoogle等のオフィシャルな情報に基づいて何をすべきか、どんな手段があるのかを解説されています。プログラマな私が業務で行った施策が多く書かれており、プログラマ寄りで高度な内容となっており、巷のビギナー向けの曖昧な情報集とは一線を画しています。Amazonアソシエイト・プログラムの参加者です。reserved.スターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。