I have a problem with a SPA page. I'm using SSR but my index.html (when i show sourcecode [Crtl+U]) don't show my title and meta description updates when i go to another component, because index is always pre-rendered in server, and i need this new data in source code.
Also i need to show in sourcecode, the code of the next component beyond index.html.
Is possible?
server.ts
(global as any).WebSocket = require('ws');
(global as any).XMLHttpRequest = require('xhr2');
import 'zone.js/dist/zone-node';
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';
import * as cookieParser from 'cookie-parser';
// 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/singapur-frontend-web');
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');
app.use( cookieParser() );
// 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);
// app.get('/', (req, res, next) => {
// const cookie = req.cookies;
// for (const prop in cookie) {
// if (!cookie.hasOwnProperty(prop)) {
// continue;
// }
// res.cookie(prop, '', { expires: new Date( 0 ) });
// }
// next();
// });
app.get('*.well-known/**', ( req, res ) => {
res.sendFile( join( DIST_FOLDER, '/.well-known/assetlinks.json' ) );
});
// Serve static files from /browser
app.get('*.*', express.static(DIST_FOLDER, {
maxAge: '1y'
}));
app.get(['/chat/**', '/profile'], (req, res) => {
res.sendFile(join(DIST_FOLDER, 'index.html'));
});
// All regular routes use the Universal engine
app.get('*', (req, res) => {
res.render('index', {
req,
res,
providers: [
{
provide: 'REQUEST',
useValue: (req)
},
{
provide: 'RESPONSE',
useValue: (res)
}
]
});
});
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node Express server listening on http://localhost:${PORT}`);
});
package.json
{
"name": "-------------------",
"version": "0.0.2-SNAPSHOT",
"scripts": {
"ng": "ng",
"start": "npm run serve:ssr",
"start:local": "ng serve",
"build": "ng build",
"build:qa": "ng build -c qa",
"build:pre": "ng build -c pre",
"build:pro": "ng build --prod",
"deploy:qa": "npm run build:qa && npm run build:ssr && gcloud app deploy qa.app.yaml",
"deploy:pre": "npm run build:pre && npm run build:ssr && gcloud app deploy",
"deploy:pro": "npm run build:pro && npm run build:ssr && gcloud app deploy",
"docker:build:prod": "cd docker && docker-compose build --build-arg app_env=production && npm run docker:export",
"docker:build:pre": "cd docker && docker-compose build --build-arg app_env=pre && npm run docker:export",
"docker:build:qa": "cd docker && docker-compose build --build-arg app_env=qa && npm run docker:export",
"docker:export": "docker export leroy_merlin > docker/container.tgz",
"test": "ng test --browsers=Chrome",
"test:ci": "ng test --no-watch --no-progress --browsers=PhantomJS",
"lint": "ng lint",
"e2e": "ng e2e",
"build:ssr": "ng run frontend-web:server:production && npm run compile:server",
"compile:server": "webpack --config webpack.server.config.js --progress --colors",
"serve:ssr": "node dist/server"
},
"publishConfig": {
"registry": "-----------------------"
},
"dependencies": {
"@angular/animations": "^7.2.13",
"@angular/cdk": "^7.3.7",
"@angular/common": "^7.2.13",
"@angular/compiler": "^7.2.13",
"@angular/core": "^7.2.13",
"@angular/fire": "^5.2.1",
"@angular/flex-layout": "^7.0.0-beta.24",
"@angular/forms": "^7.2.13",
"@angular/http": "^7.2.13",
"@angular/material": "^7.3.7",
"@angular/platform-browser": "^7.2.13",
"@angular/platform-browser-dynamic": "^7.2.13",
"@angular/platform-server": "^7.2.13",
"@angular/router": "^7.2.13",
"@ngrx/effects": "^7.4.0",
"@ngrx/router-store": "^7.4.0",
"@ngrx/store": "^7.4.0",
"@ngrx/store-devtools": "^7.4.0",
"@nguniversal/common": "^8.1.1",
"@nguniversal/express-engine": "^7.1.1",
"@nguniversal/module-map-ngfactory-loader": "0.0.0",
"@ngx-translate/core": "^11.0.1",
"@ngx-translate/http-loader": "^4.0.0",
"@nicky-lenaers/ngx-scroll-to": "^2.0.0",
"@singapur/add-credit-card": "^1.0.166",
"@singapur/alerts": "^1.0.166",
"@singapur/autocomplete": "^1.0.166",
"@singapur/banner": "^1.0.166",
"@singapur/block-services": "^1.0.166",
"@singapur/block-text-image": "^1.0.166",
"@singapur/breadcrumb": "^1.0.166",
"@singapur/calculator": "^1.0.166",
"@singapur/card-add-item": "^1.0.166",
"@singapur/card-configurator-service": "^1.0.166",
"@singapur/card-container": "^1.0.166",
"@singapur/card-description": "^1.0.166",
"@singapur/card-img": "^1.0.166",
"@singapur/card-img-opinion": "^1.0.166",
"@singapur/card-opinion": "^1.0.166",
"@singapur/card-prof": "^1.0.166",
"@singapur/card-profile-detail": "^1.0.166",
"@singapur/card-static": "^1.0.166",
"@singapur/card-tabs": "^1.0.166",
"@singapur/card-title": "^1.0.166",
"@singapur/chat": "^1.0.166",
"@singapur/cookies": "^1.0.166",
"@singapur/dialog": "^1.0.166",
"@singapur/footer": "^1.0.166",
"@singapur/grid": "^1.0.166",
"@singapur/header": "^1.0.166",
"@singapur/includes-excludes": "^1.0.166",
"@singapur/input-password": "^1.0.166",
"@singapur/menu-lateral": "^1.0.166",
"@singapur/opinion-module": "^1.0.166",
"@singapur/professionals": "^1.0.166",
"@singapur/sass": "^1.0.166",
"@singapur/spinner": "^1.0.166",
"@singapur/stepper": "^1.0.166",
"angular-star-rating": "^4.0.0-beta.3",
"cache": "^2.1.0",
"classlist.js": "^1.1.20150312",
"core-js": "^2.5.4",
"css-star-rating": "^1.2.4",
"express": "^4.15.2",
"firebase": "^6.2.0",
"hammerjs": "^2.0.8",
"lodash": "^4.17.11",
"moment": "^2.24.0",
"ngx-indexed-db": "^2.0.8",
"ngx-page-scroll": "^6.0.0-beta.1",
"ngx-page-scroll-core": "^6.0.0-beta.1",
"ngx-universal-cookies": "^8.0.1",
"rxjs": "^6.4.0",
"rxjs-compat": "^6.4.0",
"verify": "^0.1.2",
"web-animations-js": "^2.3.1",
"zone.js": "^0.9.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^0.13.8",
"@angular/cli": "^7.3.8",
"@angular/compiler-cli": "^7.2.13",
"@angular/language-service": "^7.2.13",
"@types/jasmine": "^3.3.12",
"@types/jasminewd2": "~2.0.3",
"@types/node": "^11.13.20",
"bufferutil": "^4.0.1",
"codelyzer": "^5.0.0",
"cookie-parser": "^1.4.4",
"express": "^4.16.4",
"jasmine-core": "^3.4.0",
"jasmine-spec-reporter": "^4.2.1",
"karma": "^4.1.0",
"karma-chrome-launcher": "^2.2.0",
"karma-cli": "^2.0.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "^2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"karma-phantomjs-launcher": "^1.0.4",
"karma-sonarqube-unit-reporter": "0.0.18",
"morgan": "^1.9.1",
"node-sass": "^4.12.0",
"phantomjs-prebuilt": "^2.1.16",
"protractor": "^5.4.2",
"sass-rem": "^2.0.1",
"ts-loader": "^5.2.0",
"ts-node": "~7.0.0",
"tslint": "^5.16.0",
"tslint-sonarts": "^1.9.0",
"typescript": "~3.2.2",
"utf-8-validate": "^5.0.2",
"webpack-cli": "^3.1.0",
"ws": "^7.1.2",
"xhr2": "^0.2.0"
}
}