1

I have just created a simple Angular SSR application using Angular CLI: 18.2.12.

I am not using ngExpressEngine, but I am using @angular/platform-server

The application works fine with npm run build:ssr and npm run serve:ssr.

However, when I use built-in browser objects like localStorage, sessionStorage, window, location, document, or isBrowser, I encounter errors.

I understand that these objects are not accessible on the server.

In my application, these variables (e.g., localStorage and window) are used extensively. I tried using libraries like Domino and JSDOM, but they didn’t work properly.

I also referred to this post: Angular CLI - How to use window, document, or location in environment.ts.

Still, I couldn’t find a better solution.

Here is my server.ts file:

    import 'zone.js/node';
import { renderModule } from '@angular/platform-server';
import express from 'express';
import { join } from 'path';
import AppServerModule from './src/main.server';
// import { readFileSync } from 'fs';
// import { JSDOM } from 'jsdom'


const app = express();
const PORT = process.env['PORT'] || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist/angular-ssr-project/browser');

// Serve static files
app.use(express.static(join(DIST_FOLDER, 'browser'), {
  maxAge: '1y',
  index: false
}));


// Serve SSR page
app.get('*', (req, res) => {
  renderModule(AppServerModule, {
    document: '<app-root></app-root>',
    url: req.url
  }).then(html => {
    res.send(html);
  }).catch(err => {
    console.error('SSR Rendering Error:', err);
    res.status(500).send('Error during SSR rendering');
  });
});

// Start the server
app.listen(PORT, () => {
  console.log(`Node Express server listening on http://localhost:${PORT}`);
});

// const dom = new JSDOM('<!doctype html><html><body></body></html>');
// global['window'] = dom.window;
// global['document'] = dom.window.document;
// ...
// ...

// const template = readFileSync(join(DIST_FOLDER, 'index.html')).toString();
// const win = createWindow(template);
// global['window'] = win as any;
// global['document'] = win.document;
// global['navigator'] = win.navigator;

// ...
// ...

1 Answer 1

0

If you want you can import document inside angular using:

DOCUMENT

A DI Token representing the main rendering context. In a browser and SSR this is the DOM Document. When using SSR, that document is created by Domino.

export class SomeComponent {
  document: DOCUMENT = inject(DOCUMENT);
  ...

Apart from this, we have the following techniques to bypass the errors arising from lack of localStorage, sessionStorage, document and window.

The below approach, does not do SSR, for the HTMLbut you can show a spinner to temporarily show until the proper screen loads.

@defer() {

} @placeholder { Loading... }

You can use isPlatformBrowser to conditionally execute code only on the browser.

import { inject, Inject, Injectable, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
...

...
platformId = inject(PLATFORM_ID);
...

...
ngOnInit () {
  if(isPlatformBrowser(this.platformId)) {
    const query = this.activatedRoute.snapshot.queryParams;
    if (!query.code) {
        this.router.navigate(['/auth/login']);
    } else {
        this.checkGoogleCodeAndRedirect(query);
    }
  }
}

You can also use afterNextRender to do the same. The code inside the callback executes only on the browser.

ngOnInit () {
  afterNextRender(() => {
    const query = this.activatedRoute.snapshot.queryParams;
    if (!query.code) {
        this.router.navigate(['/auth/login']);
    } else {
        this.checkGoogleCodeAndRedirect(query);
    }
  });
}
Sign up to request clarification or add additional context in comments.

2 Comments

isPlatformBrowser this condition cant set as true so how i use window, location, document... objects.?
@KishanBhola You should not execute this code in server, just bypass it, it will work fine on the browser,

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.