このサイトは、只今WEB業界で活躍中のデザイナー、プログラマーの方々の情報を集めたweb統合情報サイトです。

web帳

記事詳細

2017.10.08

Angular4 + SSR(サーバーサイドレンダリング)(Universal JavaScript)環境の最小最短 構築方法

どもです。

今回は、Angular4で最小のSSR(サーバーサイドレンダリング または、Universal JavaScript, アイソモーフィックJavaScript)環境の構築方法です。

SSR(サーバーサイドレンダリング)とはなんぞや。

SSR(サーバーサイドレンダリング または、Universal JavaScript, アイソモーフィックJavaScript)とは、ざっくり言うと、初期表示をサーバー側(今回はexpressを使用)で表示させ、その後は通常のroutingを用いたSPAの処理を行う手法となります。

何が嬉しいかと言うと、最も得られる効果としては

・初期表示のHTMLはサーバー側で生成するので、高速化を図れる。

・フラグメント識別子の必要性がないので、SEO対策となる。

etc..(他にもありますが)

と、言ったところでしょうか。

当方も以前、angularJSでゲーム作成していた頃(今は、もっぱらVueJS)、こんな感じで初期表示はDOMの方にjsonを出力し、パフォーマンスを稼いでおりました。

var json = JSON.parse(apiPath);
angular.element(document).ready(function () {
  Homepage.app.value('data', json.data);
  angular.bootstrap(document, ['Homepage'])
});

PCサイトだと気にならないかもしれませんが、スマートフォンとなると回線も早くない場合もありますので、初期表示のパフォーマンスやレスポンス量などは重要視されていました。

なので、上記の方法等で回避していたこともありました。

と言った感じに、SSR(サーバーサイドレンダリング または、Universal JavaScript, アイソモーフィックJavaScript)周りの事を書き出すとキリがないかと思いますので、今回は詳細は書かきません。

Googleさんで検索などすると、色々と見つかりますので調べて頂ければと。><

まぁ、図で表すと以下の様に通常のSPAから、最初のレスポンス(1,2の手順)をクライアント側に持ってくる感じとなります。

それでは、早速構築していきましょう。

すぐに試したい方は

すぐに動かして見たい方はgithubの方にupしましたので、こちらを使って頂ければと。

Github

Angular 4 SSR (Universal) Starter

ng CLIを用いたアプリケーション作成

今回は、「ng CLI」を用いて環境構築を行っていきます。

ng CLI」をご存知でない方は、こちらの記事などを参照頂ければと思います。

ang4-ssr」という、アプリケーション名で生成します。

オプションで「routing」を付与します。

ng new ang4-ssr --routing

ディレクトリ移動

cd ang4-ssr

その他、必要なパッケージをnpm でinstallします。

npm install --save @angular/platform-server @angular/animations
npm install --save-dev webpack

「app.module.ts」ファイルの一部を修正します。

src/app/app.module.ts

imports: [
  BrowserModule,
  ...
],

imports: [
  BrowserModule.withServerTransition({appId: 'ang4-ssr'}),
  ...
],

BrowserModuleのwithServerTransitionメンバーを利用します。

server.module作成

新規で「app.server.module.ts」ファイルを作成します。

「@angular/platform-server」パッケージの「ServerModule」を使用します。

これを「NgModule」にimportするようにします。

src/app/app.server.module.ts

import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';

@NgModule({
imports: [
  ServerModule,
  AppModule
],
bootstrap: [AppComponent]
})
export class AppServerModule { }
server.tsファイル作成

新規に「server.ts」ファイルを作成します。

「@angular/platform-server」パッケージから、「platformServer, renderModuleFactory」とそれぞれのモジュールを使用します。

サーバーは「express」を使用します。

src/server.ts

import 'reflect-metadata';
import 'zone.js/dist/zone-node';
import { platformServer, renderModuleFactory } from '@angular/platform-server';
import { enableProdMode } from '@angular/core';
import { AppServerModuleNgFactory } from '../dist/ngfactory/src/app/app.server.module.ngfactory';
import * as express from 'express';
import { readFileSync } from 'fs';
import { join } from 'path';

const PORT = 4000;

enableProdMode();

const app = express();

const template = readFileSync(join(__dirname, '..', 'dist', 'index.html')).toString();

app.engine('html', (_, options, callback) => {
  const opts = { document: template, url: options.req.url };

  renderModuleFactory(AppServerModuleNgFactory, opts)
    .then(html => callback(null, html));
});

app.set('view engine', 'html');
app.set('views', 'src');

app.get('*.*', express.static(join(__dirname, '..', 'dist')));

app.get('*', (req, res) => {
  res.render('index', { req });
});

app.listen(PORT, () => {
  console.log(`listening on http://localhost:${PORT}!`);
});

レンダリングを行うファイルは、distディレクトリを参照するようにします。

また、AppServerModuleNgFactoryモジュールが存在しない状態なので、以下の様にPATHエラーが発生しますので、ビルドを行えるように設定していきます。

tsconfig.app.json追加修正

tsconfig.app.jsonの”exclude”に「”server.ts”」追加修正行います。

src/tsconfig.app.json

"exclude": [
  "test.ts",
  "**/*.spec.ts"
]

"exclude": [
  "server.ts",
  "test.ts",
  "**/*.spec.ts"
]
tsconfig.json項目追加

tsconfig.jsonファイルに「”angularCompilerOptions”」を追加します。

compilerOptionsと同列に追加します。

/tsconfig.json

"angularCompilerOptions": {
  "genDir": "./dist/ngfactory",
  "entryModule": "./src/app/app.module#AppModule"
}
package.json、scripts修正

package.jsonのscriptsにデフォルトのコマンドが記述されていますが、これらを変更します。

/package.json

"scripts": {
  "ng": "ng",
  "start": "ng serve",
  "build": "ng build",
  "test": "ng test",
  "lint": "ng lint",
  "e2e": "ng e2e"
},

"scripts": {
  "prestart": "ng build --prod && ngc",
  "start": "ts-node src/server.ts"
},

と、一旦ここまで修正完了しましたら、起動してみましょう。

npm run start

expressサーバーが起動して、問題がなければ、localhostの4000番ポートで、サーバが立ち上がります。

ブラウザで「http://localhost:4000」をアクセスします。

http://localhost:4000

上記の様に確認できればオッケーです。

ng ジェネレートコマンドで、ページ作成

それでは、ページが変わるとmetaが変更出来るように修正していきましょう。

ctrl + c 等で、一旦サーバーを止めて、「ng generate」コマンドでページ作成の一式を作成します。

ng g c home --module=app.module.ts
ng g c about --module=app.module.ts

ng generate」コマンドで「about」「home」を作成したところ。

app-routing.module.tsファイル追加修正

app-routing.module.tsに追加修正を行っていきます。

先程、「ng generate」コマンドで生成した「about」「home」のcomponentをimportし、ルーティングに追加します。

app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AboutComponent } from './about/about.component';
import { HomeComponent } from './home/home.component';

const routes: Routes = [
  {
    path: '',
    component: HomeComponent
  },
  {
    path: 'about',
    component: AboutComponent
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
app.component.html修正

デフォルトでは、app.component.htmlに色々と記述されていますが、削除してページ遷移出来るように修正します。

app.component.html

<ul>
 	<li><a>Home</a></li>
 	<li><a>About</a></li>
</ul>
home.component.ts修正

home.component.tsを修正していきます。

‘@angular/platform-browser’パッケージの「Meta」と「Title」をimportします。

これらはそれぞれ、Titleやmetaを扱うためのAPIが用意されているので、こちらを用いてTitleやmetaを変更出来る様に設定していきます。

descriptionが増え続けない様に、meta.removeTagで一旦初期化を行い、追加しております。

src/app/home/home.component.ts

import { Component, OnInit } from '@angular/core';
import { Meta, Title } from '@angular/platform-browser';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  constructor(meta: Meta, title: Title) {

    title.setTitle('Angular4 SSR');

    meta.removeTag('name=description');

    meta.addTags([
      {
        name: 'author', content: 'webcyou.com'
      },
      {
        name: 'keywords', content: 'Angular 4 SSR tutorial'
      },
      {
        name: 'description', content: 'Angular4のSSR環境チュートリアルです'
      },
    ]);

  }

  ngOnInit() {
  }

}
about.component.ts修正

同様にabout.component.tsを修正します。

こちらでは、title.setTitle(‘Angular4 SSR – aboutページ’)と、descriptionが変更出来るようにします。

src/app/about/about.component.ts

import { Component, OnInit } from '@angular/core';
import { Meta, Title } from '@angular/platform-browser';

@Component({
  selector: 'app-about',
  templateUrl: './about.component.html',
  styleUrls: ['./about.component.css']
})
export class AboutComponent implements OnInit {

  constructor(meta: Meta, title: Title) {

    title.setTitle('Angular4 SSR - aboutページ');

    meta.removeTag('name=description');

    meta.addTags([
      {
        name: 'description', content: 'aboutページのdescription'
      },
    ]);

  }

  ngOnInit() {
  }

}

と、これで、完了となります。

それでは、確認していきましょう!

npm start

ブラウザで「http://localhost:4000」をアクセスします。

各リンクをクリックすると各ページへと遷移ができ、確認できます。

webインスペクタ等で、metaを確認

Homeページ

Aboutページ

metaタグが変更しているのが確認できました!

最後に

と言った感じで、Angular4で最小のSSR(サーバーサイドレンダリング または、Universal JavaScript, アイソモーフィックJavaScript)環境の構築方法でした。

Angular4はフルスペックなフレームワークな故に容量も大きいところがありますが、パッケージなども公式で揃っている点から「一つ一つパッケージを選択する」と言った手順も減ることから、比較的簡単に環境を構築することができる点が良かったりしますね。

今回のソースはこちらにありますので、宜しければと。

Github

Angular 4 SSR (Universal) Starter

 

ではではぁ。

  • RSSを登録する

  • follow us in feedly

Graphical FrontEnd Engineer
- Daisuke Takayama

MAD CITY 北九州市で生まれ育つ。20代はバンド活動に明け暮れ、ふと「webデザイナーになりたい。」と思い、デジタルハリウッド福岡校入学。卒業後、数々の賞を受賞、web業界をざわつかせる。
現在、港区六本木で活動中。

WEBデザイナーの、WEBデザイナーによる、WEBデザイナーの為のサイト。「みんなで書こう!」と仲間を募ってみたが、結局書くのは自分だけとなってしまいました。日々のメモを綴っていきます。