Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

Angular5のmain.bundle.jsが重いのでSpring BootのGzip圧縮を試してみる

f:id:fa11enprince:20180611025013j:plain Angular6出ましたね!割と前に…
Angularを使っています。Angularは割といろいろ好きなところはあるのですが、
やはり、FullのSPAを作っているならまだしも、そうでないので、
趣味&実験でプロダクトにぶっこんだ側面もあるので、いろいろ困難があります。
まぁ、端的に言うと、作ろうとしているものに対しての選定ミス。
おとなしくVue.jsとかが向いていたと思います。
そこで今回、重大だ、という問題について書きます。

Angularのmain.bundle.のサイズでかい問題

Angularのmain.bundle.jsが重い問題。
貧弱なネットワークの中ではこれがとても問題になる。
1M超えのJSはやっぱりちょっときつい…
何とかしたい。Angular5を使っているのだがどうにもならない…。
なんででかくなるかはわかっている
jQuery, Momentを使っているからだ。
jQueryは対処しようがなく、使用しないしか対処法がない。
Momentはlocaleを絞ればよい。
それでもでかい…1MBを切るのが難しい。
いろいろ調べると--vendor-chunck=trueを付けるといいとかでてくるが、これは意味がない。
main.bundle.jsのかわりにvendor.bundle.jsのサイズがでかくなるからだ。
Angular6に実験で上げてみるも、あんまり効果ない&RxJSの書き換えがだるい…ので諦めました。
時間があったらバージョンアップしたい。

いろいろ調べてみる

やはりjQuery, Lodash, Momentあたりを使ってると部分的な対策はあるものの(特にMomentのlocaleとか)、
根本的な対策はないようだ。
そもそもそれらを使わないというのがベストなのだが、どうしようもない事情があるのも確か…。

https://github.com/angular/angular/issues/16850
によると…

元の文

