My angular application has universal set up and running, but server side rendering wasn't taking place. I got a suggestion and step by step tutorial on what to do, because apparently ssr wasn't working since I was using "window" and "localstorage". I had to replace them with the ones provided by @ng-toolkit/universal This is the service that I created
import { Injectable, Inject } from '@angular/core';
import { LOCAL_STORAGE } from '@ng-toolkit/universal';
@Injectable({
providedIn: 'root'
})
export class LocalService implements Storage {
constructor(@Inject(LOCAL_STORAGE) private localStorage: any) {}
get length(): number {
return this.localStorage.length;
}
clear(): void {
this.localStorage.clear();
}
getItem(key: string): any {
return this.localStorage.getItem(key);
}
key(index: number): string | null {
return this.localStorage.key(index);
}
removeItem(key: string): void {
this.localStorage.removeItem(key);
}
setItem(key: string, data: string): void {
this.localStorage.setItem(key, data);
}
[key: string]: any;
[index: number]: string;
}
After it got errors, I found that I needed to include it in app.module.ts as a provider like this
providers: [
{ provide: LOCAL_STORAGE, useFactory: () => window.localStorage }
]
Afterwards, in every component where I had localStorage, I imported the service and implemented it instead
import { LocalService } from '../services/local.service';
constructor(private localStorage: LocalService)
this.localStorage.setItem('lang', 'en');
this.localStorage.getItem('lang');
The application runs fine when using ng serve/npm start to run it client side, but when building the app with "npm run build:ssr" and serving it locally, I get the following error
Node Express server listening on http://localhost:4000
ERROR TypeError: Cannot read properties of undefined (reading 'getItem')
This is what my server.ts file looks like
import 'zone.js/dist/zone-node';
import * as express from 'express';
import { join } from 'path';
// Fix for non SSR modulеs
const domino = require('domino');
const fs = require('fs');
const path = require('path');
const compression = require('compression');
const template = fs.readFileSync(path.join('.', 'dist/browser', 'index.html')).toString();
const win = domino.createWindow(template);
// tslint:disable-next-line:no-string-literal
global['window'] = win;
// tslint:disable-next-line:no-string-literal
global['document'] = win.document;
// tslint:disable-next-line:no-string-literal
global['DOMTokenList'] = win.DOMTokenList;
// tslint:disable-next-line:no-string-literal
global['Node'] = win.Node;
// tslint:disable-next-line:no-string-literal
global['Text'] = win.Text;
// tslint:disable-next-line:no-string-literal
global['HTMLElement'] = win.HTMLElement;
// tslint:disable-next-line:no-string-literal
global['navigator'] = win.navigator;
// tslint:disable-next-line:no-string-literal
global['MutationObserver'] = getMockMutationObserver();
function getMockMutationObserver() {
return class {
observe(node, options) { }
disconnect() { }
takeRecords() {
return [];
}
};
}
// End of Fix for non SSR modulеs
// Express server
const app = express();
const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist/browser');
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP, ngExpressEngine, provideModuleMap } = 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}`);
});
I looked for an answer but couldn't find it anywhere. If you can answer or know the issues I would highly appreciate it.