14

I've been looking for about 3 hours for hosting an Angular 4 app on a server with "server-side rendering" enabled. For note - I have a AWS server which has Apache installed (Ubuntu).

First of all, I already know how can we host an Angular 4 app (without server-side rendering). But here my major concern is that I want to enable my app to be enabled for - server-side rendering.

In my local, I use npm start command, which automatically serves the app (with server-side rendering enabled) on - http://localhost:4000

My package.json file looks like this:

...
"scripts": {
    "serve": "ng serve",
    "prestart": "ng build --prod && ngc && webpack",
    "start": "node dist/server.js",
    "build": "ng build"
},
...

These all commands are working fine. But I'm confused that should I again run

npm start

on a production server, so that it also requires node_modules to install. Which doesn't seems the right way to me?

Can anyone please help me with hosting my app with "server-side rendering" enabled.

Matthew Green
  • 10,161
  • 4
  • 36
  • 54
Saumya Rastogi
  • 13,159
  • 5
  • 42
  • 45
  • Weird none of the answerers below bothered even reading your question till the end. I just deployed my angular SSR and proxying via Nginx and having issues with some static files not showing – KhoPhi Dec 16 '17 at 19:56
  • @Rexford Yup, you're right... I'm quite shocked that no one has resd my question properly and they are answering what they like... Actually I'm also doing the same way as yours but I'm using apache instead. – Saumya Rastogi Dec 18 '17 at 03:20
  • I shared how I am running my SSR Angular app in production below. i hope it helps. – KhoPhi Dec 18 '17 at 19:49
  • I've also written an article on how to implement server-side rendering using Angular 4 - https://blog.squareboat.com/how-to-implement-server-side-rendering-using-angular-4-5da10f4dcb61 – Saumya Rastogi Dec 19 '17 at 03:50
  • @Saumya Rastogi Is it possible to deploy angular project on Sentora serve? Plz tell me i need to know. – vidy Sep 25 '20 at 07:40

4 Answers4

6

Can anyone please help me with hosting my app with "server-side rendering" enabled.

Yes. Unfortunately, I use Nginx. However, the approach shouldn't be any different in Apache or whatnot.

So this is how I am hosting my Server Side Rendering Angular application in production (I'm on DO). I wrote an article about it on my blog:

After building your SSR, you should have something like this:

enter image description here

After you managed to send everything within the dist/ folder onto your remote server, you run it using pm2 (which is what I use to run my node apps)

Run pm2 start path/to/dist/server.js --name name_of_process

It should be running on localhost:4000

The Nginx virtual server block below should get all requests proxied through your Nginx to the Server Side Rendering Angular application.

The nginx conf below actually serves both the statics of your angular SSR, and falls back to the proxy when request isn't for a static file.

upstream ssr_khophi_nodejs {
    server 127.0.0.1:4000;
}

server {
    listen 443 ssl http2;

    server_name staging.khophi.com; # <--- Change this part

    include /etc/nginx/ssl/ssl-params.conf;# <--- Ignore this part if not using SSL
    include /etc/nginx/ssl/khophi.com.ssl;# <--- Ignore this part if not using SSL

    root /home/khophi/khophi.com/ssr/dist/browser; # <-- Notice where we're point to

   location / {
        try_files $uri $uri @backend; # <--- This looks for requests (statics i.e js/css/fonts)
                                      # in /ssr/dist/browser folder. If nothing found, calls @backend
    }

    location @backend {
        # NOTE THERE IS NO TRAILING SLASH AT THE END. NO TRAILING SLASH. NO SLASH. NO!
        proxy_pass http://ssr_khophi_nodejs; # <--- THIS DOES NOT HAVE A TRAILING '/'
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_http_version 1.1;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_cache_bypass $http_upgrade;
        proxy_redirect off;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

server {
    listen 80;
    server_name staging.khophi.com;
    return 301 https://$server_name$request_uri?;
}

I hope this helps you.

KhoPhi
  • 9,660
  • 17
  • 77
  • 128
  • Thanks for the answer, but I've to implement this on apache. I've figured out to how to prepare for server-side rendering. I've also written an article on Medium - https://blog.squareboat.com/how-to-implement-server-side-rendering-using-angular-4-5da10f4dcb61 – Saumya Rastogi Dec 19 '17 at 03:49
  • @SaumyaRastogi your blog is just about the implementation of server-side rendering. I couldn't find how you deployed it on the server? – Vivek Sinha Mar 28 '18 at 07:35
  • the client/end-user is not going to put "pm2 start path/to/dist/server.js --name name_of_process" on the terminal of server. How will the client load the app page just by entering a url? – Sunil Kumar Apr 18 '19 at 11:43
  • @SunilKumar If I understand, you want to run `pm2 start path/to/dist/server.js --name name_of_process` without using the terminal? If so, I don't know of any other means to get your app running through the URL. – KhoPhi Apr 19 '19 at 12:06
  • @KhoPhi Is it possible to deploy angular project on Sentora server? Plz tell me i need to know. – vidy Sep 25 '20 at 07:42
  • what is the solution to change port instead running in 4000 by default ? I tried with pm2 start path/to/dist/server.js --name name_of_process --port 4001 / pm2 start path/to/dist/server.js --name name_of_process -- --port 4001 this does not work – jamuna May 20 '21 at 06:16
-3

Ok, i'm sorry i miss read your question :).

First of all, Apache is no more required to serve your application. This is because node.js will serve it for you.

So if apache service is no required on your server, you should disable it for security questions and probably to avoid port conflict between apps.

Server rendering will required to modify your angular app. Let's start.

1) Go to your angular project and install those package:

npm i -S @angular/platform-server @angular/animations express

2) Open src/app/app.module.ts and modify the commented line below with your app name.

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'your-angular-app-name' }), // You just have to change this line
    FormsModule,
    HttpModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})

