Reputation: 91
I'm having an Angular application with Angular Universal to support Server-Side Rendering (SSR). I have a problem on a root page. All other routes works perfectly on a SSR, but the "/" does not. As a try for a home route changed "/" to "/app" and it works correctly!. I'm using Angular Universal, Lambda edge Function, and Cloud front.
my server.ts file:
import 'zone.js/dist/zone-node';
import { join } from 'path';
import * as fs from 'fs';
import { renderModule, AppServerModule } from './src/main.server';
import express from 'express';
import 'localstorage-polyfill'
const domino = require('domino');
const path = require('path');
const templateA = join(process.cwd(), 'dist/prj/browser');
const win = domino.createWindow(templateA);
win.Object = Object;
win.Math = Math;
win.navigator.language = 'en';
global['window'] = win;
global['self'] = win;
global['document'] = win.document;
global['branch'] = null;
global['object'] = win.object;
global['localStorage'] = localStorage;
global['Node'] = win.Node;
global['navigator'] = win.navigator;
global['Event'] = win.Event;
global['KeyboardEvent'] = win.Event;
global['MouseEvent'] = win.Event;
global['Event']['prototype'] = win.Event.prototype;
global['document'] = win.document;
global['location'] = win.location;
console.log('start serverless');
export const app = express();
const distFolder = join(process.cwd(), 'dist/prj/browser');
app.set('view engine', 'html');
app.set('views', distFolder);
// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
app.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
app.get('*', (req, res) => {
fs.readFile(join(process.cwd(), 'dist/prj/browser/index.html'), function (err, html) {
if (err) {
throw err;
}
// console.log('req => ', req.url);
renderModule(AppServerModule, {
url: req.url,
document: html.toString()
}).then((html) => {
// console.log('html => ', html);
res.send(html);
}).catch(err => {console.log('err => ', err);});
});
});
const run = () => {
const port = process.env.PORT || 4201;
app.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
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';
My lambda function :
const path = require('path')
const serverless = require('serverless-http');
const minify = require('html-minifier').minify;
const { app } = require("./dist/prj/serverless/main");
const handle = serverless(app, {
provider: 'aws',
type: 'lambda-edge-origin-request'
});
const handler = async (event, context, callback) => {
const request = event.Records[0].cf.request;
if ((!path.extname(request.uri)) || (request.uri === '/index.html') || (request.uri === 'index.html')) {
const response = await handle(event, context);
let minified = minify(response.body, {
caseSensitive: true,
collapseWhitespace: true,
preserveLineBreaks: true,
removeAttributeQuotes: true,
removeComments: true
});
console.log('response: ', response)
callback(null, {
status: response.status,
statusDescription: response.statusDescription,
headers: {
...response.headers,
},
body: minified,
bodyEncoding: response.bodyEncoding
});
} else {
console.log(`${request.uri} directly served from S3`)
return request;
}
}
exports.handler = handler;
Upvotes: 4
Views: 825
Reputation: 91
After a few hours of searching and facing the same issue using Angular and Angular Universal, I've finally found a solution that works for me. Give it a try!
The problem was with the Default root object CloudFront, it should be empty, my default value was index.html that's why I receive just the content of this file in SSR. also I check for the empty route on my lambda function.
const handle = serverless(app, {
provider: 'aws',
type: 'lambda-edge-origin-request'
});
const handler = async (event, context, callback) => {
const request = event.Records[0].cf.request;
if ((!path.extname(request.uri)) || (request.uri === '/index.html') ||(request.uri === '') || (request.uri === '/')) {
const response = await handle(event, context);
let minified = minify(response.body, {
caseSensitive: true,
collapseWhitespace: true,
preserveLineBreaks: true,
removeAttributeQuotes: true,
removeComments: true
});
console.log('response: ', response)
callback(null, {
status: response.status,
statusDescription: response.statusDescription,
headers: {
...response.headers,
},
body: minified,
bodyEncoding: response.bodyEncoding
});
} else {
console.log(`${request.uri} directly served from S3`)
return request;
}
}
exports.handler = handler;
Upvotes: 3