LoginSignup
0
0

More than 3 years have passed since last update.

Angular Universal なアプリケーションで webfontloader を使う

Last updated at Posted at 2020-07-11

linkタグでWEBフォントを読み込むより、webfontloader で非同期に読み込む方が PageSpeed Insights のスコアが良くなります。

なので、Angular で webfontloader を使ってみましょう。

Angular Universal で SSR(サーバーサイドレンダリング) しているような場合は、ひと工夫しないとエラーが出てしまうため、この記事を参考にしてください。

GitHub にサンプルコードを用意しています。実際に動かしてみてください :eyes:

この記事に出てくるコマンドをまとめています。こちらも見てください :star2:

前提

  • 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 を使ってみましょう。

app.component.ts
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 を作成して、以下のように修正します。

app-init.service.ts
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 を修正します。

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 を以下のように修正します。

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'],
        },
      })
    })
  }
}

これですべておしまいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0