3) Now, we'll set the server in your app. For this, create the file app/src/app.server.module.ts and at the following code.

import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';

@NgModule({
imports: [
    ServerModule, // Load the servermodule
    AppModule     // Load the modules of AppModule
],
bootstrap: [AppComponent]
})
export class AppServerModule { }

4) Create the file src/server.ts and add the following code. This is the node server.

import 'reflect-metadata';
import 'zone.js/dist/zone-node';
import { platformServer, renderModuleFactory } from '@angular/platform-server';
import { enableProdMode } from '@angular/core';
import { AppServerModuleNgFactory } from '../dist/ngfactory/src/app/app.server.module.ngfactory';
import * as express from 'express';
import { readFileSync } from 'fs';
import { join } from 'path';
const PORT = 4000;
enableProdMode();
const app = express();
let template = readFileSync(join(__dirname, '..', 'dist', 'index.html')).toString();
app.engine('html', (_, options, callback) => {
  const opts = { document: template, url: options.req.url };
  renderModuleFactory(AppServerModuleNgFactory, opts)
    .then(html => callback(null, html));
});
app.set('view engine', 'html');
app.set('views', 'src');
app.get('*.*', express.static(join(__dirname, '..', 'dist')));
app.get('*', (req, res) => {
  res.render('index', { req });
});
app.listen(PORT, () => {
  console.log(`Listening on http://localhost:${PORT}...`);
});

5) Open src/tsconfig.app.json and add the file server.ts to the exclude json variable.

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "module": "es2015",
    "baseUrl": "",
    "types": []
  },
  "exclude": [
    "server.ts", # Just here !
    "test.ts",
    "**/*.spec.ts"
  ]
}

6) Open tsconfig.json locate at the root of your project and add the angularCompilerOptions like this:

{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "baseUrl": "src",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2016",
      "dom"
    ]
  },
  "angularCompilerOptions": { 
    "genDir": "./dist/ngfactory",
    "entryModule": "./src/app/app.module#AppModule"
  }  
}

7) Now, modify your package.json to make your life easier.

{
  "scripts": {
    "prestart": "ng build --prod && ngc",
    "start": "ts-node src/server.ts", 
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
}

8) Now you can test your app with:

npm start

I hope this will help you.

NOTE: If your project already exist, you'll probably have some problems with some modules like Angular Material because node.js doesn't know, window object, documents object.

So, you'll have to:

  • Create app.common.module.ts, whose the other module loading file will inherit. And gather common module (client+server).

  • Finally put the modules which annoying us in the app.module.ts .

Cdly.

  • 1
    Sorry, I don't think this answers my question. I am not asking to structure the project. The way you've talked above is the same way I'm implementing but my question is - how to serve that particular app on server? I want the implementation for that! – Saumya Rastogi Sep 25 '17 at 16:59
-5

no 7 package.jsno script has duplicate start script.

Also we need server support which does not included on a shared hosting account.

-6

Actually it's very simple.

Use a shell to go to the directory of your angular 4 project. and do this:

$ ng build --prod

This will compile the application and the result is in the dist folder at the root of your angular application.

Now you just have to put the content of the dist folder in a HTTP server and eat popcorn.

Cdly, Jerry Yong-busson.

  • 2
    I think actually you haven't read my question carefully. The solution which you've given, is already known to me as mentioned in my question. I want the solution for hosting the app with server-side rendering enabled... – Saumya Rastogi Sep 23 '17 at 07:57