Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Universal (SSR) Error: Failed to lookup view "index" in views directory

I want to deploy my angular universal app on aws.

From my understanding, I can only deploy my app on elastic beanstalk because it needs a web server to run. (It means no S3 deployment).

When I deploy my app, I have the following error:

Error: Failed to lookup view "index" in views directory "/var/app/current/dist/browser" at Function.render (/var/app/current/server.js:122227:17) at ServerResponse.render (/var/app/current/server.js:131120:7) at /var/app/current/server.js:138:9 at Layer.handle [as handle_request] (/var/app/current/server.js:124007:5) at next (/var/app/current/server.js:123755:13) at Route.dispatch (/var/app/current/server.js:123730:3) at Layer.handle [as handle_request] (/var/app/current/server.js:124007:5) at /var/app/current/server.js:123230:22 at param (/var/app/current/server.js:123303:14) at param (/var/app/current/server.js:123314:14)

Here what I've done so far:

  1. On my angular project, create a production build with the command npm run build:ssr
  2. Create an archive of my dist directory
  3. On Elastic Beanstalk, create a new application with node.js and upload my archive

And my server.ts file:

import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { enableProdMode } from '@angular/core';
// Express Engine
import { ngExpressEngine } from '@nguniversal/express-engine';
// Import module map for lazy loading
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';

import * as express from 'express';
import { join } from 'path';

// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express server
const app = express();

const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist/browser');

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');

// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
app.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [
    provideModuleMap(LAZY_MODULE_MAP)
  ]
}));

app.set('view engine', 'html');
app.set('views', DIST_FOLDER);

// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });

// Server static files from /browser
app.get('*.*', express.static(DIST_FOLDER, {
  maxAge: '1y'
}));

// All regular routes use the Universal engine
app.get('*', (req, res) => {
  res.render('index', { req });
});

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

What am I doing wrong?

Thanks for you help.

like image 884
Johan Rin Avatar asked Feb 02 '19 16:02

Johan Rin


3 Answers

Use the dist folder as your archive instead of the contents of the dist folder.

Set the following 'node command' setting in your elastic beanstalk configuration.

node dist/server

This should allow you to run locally and on AWS EB with the standard Angular out of the box setup.

EDIT Just to give a little more info, this should fix the problem. As pointed out by @Kartik Chandra the problem is in the server.ts file on line

const distFolder = join(process.cwd(), 'dist/landing/browser');

When deploying on your prod env process will look for the dist folder, so if you do not copy it it will fail.

Options are to copy the entiry dist folder or changing your server.ts, however this will break your local development.

like image 126
swuk Avatar answered Nov 20 '22 14:11

swuk


Meanwhile, I found the solution to deploy on Elastic Beanstalk.

Below the different steps I did:

  1. In your Elastic Beanstalk Application, edit the Software Configuration by changing the Node command by node dist/server.js Software Configuration
  2. Edit the port used by nodejs (2 options) :

    a. You can simply edit the port in your server.ts file by 8081 (corresponding to the nodejs port used in the nginx default configuration)

    const PORT = process.env.PORT || 8081;
    

    b. OR you can edit your nginx configuration with a configuration file .ebextensions to match the port used in your angular universal app (4000 by default)

like image 31
Johan Rin Avatar answered Nov 20 '22 14:11

Johan Rin


Instead of:

const DIST_FOLDER = join(process.cwd(), 'dist/browser');

write:

const DIST_FOLDER = join(process.cwd(), 'rootpathofServer/dist/browser');

Example:

const DIST_FOLDER = join(process.cwd(), 'root/www/prod/myProject/dist/browser');

root/www/prod/myProject/dist/browser

The above line refer to the path of my project (build path) from root in nginx aws directory.

And if not working, just console the CWD:

console.log('processPath',process.cwd());

In my case it return / only, so complete path is like /root/www/prod/myProject/dist/browser, which is ('/' + 'root/www/prod/myProject/dist/browser') for this above example.

Yeah it is also true nginx root directory is different from local i.e y it works locally fine and give error on server after deployment.

It took days to sort this issue, I hope it will help you out.
The main problem is simple: it is not able to get index file at particular location or directory.
#LearningNeverEnds

like image 2
Kartik Chandra Avatar answered Nov 20 '22 16:11

Kartik Chandra