LoginSignup
10
8

More than 5 years have passed since last update.

Cloud Functions for FirebaseでAngular Universal

Last updated at Posted at 2017-08-08
1 / 28

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


今回のGitHubリポジトリ


参考にしたもの


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

動作確認


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


Thanks :raised_hands_tone1:

10
8
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
10
8