カテゴリー
Angular Universalのサーバー(AWS Lambda)側で独自フォント(TTF/WOFF/WOFF2)がデコードできないときの対処法
※ 当ページには【広告/PR】を含む場合があります。
2022/03/07
2024/03/24

弊社ではAngular UniversalでWebサイトの構築をやっている傍ら、最近ふとWebサイトのフォントにassets内に置いたローカルのWOFFフォントを適用しようとしたところ、
460x258

というようなエラーが発生して独自フォントが読み込みに失敗していました。
Firefoxのコンソールで確認すると、なにやら
手元のローカルでの開発中のときにはこのような挙動は見られなかったので、サーバー側の設定のどこかに不具合がある訳だったのですが、原因が非常に分かりにくいため防備録ついでに解決方法を記録しておきます。
Angular UniversalからAWS Lambda経由で独自Fontファイルを読み込みする
この問題はAngular特有のバグというわけではなく、実際にはAWS Lambdaを利用するExpress.jsベースのサーバーレスアプリケーション内部の設定不備で起こるものと考えられます。
Lambda側からのサーバーレスポンスに起因するものですが、表示されるエラーの内容はブラウザごとに異なるため、とりあえず
Firefox
Chrome
Firefoxの場合
例えば当ブログでは、数式をブラウザへ表示するために、「katex」のフォントをインライン化して利用しています。
Lambda側から支給される独自フォントファイルが正しくデコードされていないと、Katexのフォントが正常に適用されない状態で表示されてしまいます。
467x216

ブラウザからのデバッグコンソールからは、例えば以下のようなエラーが記録されています。
#...
downloadable font: rejected by sanitizer (font-family: "KaTeX_Main" style:normal weight:400 stretch:100 src index:0) source: https://deep.tacoskingdom.com/KaTeX_Main-Regular.woff2
downloadable font: incorrect file size in WOFF header (font-family: "KaTeX_Main" style:normal weight:400 stretch:100 src index:1) source: https://deep.tacoskingdom.com/KaTeX_Main-Regular.woff
downloadable font: rejected by sanitizer (font-family: "KaTeX_Main" style:normal weight:400 stretch:100 src index:1) source: https://deep.tacoskingdom.com/KaTeX_Main-Regular.woff
downloadable font: bad table directory searchRange (font-family: "KaTeX_Main" style:normal weight:400 stretch:100 src index:2) source: https://deep.tacoskingdom.com/KaTeX_Main-Regular.ttf
downloadable font: bad table directory entrySelector (font-family: "KaTeX_Main" style:normal weight:400 stretch:100 src index:2) source: https://deep.tacoskingdom.com/KaTeX_Main-Regular.ttf
downloadable font: bad table directory rangeShift (font-family: "KaTeX_Main" style:normal weight:400 stretch:100 src index:2) source: https://deep.tacoskingdom.com/KaTeX_Main-Regular.ttf
downloadable font: Invalid table tag: 0x604F53 (font-family: "KaTeX_Main" style:normal weight:400 stretch:100 src index:2) source: https://deep.tacoskingdom.com/KaTeX_Main-Regular.ttf
downloadable font: (font-family: "KaTeX_Main" style:normal weight:400 stretch:100 src index:2) source: https://deep.tacoskingdom.com/KaTeX_Main-Regular.ttf
downloadable font: rejected by sanitizer (font-family: "KaTeX_Main" style:normal weight:400 stretch:100 src index:2) source: https://deep.tacoskingdom.com/KaTeX_Main-Regular.ttf
#...
エラーの内容がより細かいところまで指摘されていますが、おおよそ「読み込んだフォントファイルの構造がおかしい」という話のようです。
Chromeの場合
もう一つChromeの方でも症状を確認してみます。
こちらも先程のFirefoxとほぼ同じ見た目で数式が表示されています。
472x212

異なるのはエラーの表示で、
Failed to decode downloaded font: <URL>
19:1 Failed to decode downloaded font: https://deep.tacoskingdom.com/KaTeX_Main-Regular.woff2
19:1 Failed to decode downloaded font: https://deep.tacoskingdom.com/KaTeX_Main-Regular.woff
19:1 Failed to decode downloaded font: https://deep.tacoskingdom.com/KaTeX_Main-Regular.ttf
19:1 OTS parsing error: Size of decompressed WOFF 2.0 is less than compressed size
19:1 OTS parsing error: Failed to convert WOFF 2.0 font to SFNT
19:1 OTS parsing error: incorrect file size in WOFF header
となっています。
こちらは、Font構造のどこがどう悪いのか詳細は出てこない代わりに、
【解決策】Angular Universalでバイナリとして扱うMIMEファイルを追加する
ではまず解決策をザックリと話すと、Angular Universalのサーバー処理部分である
lambda.js
//...省略
//👇サーバーから配給するファイルのうちバイナリとして扱いたいMIMEタイプ
const binaryMimeTypes = [
//...中略
//👇古い形式のMIMEタイプは除外
//'application/x-font-ttf',
//👇主要なフォントファイルのMIMEタイプで置き換え
'font/eot',
'font/opentype',
'font/otf',
'font/ttf',
'font/woff',
'font/woff2'
]
//...
とすることで手元の環境でエラーがなくなりました。
デフォルトのままだとLambda側でテキスト形式のファイルとしてサーバー側から送りだしてくれる仕様ですので、
binaryMimeTypes
確かに言われてみるとそうだったけど、地味にExpressアプリ製のサーバー側のMIMEのルール付けは忘れてしまうので、この記事で思いだしていただけたら幸いです。
(折角なのでおさらい)独自フォントをAngularアプリに仕込む
この記事の趣旨としては、AWS Lambdaを使ったサーバレスアプリを使う際には、
lambda.js
Angularでローカルにおいたフォントの独自定義はプロジェクト任意のCSSファイルから呼び出すこともできます。
ここでは、どのコンポーネントからでも呼び出せるように
styles.scss
独自のフォントを使う場合、
ここでは仮想的な
HOGEフォント
PIYOフォント
//👇HOGE-FONTとしてフォントファミリーを注入
@font-face {
font-family: 'HOGE-FONT';
font-style: normal;
font-weight: 500;
src: url('/assets/fonts/hoge.woff') format('woff');
}
//👇Piyo-Gothicとしてフォントファミリーを注入
@font-face {
font-family: 'Piyo-Gothic';
font-style: normal;
font-weight: 500;
//👇形式の異なるフォントファイルを複数指定してファイルの読込み優先度も付けることが可能
src: url('/assets/fonts/piyo_gothic.woff2') format('woff2'),
url('/assets/fonts/piyo_gothic.woff') format('woff'),
url('/assets/fonts/piyo_gothic.ttf') format('truetype');
}
//...以下略
と、
styles.scss
Angularのローカルファイルとして扱うアセットファイルは通例として
src/assets
fonts
先ほどのstyles.scssファイルの例でいうと、
$ tree
.
├── angular.json
├── package.json
#...中略
└── src
├── styles.scss
#...中略
└── assets
#...中略
└ fonts
├── hoge.woff
├── piyo_gothic.ttf
├── piyo_gothic.woff
└── piyo_gothic.woff2
な感じのプロジェクト構造でフォントファイルをおけば良いでしょう。
Angularでの独自フォントを使うのはさほど難しいことではありませんが、@font-faceをローカルから呼び出す際の注意点としては、
url(...)
src: url('./assets/fonts/hoge.woff') format('woff');
src: url('assets/fonts/hoge.woff') format('woff');
src: url('/assets/fonts/hoge.woff') format('woff');
例えばstyles.scssから
hoge.woff
ところが、Angular Universalでサーバー側で動作するアプリにしたい場合、バックエンドで働いているExpressエンジンもリソースファイル解釈できるようにしないといけないので、
src: url('/assets/fonts/hoge.woff') format('woff');
のみがExpressでも正しくルート解決すると思います。 (※ルートのロジックを独自にカスタマイズしたい場合には
server.ts
これでAngularアプリが独自フォントを正しく読み込んだ後は、プロジェクトの任意のcss/scssコードから自由に利用可能です。
//...
h2 {
font-family: "HOGE-FONT";
}
//...
p {
font-family: "Piyo-Gothic";
}
//...
以上、Angularアプリで独自フォントが読み込まない場合に注意したいときの話でした。
参考サイト
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー