Reputation: 123
I'm building a project in Angular using SAP Spartacus storefront.
I need to enable SSR on this project, but when the server is ready to access then crashes, with the error: ReferenceError: Element is not defined.
I've folloed the instructions on this doc: https://sap.github.io/spartacus-docs/server-side-rendering-in-spartacus/#adding-ssr-support-manually
Up this message, have alot of JS in red, like that:
I tryed to scroll into start of message, but the error pass the char limit of terminal.
I tryed to find this 'Element' var, but no success.
Thanks for your time.
I've found the error is on AdyenCheckout lib, but still not working.
Follow my tryed solutions:
...
Isolating the SSR checkout URL, but unsuccessfully, I believe this is due to the fact that the problem is generated during the build and not during route requests... Still we think it would be a valid test, but without success.
Using the domino lib, which can emulate the Window, Document and others variable, including the Element variable, but somehow we were not successful either.
We were informed that when using the domino lib, we have to declare the variables before importing the AppServerModule into server.ts, we also tried it but without a solution.
We think it's something related to Adyen, because when removing the AdyenCheckout import and instantiation from the component it doesn't show any more errors.
Our frontend project is being built using storefront SAP Spartacus 3.4, Angular 10.2.4, Node 12.22.1, npm 6.14.12 and TypeScript 4.0.7.
Here's our updated server.ts file.
/***************************************************************************************************
* Load `$localize` onto the global scope - used if i18n tags appear in Angular templates.
*/
import '@angular/localize/init';
import 'zone.js/dist/zone-node';
const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs.readFileSync(path.join(join(process.cwd(), 'dist/spartacus/browser'), 'index.html')).toString();
Object.assign(global, domino.impl);
// tslint:disable-next-line: no-string-literal
(global as any)['Element'] = domino.impl.Element;
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;
import { ngExpressEngine as engine } from '@nguniversal/express-engine';
import { NgExpressEngineDecorator } from '@spartacus/setup/ssr';
import * as express from 'express';
import { join } from 'path';
import { APP_BASE_HREF } from '@angular/common';
import { existsSync } from 'fs';
import 'localstorage-polyfill';
/* tslint:disable-next-line no-string-literal */
global['localStorage'] = localStorage;
const ngExpressEngine = NgExpressEngineDecorator.get(engine);
import { AppServerModule } from './src/main.server';
// The Express app is exported so that it can be used by serverless Functions.
// tslint:disable-next-line: typedef
export function app() {
const server = express();
const distFolder = join(process.cwd(), 'dist/spartacus/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
server.engine(
'html',
ngExpressEngine({
bootstrap: AppServerModule
})
);
server.set('view engine', 'html');
server.set('views', distFolder);
// restrict folders
server.get('/checkout/**', (req, res) => {
res.sendFile(join(distFolder, 'index.html'));
});
// Serve static files from /browser
server.get(
'*.*',
express.static(distFolder, {
maxAge: '1y'
})
);
// All regular routes use the Universal engine
server.get('*', (req, res) => {
res.render(indexHtml, {
req,
providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }]
});
});
return server;
}
// tslint:disable-next-line: typedef
function run() {
const port = process.env.PORT || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
// tslint:disable-next-line: no-console
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 './src/main.server';
Upvotes: 0
Views: 410