linkタグでWEBフォントを読み込むより、webfontloader で非同期に読み込む方が PageSpeed Insights のスコアが良くなります。
なので、Angular で webfontloader を使ってみましょう。
Angular Universal で SSR(サーバーサイドレンダリング) しているような場合は、ひと工夫しないとエラーが出てしまうため、この記事を参考にしてください。
GitHub にサンプルコードを用意しています。実際に動かしてみてください
この記事に出てくるコマンドをまとめています。こちらも見てください
前提
- Angular 9.1.12
- Angular Universal 9.1.11
なアプリケーションで webfontloader を使ってWebフォントを利用します。
準備
npm i webfontloader --save
でインストールします。
npm i @types/webfontloader --save-dev
で型定義もインストールすると良いです。
まずは普通に使ってみる
Angular Universal で SSR していないようなアプリケーションで webfontloader を使ってみましょう。
import { Component, OnInit } from '@angular/core'
import * as WebFont from 'webfontloader'
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
ngOnInit() {
WebFont.load({
google: {
families: ['Modak', 'M+PLUS+1p:400,900'],
},
})
}
}
AppComponent の ngOnInit でこんな風に呼び出してみましょう。
CSS に font-family: Modak;
とすればフォントが適用されます。
APP_INITIALIZER を使う
アプリケーション全体で読み込む必要があるのであれば、APP_INITIALIZER でアプリケーションの初期化時に webfontloader の設定をするようにしましょう。
ng g service app-init
で AppInitService を作成して、以下のように修正します。
import { Injectable } from '@angular/core'
import * as WebFont from 'webfontloader'
export function AppInitFactory(appInit: AppInitService) {
return () => appInit.init()
}
@Injectable({
providedIn: 'root',
})
export class AppInitService {
constructor() {}
init() {
this.initWebFont()
}
private initWebFont() {
WebFont.load({
google: {
families: ['Modak', 'M+PLUS+1p:400,900'],
},
})
}
}
次に、app.module.ts を修正します。
import { BrowserModule } from '@angular/platform-browser'
import { NgModule, APP_INITIALIZER } from '@angular/core'
import { AppComponent } from './app.component'
import { AppInitService, AppInitFactory } from './app-init.service'
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [
// 以下を追加
{
provide: APP_INITIALIZER,
useFactory: AppInitFactory,
multi: true,
deps: [AppInitService],
},
],
bootstrap: [AppComponent],
})
export class AppModule {}
これでアプリケーションの初期化時にlinkタグが追加されます。
Angular Universal で SSR
ng add @nguniversal/express-engine
のあと npm run dev:ssr
でアプリケーションを動かしてみましょう。
しかし、このままでは ReferenceError: window is not defined というエラーが出てサーバーが起動できませんので、今までのコードを修正していきましょう。
Angular Universal のための修正
ここまでで作成した app-init.service.ts を以下のように修正します。
import { Injectable, Inject, PLATFORM_ID } from '@angular/core'
import { isPlatformServer } from '@angular/common'
export function AppInitFactory(appInit: AppInitService) {
return () => appInit.init()
}
@Injectable({
providedIn: 'root',
})
export class AppInitService {
constructor(@Inject(PLATFORM_ID) private platformId: Object) {}
init() {
this.initWebFont()
}
private initWebFont() {
// SSRの場合は実行しないように
if (isPlatformServer(this.platformId)) {
return
}
// ここでimportしないとReferenceError: window is not definedになる
import('webfontloader').then((WebFont) => {
WebFont.load({
google: {
families: ['Modak', 'M+PLUS+1p:400,900'],
},
})
})
}
}
これですべておしまいです。