angular-oauth2-oidc: Error on npm run serve:ssr

Describe the bug I’m trying to build and serve a local app in ssr mode but npm run server:ssr crash.

To Reproduce Steps to reproduce the behavior:

  1. npm install angular-oauth2-oidc --save
  2. add OAuthModule.forRoot() on AppModule
  3. npm run build:ssr && npm run serve:ssr or npm run dev:ssr

Expected behavior Node Express server listening on http://localhost:4000

Additional context ReferenceError: Document is not defined at Module../node_modules/angular-oauth2-oidc/fesm2015/angular-oauth2-oidc.js

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 17
  • Comments: 36 (11 by maintainers)

Commits related to this issue

Most upvoted comments

I created a new Angular 9 project and added SSR, keeping everything default.

Then as a test, I injected the DOCUMENT token in AppComponent and use it in ngOnInit(). I could not reproduce the problem.

However, as soon as I added angular-oauth2-oidc and OAuthModule.forRoot in AppModule I got the error (Document is not defined) on build.

Seems to me there is something specific with angular-oauth2-oidc. If I get some more time I will do some more testing.

still no news about this issue ? i’ve tried some fixes on my side but without any luck yet …

We were able to work around this, for now, by adding Document to the global object when running on the server. For example, add

(global as any).Document = (global as any).Document || {};

at the beginning of your main.server.ts. Be careful to add this in a file that is included only on the server.

I have also added a PR for this #853.

I have just added this in my tsconfig.server.json, and I still have the error

"lib": ["DOM", "ES2015"],

I’m getting the error as well, working with angular-oauth2-oidc v9 (Angular 9.1.0). At the moment now sure why.

ReferenceError: Document is not defined
    at Module../node_modules/angular-oauth2-oidc/fesm2015/angular-oauth2-oidc.js (C:\***\dist\***\server\main.js:206143:9)

The line it is referring to in main.js:

OAuthService = Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__decorate"])([ 
...
...
[_angular_core__WEBPACK_IMPORTED_MODULE_1__["NgZone"],
        _angular_common_http__WEBPACK_IMPORTED_MODULE_3__["HttpClient"],
        OAuthStorage,
        ValidationHandler,
        AuthConfig,
        UrlHelperService,
        OAuthLogger,
        HashHandler,
        Document])      <--------
], OAuthService);

Hi there,

I was evaluating whether to use this library in my solution because I am using (the) other oidc client option and facing some weird issues regarding token storage at server side (and protected modules CanLoad)…

Well, for all of you that are facing issues with document, window and any other browser APIs here is my advice:

  • Use domino to declare those global vars
  • Here is the most important thing: USE IT BEFORE IMPORTING App ServerModule from main.server

As an example (a working example indeed):

import { APP_BASE_HREF } from '@angular/common';
import '@angular/localize/init';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { existsSync } from 'fs';
import { join } from 'path';
import 'zone.js/dist/zone-node';

// THIS FIX MOST OF THE COMMON ISSUES WITH SSR:
const enDistFolder = join(process.cwd(), 'dist/browser/en');

// Emulate browser APIs
const domino = require('domino');
const fs = require('fs');
const templateA = fs.readFileSync(join(enDistFolder, 'index.html')).toString();

const win = domino.createWindow(templateA);
console.log('win');
win.Object = Object;
console.log('Object');
win.Math = Math;
console.log('Math');

global['window'] = win;
global['document'] = win.document;
global['Event'] = win.Event;
console.log('declared Global Vars....');

/** I need to avoid sorting this line */
// USE CTRL+P -> SAVE WITHOUT FORMATTING
/// --> import { AppServerModule } from './main.server';
import { AppServerModule } from './main.server';
/// --> import { AppServerModule } from './main.server';///
/** I need to avoid sorting this line */

// The Express app is exported so that it can be used by serverless Functions.
export function app() {
  const server = express();
  const distFolder = join(process.cwd(), 'dist/browser');
  const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';

  // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
  server.engine('html', ngExpressEngine({
    bootstrap: AppServerModule,
  }));

  server.set('view engine', 'html');
  server.set('views', distFolder);

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

  server.use('/robots.txt', express.static('/en/robots.txt'));
  server.use('/ads.txt', express.static('/en/ads.txt'));

  // // // All regular routes use the Universal engine
  // // server.get('*', (req, res) => {
  // //   res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
  // // });

  // All regular routes use the Universal engine
  server.get('*', (req, res) => {
    // this is for i18n
    const supportedLocales = ['en', 'es'];
    const defaultLocale = 'es';
    const matches = req.url.match(/^\/([a-z]{2}(?:-[A-Z]{2})?)\//);

    // check if the requested url has a correct format '/locale' and matches any of the supportedLocales
    const locale = (matches && supportedLocales.indexOf(matches[1]) !== -1) ? matches[1] : defaultLocale;

    res.render(`${locale}/index`, { req });

    // // AS A POC WE WANT TO RENDER ENG VERSION ONLY:
    // // res.render(`en/index`, { req });
  });

  return server;
}

function run() {
  const port = process.env.PORT || 4000;

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

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
  run();
}

export * from './main.server';

Note that this code is using i18n but I left the original request handler.

I hope it helps, I spent a huge amount of time fixing my own issues after Angular 9 migration.

We were able to work around this, for now, by adding Document to the global object when running on the server. For example, add

(global as any).Document = (global as any).Document || {};

at the beginning of your main.server.ts. Be careful to add this in a file that is included only on the server.

I have also added a PR for this #853.

obviously not a long term fix, but this workaround works well on our side too, well done @JohannesHuster

Not sure, I started using it with v9, then tried 8.0.3 and got lots of errors. So that made me fork and “fix” the v9 version

On Thu, 7 May 2020 at 18:43, mikg2003 notifications@github.com wrote:

Dumb question, but out of curiosity, is there something in particular that doesn’t work when using 8.x? I have a similar requirement of using this library with angular 9 and SSR, and it seems to be working ok. You actually have a workable solution, which is the way to go, but again I was just curious. I know we’re supposed to use the matching version, but I’m not sure how to go about finding out what would break, or at least not be guaranteed to work, if using an older package version with the newer angular version.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/manfredsteyer/angular-oauth2-oidc/issues/773#issuecomment-625368127, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAW3SSSY22DXVA3APMXRWLTRQLQMTANCNFSM4LULXJAQ .

Same here, can’t go back to 8.x because I’m on angular ivy / 9 and I can’t release this because we’re using SSR