- JampackはStatic Site Generatorの出力を受け取り、ユーザー体験とCore Web Vitalsスコアを最適化する後処理ツールであり、バンドラーやフレームワークではない
- HTMLの
<img>と<picture>をレスポンシブ画像に変換し、WebP・AVIFなどの形式、srcset、sizes、width、height、loading="lazy"、decoding="async"などを自動で追加する
- CDN画像はURLパラメータベースの
srcsetでレスポンシブ対応でき、外部画像は_jampack配下にダウンロードして最適化済みのローカル画像に置き換えられる
- Above-the-foldのアセットは高い優先度で処理し、小さな画像はHTMLにインライン化し、below-the-foldの画像とiframeは遅延読み込みする
- 静的サイトのビルド結果フォルダに対して
npx @divriots/jampack./distを実行する形で適用し、CSS・JS・HTML・SVG・画像の圧縮まで2回目のパスで実行する
Jampackの役割
- JampackはStatic Site Generator、つまりSSGが生成した出力を入力として受け取り、静的Webサイトを最適化する
- 目的はユーザー体験とCore Web Vitalsスコアを改善すること
- READMEではJampackを「バンドラーでもフレームワークでもない」と区別している
- 紹介記事はRead the introduction blog postで提供されている
画像最適化
- 通常の
<img>はレスポンシブ画像に変換される
- 元の
srcに対してWebPファイルを作成し、srcsetを追加する
sizes="100vw"、loading="lazy"、decoding="async"、width、heightなどの属性が追加される
<picture>要素は複数の画像形式を含むレスポンシブ構造に変わる
- AVIF用の
<source type="image/avif">が追加される
- WebP用の
<source type="image/webp">が追加される
- 元の
<img>にもsrcset、sizes、loading、decoding、width、heightが入る
- 画像最適化機能は
optimize-imagesドキュメントにつながるが、README内の該当リンクは相対パスになっている
CDNおよび外部画像の処理
- CDN画像はリモートURLを維持しながらレスポンシブな
srcsetを追加できる
- 例ではUnsplashの画像URLに
w、fit=min、auto=formatパラメータを付け、複数幅の候補を作成する
- 元の画像にも
loading="lazy"、decoding="async"、sizes="100vw"が追加される
- 外部画像はダウンロード後、最適化済みのローカルファイルに置き換えられる
- 例では外部のUnsplash画像を
_jampack/ab99b9d280ce4cf7cfc810b59f3a7739.jpg.webpのようなパスに変換する
- 変換後の画像には
width、height、srcset、sizes、loading、decodingが含まれる
Above-the-foldとCSS・リンク最適化
- Jampackはabove-the-foldアセットを個別に最適化する
- 画像はより高い優先度で読み込まれる
- 小さな画像はHTMLに埋め込まれる
- below-the-foldアセットは遅延読み込みされる
- 画像とiframeがlazy loadの対象となる
- Critical CSSはHTMLにインライン化される
- 目的はスタイルシートのダウンロードと解析中に発生しうるFOUCを避けること
- 残りのCSSは遅延読み込みされる
- リンクのプリフェッチは、今後のページ遷移を高速化するための機能
アセット圧縮と実行方法
- Jampackは2回目のパスで、手を加えていないすべてのアセットを圧縮し、同じ名前と同じ形式を維持する
- 拡張子別の圧縮ツールは以下のとおり
- 静的Webサイトが
distフォルダにある場合、次のコマンドで実行する
npx @divriots/jampack ./dist
ユースケースと名前の意味
1件のコメント
Hacker Newsのコメント
まさに探していたツール。こういう画像最適化のためにSharpベースのスクリプトを自作して使っていたが、Jampackがそれを完全に置き換えてくれて、しかもずっとよく動く
Quartoの静的サイトをビルドしたあとにJampackを走らせたところ、フォルダサイズが32%減少し、今のところ目立った欠点はない
PageSpeed Insightsでは、Jampack適用前はモバイルがパフォーマンス52、アクセシビリティ73、ベストプラクティス100、SEO 85、デスクトップはパフォーマンス90、アクセシビリティ75、ベストプラクティス100、SEO 82だった
適用後はモバイルがパフォーマンス49、アクセシビリティ80、ベストプラクティス100、SEO 92、デスクトップはパフォーマンス85、アクセシビリティ82、ベストプラクティス100、SEO 91になった
「Lighthouseスコアを5回実行した中央値は、1回実行より2倍安定する」という資料もある: https://developers.google.com/web/tools/lighthouse/variabili...
georges [at] divriots [dot] com
ApacheとNginx向けのPageSpeedモジュールを思い出す: https://developers.google.com/speed/pagespeed/module
GitHubリポジトリもアーカイブされている: https://github.com/apache/incubator-pagespeed-ngx
どこか別の場所へ移ったのだろうか?
これはかなり気に入った。使ってみるつもり
いまいちだと感じた人がいるなら、欠点を指摘してほしい。自分には、Cを超高度に最適化されたアセンブリにコンパイルするのに近く、しかも自分ではやりたくない作業を確実に代わりにやってくれるツールに見える
できるだけ単純で直感的なHTMLとCSSを書けば、あらゆるデバイスのブラウザがそのまま問題なくレンダリングできるべきだと思う
本当にそのレベルの最適化成果物を配布しなければならないなら、HTMLとCSSは完全に飛ばして、高度に最適化されたWebAssemblyを配布し、開発者には好きな言語を使わせたほうがよい
SSG出力のUnicode範囲に基づいてフォントをサブセット化し、CSSで定義されたfont-feature-settingsをもとにOpenType軸を固定する方法があるとよい
それが言っている「font-feature-settingsベースのOpenType軸固定」のことなのか、それとも別の意味なのか気になる
フォントのサブセット最適化もやりたいが、どれほど改善するのかはまだよく分からない。手動で試したことがあるのか気になる
別スタイルシートに置かずインライン化すべき重要CSSを特定するという発想は興味深い
重要CSSと非重要CSSを原理的に区別する方法があるのかと期待した。たとえば
:hoverのようなユーザー操作の効果は常に非重要とみなす、などしかし使っているライブラリは、ページをレンダリングしてどのルールが重要かを最善推定する方式なので、少し残念: https://github.com/GoogleChromeLabs/critters
もちろんフォントまでインライン化するなら話は分かるが、それ以外のスタイルだけで50KBを超えるなら、たいていは方向性を誤っている
真面目な話、インライン化はウォームキャッシュと比べても性能面で非常に有利で、外部スタイルシートやスクリプトのほうが良くなる閾値は思ったより高く、一般的な市場基準では数百KBに達することもある
重要CSSという概念は、根本問題を直すのではなく、無駄にした性能を少し取り戻そうとする敗北主義的アプローチのように感じる
ただし、これは体系的な手法ではなく、軽い経験と観察に基づく判断だ。誰かがこの概念をもっときちんと測定してくれるとよいが、自分がやることはなさそうだ
これは、そもそも人々がSSGとプラグインを選ぶさまざまな用途をカバーしているように見える。特にAstroやEleventyを選ぶ場合はなおさらだ
別個のビルド後ステップにしておくことを好む理由はあるだろうか? 開発中の再ビルドは速くなるが、画像のwidth指定のようなものを追加することで生じる微妙なバグを見逃す可能性とのトレードオフに見える
Webページのレイアウト作業が嫌いで、学ぶ気もないが、ときどきやらなければならない立場としては、このツールはとても良さそう
良さそう。ただ、個人的にはページをファーストビューの下へスクロールしたときに画像を待たされるのが嫌い
デフォルトの動作では、ファーストビューのコンテンツが終わったあと、残りの下側コンテンツをバックグラウンドで読み込むのだろうか?
loading="lazy"属性を「この画像/iframeがほぼ見えるようになるまで読み込まない」という意味として扱う: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/im...ただしアスペクト比はインラインで入れるので、読み込み後にレイアウトが変わることはない。遅延読み込みの最大の罪を避けているわけだ
loading="lazy"を使っている現時点ではこの動作を変える方法はないが、ページ全体の読み込み後にファーストビュー下の画像をバックグラウンドで先読みするオプションを追加することはできる。かなり良いアイデアだ
ただ、ページ下部の不要な画像まで読み込んでしまうのではないかと心配している。オプションなら各自でオン・オフできるので問題なさそうだ
本番環境で使える静的サイトジェネレータにはどんなものがある? このツールで出力結果をさらに最適化できそうだ
たとえば昨日は、DivjoyのReactウェブサイトを単純なHTMLに変換してS3バケットから配信しようと、サンプルに従って丸一日費やした。こんなに難しいとは思わなかったし、まだ苦戦している
理想を言えば、S3バケットに自動デプロイしてドメインまで接続してくれる何かがあるとよい。有料なのに開発者はいなくなり、Discordも放置されているのがつらい。だから自分はいつもFOSSのほうを好む
ある程度はこうした機能の一部を備えている
自分のプロジェクトの一つでは大きな変化はなかった。たとえば全体のバンドルサイズは減ったが、gzipサイズは増えたので、実際には自分にとって純損だった
それでもCSS改善は実際に役立ったように思う
アイデア自体は素晴らしく、プロジェクトに画像があればたぶん役に立っただろう
browserlistを空文字列に設定すればこの機能は無効化できる: https://jampack.divriots.com/features/browser-compatibility/