Angular4 + SSR(サーバーサイドレンダリング)(Universal JavaScript)環境の最小最短 構築方法
2017.10.08
この記事は最終更新日から1年以上が経過しています。
どもです。

今回は、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」をアクセスします。

上記の様に確認できればオッケーです。
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
ではではぁ。



















