laakissi achraf
laakissi achraf

Reputation: 91

Angular universal not rendering properly in Root path '/'

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

Answers (1)

laakissi achraf
laakissi achraf

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

Related Questions