简体   繁体   中英

Angular SSR is not working in docker NGINX

I added angualr universal to my app.

When I run commands:

npm run build:ssr
npm run serve:ssr

SSR rendering works fine.

But when I run my app in docker SSR isn't work I see only my static index.html in page source.

This is my server.ts:

import 'zone.js/dist/zone-node';

import {APP_BASE_HREF} from '@angular/common';
import {ngExpressEngine} from '@nguniversal/express-engine';
import * as express from 'express';
import {existsSync} from 'fs';
import {join} from 'path';

import {AppServerModule} from './src/main.server';
const compression = require('compression');

// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
  const server = express();
  const distFolder = join(process.cwd(), 'dist/my-app-frontend/browser');
  const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';

  server.use(compression());

  // Our Universal express-engine (found @ https://github.com/angular/universal/tree/main/modules/express-engine)
  server.engine('html', ngExpressEngine({
    bootstrap: AppServerModule,
  }));

  server.set('view engine', 'html');
  server.set('views', distFolder);

  // Example Express Rest API endpoints
  // server.get('/api/**', (req, res) => { });
  // 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;
}

function run(): void {
  const port = process.env['PORT'] || 4200;

  // Start up the Node server
  const server = app();
  server.listen(port, () => {
    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';

This is my Dockerfile :

    FROM node:16.17.0-alpine3.16 AS node
    
    WORKDIR /frontend
    
    COPY package*.json ./
    
    RUN npm install
    
    COPY . .
    
    RUN npm run build:ssr

This is my docker-compose.yml :

version: '3'
    
...
    
  frontend:
    container_name: my-app-docker-frontend
    build: ./frontend
    restart: unless-stopped
    command: npm run serve:ssr
    networks:
      - my-app-docker-network

  nginx:
    image: nginx:stable
    container_name: my-app-docker-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./data/nginx:/etc/nginx/conf.d
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    depends_on:
      - frontend
      - backend
    networks:
      - my-app-docker-network
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"


volumes:
  my-app-docker-db: { }

networks:
  my-app-docker-network:
    driver: bridge

This is my app.conf :

server {
  gzip on;
  gzip_static on;
  gzip_types      text/plain application/xml;
  gzip_proxied    no-cache no-store private expired auth;
  gzip_min_length 1000;

  listen 80;
  server_name mysite.com;
  server_tokens off;

    location / {
      proxy_pass  http://frontend:4200;
      proxy_set_header    Host                $http_host;
      proxy_set_header    X-Real-IP           $remote_addr;
      proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
    }

    location /api {
      proxy_pass http://backend:8080;
      rewrite ^/api/(.*) /$1 break;
    }
}

I spend two days to solve this problem, any help will usefull.

It looks like your post is mostly code; please add some more details.

I fixed my problem.

My app worked fine, exept that SSR wasn't work. I aded request intersepter and realized that I was getting error:

Http failure response for (unknown url): 0 Unknown Error

But everything work fine. I started googling and found this post:

https://github.com/angular/angular/issues/20738#issuecomment-415740935

Author had problem with localhost and docker. I am not using localhost in my project so i just replace serverUrl in my environment.prod.ts file.

Before was just api i replase with full url https://myapp.com/api and SSR started working. Also the error: Http failure response for (unknown url): 0 Unknown Error went away.

This was easy fix, but spend 4 days to find it. The main couse of error was thay I used relative url instead of absolute.

as angular manual said:

The tutorial's HeroService and HeroSearchService delegate to the Angular HttpClient module to fetch application data. These services send requests to relative URLs such as api/heroes. In a server-side rendered app, HTTP URLs must be absolute (for example, https://my-server.com/api/heroes). This means that the URLs must be somehow converted to absolute when running on the server and be left relative when running in the browser.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM