Help us understand the problem. What is going on with this article?

Angular Universal の Web サーバを Express でサクッと作る方法

More than 1 year has passed since last update.

概要

Angular Universal の Web サーバ部分を、簡単な疎通など確認するためにとりあえずサクッとコピペするための備忘録

前提

以下の必要なモジュールは、型定義ファイル(@types/* でインストール)含めインストールされていること

  • express
  • express-engine
  • @nguniversal/express-engine
  • @nguniversal/module-map-ngfactory-loader

Express で Web サーバを作成

以下の通り、Express を使って Web サーバを作成する

server/web-server.ts
// 以下の2インポートは最初に呼ばれる必要がある
import 'zone.js/dist/zone-node';
import 'reflect-metadata';

import * as express from 'express';
import { join } from 'path';
import { ngExpressEngine } from '@nguniversal/express-engine';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';

const webServer = express();
const PORT = process.env.PORT || 3000;
const CLIENT_DIST_PATH = join(process.cwd(), 'dist/demo-app'); // TODO: パスをビルド先フォルダ名に合わせる
// 動的に生成される dist ファイルため、require() のままにしておく
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require(join(process.cwd(), 'dist/demo-app-server/main')); // TODO: パスをビルド先フォルダ名に合わせる

// テンプレートファイル名で拡張子が省略された場合のデフォルト拡張子を設定
webServer.set('view engine', 'html');
// テンプレートファイルを置くパスを設定
webServer.set('views', CLIENT_DIST_PATH);
// レンダリングに利用するテンプレートエンジンに Angular Express エンジン を登録
webServer.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [ provideModuleMap(LAZY_MODULE_MAP) ]
}));
// サーバサイドレンダリングされる静的ファイル
webServer.get('*.*', express.static(CLIENT_DIST_PATH));

// 全ての API ルートは このルーティングを使用
webServer.use('/api/*', (req, res) => {
  console.log('[API が呼び出されました]');
  const response = { test1: 'aaa', test2: 'bbb' };
  res.status(200).send(response);
});

// 全ての通常ルートは Universal エンジンを使用
webServer.get('*', (req, res) => {
  console.log('[通常ルートが呼び出されました]');
  res.render('index', { req, res });
});

// Node サーバ開始
webServer.listen(PORT, () => {
  console.log(`Node server is listening - http://localhost:${PORT}`);
});

起動確認

起動スクリプト修正

以下のとおりに、package.json のスクリプトを修正

package.json
:
  "scripts": {
    "start": "node ./dist/server/web-server.js",
    "build": "npm run build:client && npm run build:server",
    "build:client": "ng run demo-app:app-shell:production",
    "build:server": "tsc --project server --outDir dist --allowjs true",
  },
:

以下のコマンドでビルド、アプリ起動

# ビルド
npm run build

# 起動
npm run start

以下の点をチェックし、問題なく動いていればOK。

  • ビルド完了後、以下のディレクトリと中身がルートディレクトリ配下に生成されているか
    • dist/common(クラサバ共用ファイル群)
    • dist/demo-app(クライアントのソースコード)
    • dist/demo-app-server(Universal 対応で作ったやつ)
    • dist/server(Express および API ロジック用ファイル群)
  • Web ブラウザにアクセスし、以下の挙動が行われるか
    • http://localhost:3000 でアクセスするとホーム画面が表示され、コンソールには [通常ルートが呼び出されました] と標準出力される
    • http://localhost:3000/api/aaa でアクセスすると、画面に {"test1":"aaa","test2":"bbb"} と表示され、コンソールには [API が呼び出されました] と標準出力される
    • http://localhost:3000/api でアクセスすると、URLは http://localhost:3000 となり、画面は何かしらの HTML で画面表示がなされ、コンソールには何かしらのエラーログが標準出力される(存在しないページへのアクセスエラー)
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした