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

Cloud Functions for FirebaseでAngular Universal

More than 3 years have passed since last update.

Cloud Functions for FirebaseでAngular Universal

by ovrmrw
1 / 28

名前: ちきさん
所属: オプト
GitHub/Twitter/Qiita: @ovrmrw


今回のGitHubリポジトリ

https://github.com/ovrmrw/angular-universal-with-firebase-hosting


参考にしたもの

https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/universal-rendering.md

https://medium.com/@cdeniz/angular-universal-on-firebase-dynamic-hosting-4fdd034af3db

https://medium.com/@cyrilletuzi/angular-server-side-rendering-in-node-with-express-universal-engine-dce21933ddce


Angular Universalやってみたい :blush:


Expressが必要... :pensive:


Firebase好きだし、Firebase HostingでAngular Universalやりたい :blush:


Firebase HostingにはExpressアプリをホスティングできない... :pensive:


Cloud Functions for Firebaseでワンチャンあるかも...! :smiling_imp:


Angular CLI 1.3.0-rc.3以上とFirebase CLIをインストールする

$ npm install -g @angular/cli@next firebase-tools

ng new で新しいプロジェクトを作成する。

$ ng new angular-universal-with-firebase-hosting

Firebaseプロジェクトにする。

$ cd angular-universal-with-firebase-hosting
$ firebase init

※ HostingとFunctionsは必須。その他は下記のように設定する。

Do you want to install dependencies with npm now? (Y/n): N
What do you want to use as your public directory? (public): public
Configure as a single-page app (rewrite all urls to /index.html): Y

@angular/platform-serverをインストールする。

$ npm install --save-dev @angular/platform-server

src/app/app.module.ts を編集する。

src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    // BrowserModule
    BrowserModule.withServerTransition({ appId: 'my-app' }) // ←ここ
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

src/app/app.server.module.ts を追加する。

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: [
    AppModule, // ←ここにAppModuleを入れる。
    ServerModule,
  ],
  bootstrap: [AppComponent],
})
export class AppServerModule { }

src/main.server.ts を追加する。

src/main.server.ts
import { enableProdMode } from '@angular/core';
export { AppServerModule } from './app/app.server.module';

enableProdMode();

src/tsconfig.server.json を追加する。

src/tsconfig.server.json
{
  "extends": "./tsconfig.app.json",
  "compilerOptions": {
    "module": "commonjs"
  },
  "exclude": [
    "test.ts",
    "**/*.spec.ts"
  ],
  "angularCompilerOptions": {
    "entryModule": "app/app.server.module#AppServerModule"
  }
}

angular-cli.json を編集する。

.angular-cli.json
{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "angular-universal-with-firebase-hosting"
  },
  "apps": [
    {
      .......
    },
    {
      "platform": "server",
      "root": "src",
      "outDir": "functions/dist-server",
      "assets": [
        "assets",
        "favicon.ico"
      ],
      "index": "index.html",
      "main": "main.server.ts",
      "test": "test.ts",
      "tsconfig": "tsconfig.server.json",
      "testTsconfig": "tsconfig.spec.json",
      "prefix": "app",
      "styles": [
        "styles.css"
      ],
      "scripts": [],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ],
  .......
}

src/index.html を functions/dist-serverディレクトリ にコピーする。

$ cp src/index.html functions/dist-server

functions/package.json の dependencies を編集する。この後 functionsディレクトリに移動して npm install する。

functions/package.json

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "dependencies": {
    "firebase-admin": "~4.2.1",
    "firebase-functions": "^0.5.7",
    "@angular/animations": "^4.0.0",
    "@angular/common": "^4.0.0",
    "@angular/compiler": "^4.0.0",
    "@angular/core": "^4.0.0",
    "@angular/forms": "^4.0.0",
    "@angular/http": "^4.0.0",
    "@angular/platform-browser": "^4.0.0",
    "@angular/platform-browser-dynamic": "^4.0.0",
    "@angular/platform-server": "^4.0.0",
    "@angular/router": "^4.0.0",
    "core-js": "^2.4.1",
    "express": "^4.15.3",
    "rxjs": "^5.4.2",
    "zone.js": "^0.8.16"
  }
  "private": true
}

functions/index.js を編集する。

functions/index.js
require('zone.js/dist/zone-node');
const functions = require('firebase-functions');
const express = require('express');
const path = require('path')

const renderModuleFactory = require('@angular/platform-server').renderModuleFactory;

const AppServerModuleNgFactory = require('./dist-server/main.bundle').AppServerModuleNgFactory;

const index = require('fs').readFileSync(path.resolve(__dirname, './dist-server/index.html'), 'utf8');

const app = express();

app.get('/', (req, res) => {
  renderModuleFactory(AppServerModuleNgFactory, { document: index, url: '/' })
  .then(html => {
    res.send(html);
  })
  .catch(err => {
    console.log(err)
  });
});

exports.ssr = functions.https.onRequest(app);

firebase.json を編集する。

firebase.json
{
  "hosting": {
    "public": "public",
    "rewrites": [
      {
        "source": "**",
        "function": "ssr"
      }
    ]
  }
}

publicフォルダを追加し、空の hoge.css というファイルを配置する。

(ファイルが何もないとそのフォルダをFirebase Hostingにデプロイできないため)


package.json の scripts を編集する。

package.json
{
  "scripts": {
    .....,
    "build": "ng build --prod --app 1 --output-hashing=none",
    "copy": "cp src/index.html functions/dist-server", 
    "deploy": "npm run build && npm run copy && firebase deploy",
    .....
  }
}

デプロイする。

$ npm run deploy

動作確認

https://easy-ng-universal.firebaseapp.com/


なにかいろいろもんだいはありそうだけど、くわしいことはよくわからない。


Thanks :raised_hands_tone1:

ovrmrw
ちきさんです。ただのWebエンジニアです。
http://overmorrow.hatenablog.com/
opt
"INNOVATION AGENCY" を標榜するインターネット広告代理店。エンジニア組織 "Opt Techonologies" を中心にアドテクetc...に取り組んでいます。
https://opt-technologies.jp/
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