meteor-client-bundler
meteor-client-bundler copied to clipboard
Angular 5 & Angular CLI & Angular Universal - SSR
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?
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.
@ardatan I am having the same issue as @DarkChopper mentioned. do you have example of it. @DarkChopper have you solved it?
@raza2022 Nope, i haven't yet.. I'm still running into it.
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 ?