" it shouldn't be expected to use gzip in order to get a realistic file size." If being lightweight is crucial to your project, you might want to consider trying out a view library like React or VueJs until angular properly supports server-side rendering and platform-server is documented. Unfortunately, since angular is a complete framework, its size is large and getting the porduction files to less than 100kb even with compression is not trivial [I've read some people experimenting with the closure compiler getting builds ~50kb in size]

" As I said, the servers I'm using do not support gzip" . The express compression middle-ware does the compression on the fly as a client requests the resources and does not need the server to support gzip files, meaning that the files you'll be uploading to your server are going to be the original files built using ng build command as-is, without being compressed.

翻訳

「(サーバがgzip圧縮に対応してないので)現実的なファイルサイズを得るためにgzipを使用することは期待できません。」 軽量であることがプロジェクトにとって重要なら、サーバサイドレンダリングやplatform-serverを適切にサポートしていることがドキュメントに書かれるまで、ReactやVueJsなどのViewライブラリを試すことを検討することをお勧めします。 残念ながら、Angularは完全なフレームワークなので、サイズは大きく、圧縮してもporductionファイルを100kb未満にすることは自明ではありません。 [私はclosureコンパイラを使って~50kbのサイズをにしたというのを読んだことがあります]

「私が言ったように、私が使用しているサーバはgzipをサポートしていません」 。 Expressのオンザフライで圧縮を行うミドルウェアがあるので、gzipファイルをサポートする必要がありません。つまり、サーバーにアップロードするファイルは圧縮されずにng buildのそのままということになります。

端的に言うと、それなりのbundleのサイズは覚悟しろってことか。

他にもSSRを使えというのがあるが、そもそもサーバサイドはExpressじゃなく、Javaなので使えない…
部分的に導入ってのもありはありだが、めんどくさい事がかなり増える。
そもそもExpressは好きじゃない(そういう問題ではない)。
JavaでSSRを行うものもGitHubに上がってるが、今後のバージョンアップに追随できるか謎なのでまっとうな方法でいきたい。しかし、このやりっぷりには感動した。
ちなみにJNIでV8をたたいてる……ものだった。
そのほかの方法としてはLazy Loadingか…。

ということで…
結論としてはGzip圧縮を試みようということになった。
幸い、使っているものはSpring Bootなので、Gzip圧縮を気軽に試せる。
もちろん、古き良きApacheにもモジュール追加でその方法は試せるが。

Gzip圧縮を使ってみる

まずはAOTビルド時のサイズ

Time: 119604ms
chunk {scripts} scripts.bundle.js (scripts) 398 kB [initial] [rendered]
chunk {0} main.bundle.js (main) 1.16 MB [initial] [rendered]
chunk {1} polyfills.bundle.js (polyfills) 169 kB [initial] [rendered]
chunk {2} styles.bundle.css (styles) 219 kB [initial] [rendered]
chunk {3} inline.bundle.js (inline) 1.36 kB [entry] [rendered]

SSDのそこそこのスペックのマシンだが11sかかってる…。そして1.16MB…
もちろん、RxJSとかのimportは極小になるように頑張っている

Spring Bootの公式サイトによると

server.compression.enabled=false # If response compression is enabled.

がデフォルトのことなので、

application.yamlを書き換える

server:
  compression:
    enabled: true
    mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css

Chromeの帯域制限で計測

に記載の方法で試してみる。 Fast3Gで計測

圧縮前
f:id:fa11enprince:20180709224402p:plain
圧縮後
f:id:fa11enprince:20180709230852p:plain
帯域を絞ると…だいぶ早くなってますね!

GZIPで返ってこないと少しハマった件

ちなみにですが、あれれ?gzipでレスポンス返ってきてない!!とおもってハマりました。 アンチウィルスのESETのせいでgzipで受け付けなかったようです。
f:id:fa11enprince:20180709230605p:plain
ここの設定をOFFにしないとダメでした(ファイヤーウォール全無効にするだけじゃダメでした)

Thunderbirdのデータがすべて消えたので復旧した

f:id:fa11enprince:20150727234208j:plain

問題発覚

WindwosでThunderbirdを使っています。 再起動とかかけてないのに、Thunderbirdをふと開くと、プロファイルから何から何まで全部消えてる… うーん何かしたか?と思い当たると、 普段使わないCClearを気まぐれで使ったのでこれが怪しい… そういえばマルウェア問題があったから更新しとこうとか思ってついつい使ってしまった。

http://note.lilish.com/digital_life/windows/ccleaner_thunderbird

ここのサイトの情報が全てでこの手順をやればOKです。

復旧手順

かならずしもこの方法で復旧できるとは限りません Explorerで%APPDATA%と打つ そうすると普通の環境であればC:\Users\[ユーザ名]\AppData\Roamingに移動します

とにもかくにも退避

Thunderbirdというフォルダがあると思うのでバックアップします。 デスクトップ等にコピーしましょう

Profileデータがあるか確認します

C:\Users\[ユーザ名]\AppData\Roaming\Thunderbird\Profiles の下にxxxxxxx.defaultのような名前でフォルダがあってその下にデータがあるか確認します

Invalidprefs.jsがあるか確認します

C:\Users\[ユーザ名]\Desktop\Thunderbird\Profiles\xxxxxxx.default Invalidprefs.jsとprefs.jsがあればだいたい復旧できる条件が整ってます。 WinMergeを使って念のため差分を見ます(※この作業は必須ではありません)

f:id:fa11enprince:20180610214813p:plain

そうすると文字化けしていて、かつ文字コードがUTF-8が正しいはずなのに、誤った認識をしていることがわかります。

Invalidprefs.jsをサクラエディタ等で開きます。

サクラエディタ等でUTF-8で開きなおします。 そうすると、日本語で書かれている部分がいくつか文字化けしているところがあるので、あきらめて消すか、 推測で適当な文字列に置換します。 私の場合 ・calendar.categories.namesは消しました ・profileの自分の名前らしきところは名前を正しく打ち直しました。

user_pref("mailnews.tags.$label1.color", "#FF0000");
user_pref("mailnews.tags.$label1.tag", "重要E);
user_pref("mailnews.tags.$label2.color", "#FF9900");
user_pref("mailnews.tags.$label2.tag", "仕亁E);
user_pref("mailnews.tags.$label3.color", "#009900");
user_pref("mailnews.tags.$label3.tag", "プライベ��EチE);

となってたところは、重要・仕事、プライベートだと思われるのでそのように書き換えました。

Invalidprefs.jsをprefs.jsにして上書き

上書きします。 そしてThunderbirdを起動します。

そうすると無事復旧できました。

その他参考にさせていただいたサイト

プロファイル消えた? と思ったら… - とりかごとなり。 CCleanerのアップデートに注意!Thunderbirdのデータが消えた原因とその対処法|くまらぼ Thunderbirdを起動したら初期化されててメールがすべて消えていました - Fioに言わせろ!

なお、本件については質問は受けません。

システム開発で最近やっていることのまとめ&感想

f:id:fa11enprince:20180420015702j:plain ここ3か月程度で取り組んでいることのまとめと感想
ほぼ殴り書きで自分向けに書いている内容となっています。
それぞれ細かく記事は書きたいのだけれど…
備忘録的な位置づけで書いてしまっています。
※Web系の人ではないので悪しからず…。

技術スタック

Java

  • ガリガリ書いてる。なぜこの言語かというと…察してください。
  • Spring Boot
    • 最近初めて触った。
    • JavaにしてはよくできたWebフレームワーク
      • 比較的手軽に何でもできてしまう。めんどくさいの代名詞Springのイメージを覆してる。
    • Hibernate
      • やはりJPAというかHibernateの学習コストが高すぎるOneToMany, ManyToOne, LAZY, EAGAR, FETCH結合が鬼門すぎる。
        • 何も考えずにN+1問題やだーでEAGARにすると死ぬ。
        • もはや1対多、多対1関連なんて使わずにJava側で自前で結合しまったりキーを抜き出してEntityごとにfindしたほうが余計な轍を踏まなくていいんじゃね…状態になりがち
        • Rails(ActiveRecord)のようにシンプルにならんのか
      • とはいえ複合PK(やむを得ず使う場合がある…)を扱えたりと何でもできる。
      • JPQLは便利
    • フロントエンドはAngularなのでThymeleafなにそれ?おいしいの?状態。ただのREST API作成用のアレですよ。
    • Scaffoldくらいさせてくれよ…という不満はある
    • Spring Batchはやりすぎ感がある。高機能だけど。
    • application.yml, application.propertiesはよく考えられてる。
    • Gradle 何それおいしいの?そもそもmavenで困ってない。gulpかwebpackにやらせたいことをやらせればいいんじゃね的な。どーなんだろ。

Angular5

  • 最近初めて触った。Spring Bootと組み合わせてる。
  • VSCodeと組み合わせると最強。Lint系ツールも素敵。
  • そこそこガリガリ書いてる。Vue.jsを選べばよかったかも…。と少し後悔。Reactでもよかったかも。いやでもよいところもありますよ。。。
  • なかなか良い感じ。しかし…、SPAですべて作ることを強要されるような気がする。SPAに浸食される。
    • もっと気軽に使いたいんだ
    • AngularJSのときのようにシンプルなテンプレートエンジンでサーバサイドで生成したページと混ぜることが容易ではない。

      • 混ぜたい場合はどうすればよいかいまいちわからない。Angular単位?でアプリを分けるしかない?
        • 詳しい方教えてください(´;ω;`)ウゥゥ
        • 別窓で開くページとかだと戻る必要がないのでそこは問題ないけどrouterがあるのでThymeleafのページとかと組み合わせずらいっすよね。
    • jQueryとかと組み合わせないと結局込み入ったものが作れない。が、jQueryと組み合わせるとちょっと面倒。

      • いや、まじめにコンポーネント作ればできるっちゃできるんですが、ほら、偉大な過去の資産がね…。
    • 学習コストはAngularJSより下がってる(個人的には)。つまり学習が楽だ(ngコマンドとTypeScriptのおかげ)。あんまりng、んぐ言わない。
  • AOTコンパイル通らない。うえー…が多々。
  • npmで依存モジュールとかでダメになる…おまえはアレか、bundlerと同じつらみ。バージョン合わせに四苦八苦。
  • ngx-bootstrapもうちょっと頑張ってくれ…頼む。
  • bootstrap4はいいけど…それにしてもbootstrap依存すぎる。まぁいいけど。
  • TypeScript
    • ほぼES6 + 型。素敵。初見はSwiftに似てると思った。
  • RxJS
    • 込み入った機能を使わなければ超便利なやつ。いいと思います。

JavaScript

  • 読んでるだけ。TypeScriptかES6じゃないと読むの苦痛…。プロトタイプ、テメーはダメだ。いやES5あたりだと思うんだけど旧来のJSが……。
  • Node.js
    • Express
      • Node.jsのWebフレームワーク
      • 自分は読んでるだけ

Python2

  • 読んでるだけ
  • Python2のサポートがRHELとかから外れるってのも知ってますよ…でもね…
  • 機械学習…逃げたいけどやつは追ってくる。嫌だ。機械学習嫌だ。
  • Jupyter
    • いやだから機械学習系は…くぁwせdrf
    • ジュパイターなのかジュピターなのかよくわからん…とおもったらアメリカではジュピターなのね…。セントオーエスVSセントス的な

Ansible

  • あらためて冪等性ってマジ素敵

docker

  • いや、ポータビリティいいんだけどさ…間に何か挟まった感じでダルい…いやきっとそれはまだ自分のスキルが低いのだ…。
    • ポータビリティはいいけどイメージのサイズが当然デカイので、どうにかならないのか…ならないね。
    • docker越しでコマンドをひたすらビシビシたたく!うん。便利。オーバーヘッドも全然なさそう。
    • ポートの指定をrun時に忘れたときの絶望感…docker rmしないとダメか…あぁ。
  • docker-compose
    • dockerの親分的な。便利。
  • kubernates
    • よくわからんけどdocker-composeの競合的な?

MongoDB

  • スキーマレス。テーブル定義的なのがないよ。
  • JSONぶち込み放題
  • MEANスタックってあるけど確かに相性いいよね。ただ、Expressってちょっと機能少なくないですか?
  • すすんで使いたいと思わない。用途に寄るが

MariaDB

  • MySQLの派生
  • Oracle色がなくて素敵(Oracle嫌い)
  • 無料で高機能を使えて素敵

Ubuntu

  • もうこれからLinuxはこれでいいんじゃね的な感じがとってもある。dockerと相性いいし。
  • Ubuntu Desktopはよく使っていたがUbuntu Server悪くないね。CentOSを窓から投げ捨てたくなった。
    • yumって間違えて打つことがなくなって逆にCentOSでapt-getしそうになる。
  • 海外ではCentOSよりUbuntuが主流
  • Ubuntuに限らずだけどsystemctl ... このコマンドとサービス名が長くなりがちなので打つのダルい。serviceとかinitdのときは楽だった。
  • おい、rootになれないんだけど…えっ?sudoが必要だって?とにかく宇文津さんは須藤さんが大好き。

AWS

  • EC2とRDSとS3とかそのあたりは大体つかってた。
    • lambda
      • 勉強したいがいまいちそそらない。lambdaというよりAWS全般にあまり興味がわかない。課金怖い。
      • RDSと相性悪い。

GitBucket

  • Scala製なんだ。へー。
  • しかしGitHubに比べると物足りない…。でも無料でこれなら素敵。メンションでメール飛ばしたい。

開発用Chatツール

  • SlackかHipChat使いたい…無料で代替のがないのか…。

Proxy

  • 技術スタックというか、こいつが邪魔……。squidとかそういう話ではないです。

Apache

  • ええ、今更語ることはないです。

もっといろいろなんか新たに学んだことややったことがある気がするけどこんなところかも… 管理系ってのもありますね。マネジメント あぁ、でもマネジメントしてるのに一番プログラミングしてるゆがんだ状態になってます。 管理したくない。されたい。ふー。 Djangoを触ってみたいなーと思いながらも、触れない日々を過ごしています。

Angular + TypeScript + Spring Bootをやってみた

f:id:fa11enprince:20180130152024j:plain 2018/08/12更新
最近開発でAngular(2+) + TypeScript + Spring Bootを使っています。
それぞれのバージョンの詳細はこんな感じです。
Angular 6
TypeScript 2.7.2
Spring Boot 1.5
Java 8
Maven 3
Node.js 8.11.3
Angular-CLI 6.0.8

実際の構成例

GitHubに置きました。

AngularのチュートリアルとSpring Bootのチュートリアルを混ぜたものです。
ArpitSuthar (Arpit Suthar) · GitHub のをforkしました。

大まかな構成

TypeScriptをどう、SpringのTomcatと連携させるか考えていました。
あんまり複雑な構成にしたくなく、AngularJS(1系)の時のようにお手軽に使えるようにしたかったのです。
それでいろいろ調べたところ、下記の構成にしました。

src
 └ main
      └ client ... ここにAngularのソースを書く(npmで管理しているのもこの配下)
      └ java
      └ resources
         └ static ... ここにAngularのTypeScriptのビルド結果が入る(Angular専用ディレクトリにする)
         └ public ... Spring bootのstaticのかわりにここを使う。Thymeleaf等で参照したいものがあればここに入れる

ご覧の通りSpring Bootが中心の構成になっています。
Angular2+は基本的にフルでSPAで作るといった感じになります。
AngularJSは何も考えずに一部画面だけにAngularJSを適用するとかができましたが、
Angular2+の場合はちょっと考えないと一部画面だけAngular適用ってのは辛いです。。 フルでSPAにしたくない場合は、特定のパス配下はThymeleafでやるといった運用も可能です。 今回のサンプルは特にパッケージ(名前空間)を特に分けてないので、このままではそれはできませんが、 packageを何らかの名前で切ってangular.jsonBaseHrefで設定すればこの配下だけAngularというのは可能です。

ビルドはmavenにやらせてmaven経由でnpmをたたいてnpmのpackage.jsonからAngular-CLIのngコマンドをたたいて
TypeScript→JavaScript変換をしてビルドする感じです。

Angular2+について

AngularJSをちょっとだけ触ったことがあったのですが、
AngularJSに比べてかなり使いやすいです。学習コストは高いといわれますが、周辺のエコシステムを学ばなくていい分Reactよりだいぶ学びやすいと思いました。
TypeScriptの恩恵もあってか、どう作ればいいかという道しるべを示してくれている分、
あんまり書き方に差異は出ないような気がしました。複雑になってきたらServiceにとりあえず逃がしておけばよいといった感じで。
TypeScript素敵です。ES6よりも当然、良いです。JavaScript全部TypeScriptにならないかな…と思える今日この頃です。

Spring Bootについて

Spring単体だと嫌なイメージしかなかったのですが、なかなか素敵なフレームワークです。
ただ、Ruby On Railsとかに比べるとやや生産性は落ちる気がしますが、それでも素敵なフレームワークだと思います。
規模が大きくなっても全然辛くならないフレームワークですね。 ただ、JPAというかHibernate、テメーはダメだ。
Hibernate、機能多すぎて、ハマりも多すぎて辛い…。RailsのActive Recordくらいシンプルになればいいのに。

ハマったところ

Angularがどう頑張っても更新されない…watchしてんのに…。
Angularのhtmlを更新してもなんで反映されないのよ…Springのdevtoolいれてんのに…と思っていました。

IntelliJだとこのハマりはないっぽいです。

なんで更新されなかったかというと、Eclipseがリフレッシュをうまいこと効かせてくれなくて、 そのためEclipseからのSpring Boot Appから普通は動かすと思うのですが(デバッグ時)
その時は
target/classes/resources/static/
を見に行きます。

一方、デプロイして動かす環境やmvn spring-boot:runで動かしたときは
webapp/src/main/resources/static
を参照しに行き、そちらを見に行きます。

いずれにしてもリフレッシュがうまくいかなくてstaticディレクトリに入ってくれないんです。 ただ、Eclipseをリフレッシュしてしまえば、うまくいくこともママあります。 native pollingをONにしても解決しない…だれかうまい解決方法しらないかな? 仕方ないんで、都度都度Spring Boot Appの再起動をかけるか、リフレッシュしてプラグインで強制同期かけてます。