Title and Meta tags not rendering in angular SSR in server
Asked Answered
O

3

8

I have developed a website using Angular 6 in the frontend. By default Angular is not SEO friendly, so in order to do that, I implemented it in the way of Angular-Universal or Angular SSR (Server Side Rendering). I updated the code and comparing the page sources from before and now, I can see my application inside the tags <app-root> and </app-root>, before only "loading..." would come.

I am using the MetaService and TitleService from @angular/platform-browser to update the desired <meta> tags for Facebook and Twitter and the <title> tag respectively.

The problem is when I run the node server in my local system, view-source shows me the rendered meta tags, but when I run the same code in node server on AWS VM, I don't get the rendered meta tags, but other application code is available.

UPDATE: The function that adds the meta tags

updateMetaTags(egElement: Elements[]) {
    this.url = 'https://example.com/eg/' + this.id;
    const title = egElement[1].innerHTML;
    this.tweetText = 'Check the latest blog on \"' + title + '\"';
    this.meta.addTags([
      { property: 'og:url', content: this.url },
      { property: 'og:type', content: 'website' },
      { property: 'og:title', content: title },
      { property: 'og:description', content: 'Author: ' + egElement[2].innerHTML },
      { property: 'og:image', content: this.egElement[3].img }
    ]);
  }

I call this function in ngOnInit(). It does the rendering properly in my local machine, but does not do it on the server.

egElement and id is returned from the service call to backend and meta service has been imported and injected in the constructor.

Olgaolguin answered 5/11, 2018 at 11:21 Comment(13)
can you show the code for generating the meta tags?Nigger
@PierreDuc I have updated the question, please check.Olgaolguin
Any conditions while calling updateMetaTags in ngOnInit? Can you provide the code until that updateMetaTags method is called?Smash
@dcballs No conditions while calling it in ngOnInit(). Inspect elements shows me the meta tags in both local and server, so the code is working. But it doesn't get rendered in view-source in server env. Please check the URL. Check the console, have added logs for calling the method updateMetaTags.Olgaolguin
The most of your content is not rendered into the html on the server side. If you want to have proof that content is rendered and delivered, you can disable javascript on your website. Do you use a third party library for the API calls?Smash
No 3rd party APIs are used. I'll try by disabling js in my browser.Olgaolguin
Looking to the network logs of my browser, I can see an xhr to dev.******/SharedExperiences/getBlogApi/22. Do you even want this xhr on the page which you want to render on the server side already?Smash
@dcballs This XHR gets the data for the page. If you can get deeper into this, we could continue in a chat maybe?Olgaolguin
@Olgaolguin any suggestions or any preferred chat? Maybe Discord?Smash
@dcballs ok, I'll sign up for it, let me know your id.Olgaolguin
@dcballs my discord username is inthevortex#2471 and email is [email protected]Olgaolguin
@Olgaolguin is issue resolved?Poulter
I am also facing the same problem. Did you manage to resolve this? I believe it is a bug in Angular ssr. After I updated to Angular 17 it stopped working, but I'm not sure, because it was in some version that it stopped working and I had made several Angular updates. My suspicion seems to be when updating meta tags after receiving content from the API, as on another page that updates directly (without consuming the API) there is no problem.Perennate
D
4

If you're using custom XHR calls , e.g. not using Angular HttpClient, the SSR won't wait for API call responses (this can also occur if using 3rd party libraries to retrieve API data). Looking at your site there is no server side rendering occurring other than the page layout/header/footer

I'm guessing it's related to the API data not being retrieved in SSR. Maybe you could update your question with some info on this?

There is a well tested and maintained library called ngx-meta that's universal (SSR) compatible. You could look at their implementation, and demos, or give their library a go https://github.com/fulls1z3/ngx-meta

Dardanelles answered 13/11, 2018 at 10:1 Comment(6)
I am using Angular HttpClient.Olgaolguin
The service is fetching the data from the backend API. Yes I am rendering the page and want to render the meta tags related to it. The meta tags aren't getting rendered.Olgaolguin
The API can use any backend. You may need to add route resolvers, and apply your meta tags in the resolver. This would mean that the server side rendering would wait for the tags to be added before continuing and completing the render process. This might be worth looking into. I tried your site with JS turned off, and the body is not rendering, so that's what led me to this (although maybe you're aware of that already)Dardanelles
The ssr is sort of failing because of error thrown by one of the packages, I am trying a way around it. Will surely try this method and let you know.Olgaolguin
any updates man? i set the meta tags inside an observable subscription in ngoninit but they are not set when deployed using angular ssrFrump
I am using ngx-meta as well, but it does not work with SSR. If you have any suggestions please tell meCreighton
E
2

Hi I also was facing this error so make sure in your server.ts file to have imported import 'reflect-metadata'; to reflect all meta to index.html

You can take a look at my server.ts config file\

import 'zone.js/dist/zone-node';
import 'reflect-metadata';

import { enableProdMode } from '@angular/core';
// Express Engine
import { ngExpressEngine } from '@nguniversal/express-engine';
// Import module map for lazy loading
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';

import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';

// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express server
const app = express();

const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist/browser');

const template = readFileSync(join(DIST_FOLDER, 'index.html')).toString();

const domino = require('domino');
const win = domino.createWindow(template);
global['localStorage'] = win.localStorage;
global['window'] = win;
global['document'] = win.document;
global['Document'] = win.document;
global['DOMTokenList'] = win.DOMTokenList;
global['Node'] = win.Node;
global['Text'] = win.Text;
global['HTMLElement'] = win.HTMLElement;
global['navigator'] = win.navigator;
global['MutationObserver'] = getMockMutationObserver();

function getMockMutationObserver() {
  return class {
    observe(node, options) {}

    disconnect() {}

    takeRecords() {
      return [];
    }
  };
}

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');

// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
app.engine(
  'html',
  ngExpressEngine({
    bootstrap: AppServerModuleNgFactory,
    providers: [provideModuleMap(LAZY_MODULE_MAP)],
  }),
);

app.set('view engine', 'html');
app.set('views', DIST_FOLDER);

// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
app.get(
  '*.*',
  express.static(DIST_FOLDER, {
    maxAge: '1y',
  }),
);

// All regular routes use the Universal engine
app.get('*', (req, res) => {
  res.render('index', { req });
});

// Start up the Node server
app.listen(PORT, () => {
  console.log(`Node Express server listening on http://localhost:${PORT}`);
});
Eckman answered 30/7, 2019 at 9:54 Comment(0)
R
0

Basically Server.ts file is responsible for perform server-side rendering. The flow is like first Server.ts hits the url which we are searching then the result will be rendered and again browser request will hit the url. If we are using any localstorage , session storage, windows in the code level this will not be accessed by server, so the flow will be disconnected and initial static data in the page only rendered.We can control browser request if already server rendered the page by using State Transfer Key Mechanism.

Rainbolt answered 13/6, 2024 at 9:15 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.