Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular 5 & Angular CLI & Angular Universal - SSR #51

Open
alexbaron50 opened this issue Dec 13, 2017 · 4 comments
Open

Angular 5 & Angular CLI & Angular Universal - SSR #51

alexbaron50 opened this issue Dec 13, 2017 · 4 comments

Comments

@alexbaron50
Copy link

alexbaron50 commented Dec 13, 2017

I have managed to integrate the MCB with an Angular application and make it work with Angular Universal on the server.

To make it work I just modified the angular-cli.json file to include the generated bundler script like this:

{
    "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
    "project": {
      "name": "ng-universal-demo"
    },
    "apps": [
      {
        "root": "src",
        "outDir": "dist/browser",
        "assets": [
          "assets",
          "favicon.ico"
        ],
        "index": "index.html",
        "main": "main.ts",
        "polyfills": "polyfills.ts",
        "test": "test.ts",
        "tsconfig": "tsconfig.app.json",
        "testTsconfig": "tsconfig.spec.json",
        "prefix": "app",
        "styles": [
          "styles.css"
        ],
        "scripts": [
          "meteor_packages/meteor-client.js"
        ],
        "environmentSource": "environments/environment.ts",
        "environments": {
          "dev": "environments/environment.ts",
          "prod": "environments/environment.prod.ts"
        }
      },
      {
        "platform": "server",
        "root": "src",
        "outDir": "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"
        }
      }
    ],
    "e2e": {
      "protractor": {
        "config": "./protractor.conf.js"
      }
    },
    "lint": [
      {
        "project": "src/tsconfig.app.json",
        "exclude": "**/node_modules/**"
      },
      {
        "project": "src/tsconfig.spec.json",
        "exclude": "**/node_modules/**"
      },
      {
        "project": "e2e/tsconfig.e2e.json",
        "exclude": "**/node_modules/**"
      }
    ],
    "test": {
      "karma": {
        "config": "./karma.conf.js"
      }
    },
    "defaults": {
      "styleExt": "css",
      "component": {
        "spec": false,
        "inlineStyle": true,
        "inlineTemplate": true
      },
      "directive": {
        "spec": false
      },
      "class": {
        "spec": false
      },
      "guard": {
        "spec": false
      },
      "module": {
        "spec": false
      },
      "pipe": {
        "spec": false
      },
      "service": {
        "spec": false
      }
    }
  }

With this configuration a new file script.[hash].bundle.js is generated and it contains the needed meteor scripts to connect to the meteor server.

To resolve the meteor dependencies I modified the tsconfig file so the packages resolves to and specific file where I export the desired package, specifically the paths option:

{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "baseUrl": "./",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "skipLibCheck": true,
    "stripInternal": true,
    "noImplicitAny": false,
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ],
    "paths": {
      "meteor/meteor": [
        "meteor_packages/meteor.js"
      ],
      "meteor/mongo": [
        "meteor_packages/mongo.js"
      ],
      "meteor/tracker": [
        "meteor_packages/tracker.js"
      ]
    }
  },
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}

And finally inside the src folder I created a folder called meteor_packages and inside that folder I copied the meteor bundle generated, and a file for each package I need on the app. For example this is the content of mongo.js

export const { Mongo } = Package['mongo'];

I made a repository based on the Angular Universal Starter where you can see my code: https://github.com/alexbaron50/meteor-angular-universal

To make it work you just have to have a meteor server running on http://localhost:3015 and have published a collection by the name of settings.

When you run the application you will see that there is a connection between the app and the server, everything work as expected. However when I generate the needed files to make it run as SSR, all html is generated on the server except for the information that is grabbed from the sever. This is the code of the component where I grab the information:

import { Component, OnInit } from '@angular/core';
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';

import { Settings } from '../../../api/collections/settings.collection';
import { NgZone } from '@angular/core';
import { Observable } from 'rxjs/Observable';

@Component({
  selector: 'app-alex',
  template: `
    <p>
      alex works!
    </p>
    <ul>
      <li *ngFor="let setting of settings | async">{{setting._id}}</li>
    </ul>
  `,
  styles: []
})
export class AlexComponent implements OnInit {

  settings: Promise<any[]>;

  constructor (
    private zone: NgZone,
  ) {
    this.settings = this.getSettings();
   }

   ngOnInit() {}

  async getSettings() {
    const settings = await new Promise<any[]>((resolve, reject) => {

      Meteor.subscribe("settings", {
        onReady: () => {
          resolve(Settings.find({}).fetch());
        }
      });
    });
    
    return settings;
  }

}

In order to make the app fully SEO friendly I need to have that information rendered on the server, however this is the html that I get from that part:

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>NgUniversalDemo</title><base href="/"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" type="image/x-icon" href="favicon.ico"><link href="styles.d41d8cd98f00b204e980.bundle.css" rel="stylesheet"></head><body><app-root ng-version="5.1.0">
<h1>Universal Demo using Angular and Angular CLI</h1>
<a routerlink="/" href="/">Home</a>
<a routerlink="/lazy" href="/lazy">Lazy</a>
<a routerlink="/lazy/nested" href="/lazy/nested">Lazy_Nested</a>
<a routerlink="/async" href="/async">Alex</a>
<router-outlet></router-outlet><app-alex>
<p>
alex works!
</p>
<ul>
<!---->
</ul>
</app-alex>
</app-root><script type="text/javascript" src="inline.eb3100164b29d2bf3efc.bundle.js"></script><script type="text/javascript" src="polyfills.b1385e24ac5fb8930eae.bundle.js"></script><script type="text/javascript" src="scripts.93264fe3a201e13e967b.bundle.js"></script><script type="text/javascript" src="main.cfb4a48d9421f30684d6.bundle.js"></script></body></html>

This is the html you see when you view the source of the page, the component is rendered except for the part where I render the information gotten from the server <!---->.

How can I make this part to be rendered on the server?

@xtiannyeto
Copy link

Hi @ardatan,
What do you mean by to mock subscribe to pass data? do you have a quick example?
I have done the exact same step as @alexbaron50 in angular 6 and i'm facing the exact same issue.

@raza2022
Copy link

@ardatan I am having the same issue as @DarkChopper mentioned. do you have example of it. @DarkChopper have you solved it?

@xtiannyeto
Copy link

@raza2022 Nope, i haven't yet.. I'm still running into it.

@6at9l
Copy link

6at9l commented Nov 22, 2018

Hi, i use anular 6 and MCB, but now needed add SSR in my project, it is possible to use MCB with SSR on the server side ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants