Angular 8 中的动态渲染
Dynamic Rendering in Angular8
要求根据服务器中的配置动态呈现样式。
示例:
Path :/customer?customerId=1
<link rel="stylesheet" href="customer1.css">
/customer?customerId=2
<link rel="stylesheet" href="customer2.css>
我决定遵循 angular-通用方法,它帮助我通过查询服务器配置在服务器端呈现 html。
app.get('/customer:customerId', (req, res) => {
console.log("hello");
// console.log(pug)
res.render('index', { req, styleDet : 'customer1' });
});
styleDet
是应该注入到 index.html 的动态内容,但它不起作用。
我转向了另一种使用 pug 模板引擎的方法。
已在开发依赖项中安装 pug:
npm install --save pug
server.ts
import 'zone.js/dist/zone-node';
import * as express from 'express';
import * as pug from 'pug';
import {join} from 'path';
// 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, ngExpressEngine, provideModuleMap} = require('./dist/server/main');
// // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
// app.engine('pug', ngExpressEngine({
// bootstrap: AppServerModuleNgFactory,
// providers: [
// provideModuleMap(LAZY_MODULE_MAP)
// ]
// }));
app.set('view engine', 'pug');
app.set('views', 'src');
// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
app.get('*.*', express.static(DIST_FOLDER, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
app.get('*', (req, res) => {
console.log("hello");
// console.log(pug)
res.render('index', { req });
});
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node Express server listening on http://localhost:${PORT}`);
});
这是导致模块未找到的错误
Error: Cannot find module 'pug'
at webpackEmptyContext (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:17271:10)
at new View (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:17162:38)
at Function.render (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:12379:12)
at ServerResponse.render (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:24813:7)
at /Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:143:9
at Layer.handle [as handle_request] (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:15833:5)
at next (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:14754:13)
at Route.dispatch (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:14729:3)
at Layer.handle [as handle_request] (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:15833:5)
at /Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:14229:22
package.json
{
"name": "ssr",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"compile:server": "webpack --config webpack.server.config.js --progress --colors",
"serve:ssr": "node dist/server",
"build:ssr": "npm run build:client-and-server-bundles && npm run compile:server",
"build:client-and-server-bundles": "ng build --prod && ng run ssr:server:production --bundleDependencies all"
},
"private": true,
"dependencies": {
"@angular/animations": "~8.2.14",
"@angular/common": "~8.2.14",
"@angular/compiler": "~8.2.14",
"@angular/core": "~8.2.14",
"@angular/forms": "~8.2.14",
"@angular/platform-browser": "~8.2.14",
"@angular/platform-browser-dynamic": "~8.2.14",
"@angular/platform-server": "~8.2.14",
"@angular/router": "~8.2.14",
"@nguniversal/express-engine": "^8.2.6",
"@nguniversal/module-map-ngfactory-loader": "v8.2.6",
"@types/pug": "^2.0.4",
"express": "^4.15.2",
"pug": "^2.0.4",
"rxjs": "~6.4.0",
"tslib": "^1.10.0",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.803.24",
"@angular/cli": "~8.3.24",
"@angular/compiler-cli": "~8.2.14",
"@angular/language-service": "~8.2.14",
"@types/express": "^4.17.0",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "^5.0.1",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"nodemon": "^2.0.3",
"protractor": "~5.4.0",
"ts-loader": "^5.2.0",
"ts-node": "~7.0.0",
"tslint": "~5.15.0",
"typescript": "~3.5.3",
"webpack-cli": "^3.1.0"
}
}
请帮助我解决这个问题或建议我任何其他更可行的方法。
使用 encapsulation: ViewEncapsulation.None
创建一个 ThemeComponent
并将此组件中的所有样式视为全局样式。然后,您可以将此组件放在应用程序的任何位置,并使用 *ngIf
有条件地应用这些样式。为每组要动态更改的不同样式创建不同的 ThemeComponent
。
如果您不介意在构建中包含样式,您可以将不同的样式添加到 styles.scss
文件中。
styles.scss
//common rules go here
//...
//customer specific rules below
body.customer1{
// ...rules for customer 1
}
body.customer2{
// ...rules for customer 2
}
然后,在您的应用程序组件或您认识客户的任何组件中,将相应的 class 动态添加到 body 元素。
component.ts
import {DOCUMENT} from "@angular/common";
import {Renderer2} from '@angular/core';
constructor(@Inject(DOCUMENT) private document: any, private renderer: Renderer2)
{
}
//add this when you subscribe to route change, or ngOnInit
this.renderer.addClass(this.document.body, 'customer1');//or customer2
备选
您也可以根据当前客户直接在您的组件中添加正确的css link。但是,使用这种方法,我认为 css 不会在您加载页面时内联,因此显示可能会慢一点
const link = this.renderer.createElement('link');
this.renderer.setAttribute(link, 'rel', 'stylesheet');
this.renderer.setAttribute(link, 'href', 'customer1.css');
this.renderer.appendChild(this.document.head, link);
要求根据服务器中的配置动态呈现样式。
示例:
Path :/customer?customerId=1
<link rel="stylesheet" href="customer1.css">
/customer?customerId=2
<link rel="stylesheet" href="customer2.css>
我决定遵循 angular-通用方法,它帮助我通过查询服务器配置在服务器端呈现 html。
app.get('/customer:customerId', (req, res) => {
console.log("hello");
// console.log(pug)
res.render('index', { req, styleDet : 'customer1' });
});
styleDet
是应该注入到 index.html 的动态内容,但它不起作用。
我转向了另一种使用 pug 模板引擎的方法。
已在开发依赖项中安装 pug:
npm install --save pug
server.ts
import 'zone.js/dist/zone-node';
import * as express from 'express';
import * as pug from 'pug';
import {join} from 'path';
// 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, ngExpressEngine, provideModuleMap} = require('./dist/server/main');
// // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
// app.engine('pug', ngExpressEngine({
// bootstrap: AppServerModuleNgFactory,
// providers: [
// provideModuleMap(LAZY_MODULE_MAP)
// ]
// }));
app.set('view engine', 'pug');
app.set('views', 'src');
// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
app.get('*.*', express.static(DIST_FOLDER, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
app.get('*', (req, res) => {
console.log("hello");
// console.log(pug)
res.render('index', { req });
});
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node Express server listening on http://localhost:${PORT}`);
});
这是导致模块未找到的错误
Error: Cannot find module 'pug'
at webpackEmptyContext (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:17271:10)
at new View (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:17162:38)
at Function.render (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:12379:12)
at ServerResponse.render (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:24813:7)
at /Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:143:9
at Layer.handle [as handle_request] (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:15833:5)
at next (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:14754:13)
at Route.dispatch (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:14729:3)
at Layer.handle [as handle_request] (/Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:15833:5)
at /Users/boopathi/Documents/Projects/Angular-Universal/ssr/dist/server.js:14229:22
package.json
{
"name": "ssr",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"compile:server": "webpack --config webpack.server.config.js --progress --colors",
"serve:ssr": "node dist/server",
"build:ssr": "npm run build:client-and-server-bundles && npm run compile:server",
"build:client-and-server-bundles": "ng build --prod && ng run ssr:server:production --bundleDependencies all"
},
"private": true,
"dependencies": {
"@angular/animations": "~8.2.14",
"@angular/common": "~8.2.14",
"@angular/compiler": "~8.2.14",
"@angular/core": "~8.2.14",
"@angular/forms": "~8.2.14",
"@angular/platform-browser": "~8.2.14",
"@angular/platform-browser-dynamic": "~8.2.14",
"@angular/platform-server": "~8.2.14",
"@angular/router": "~8.2.14",
"@nguniversal/express-engine": "^8.2.6",
"@nguniversal/module-map-ngfactory-loader": "v8.2.6",
"@types/pug": "^2.0.4",
"express": "^4.15.2",
"pug": "^2.0.4",
"rxjs": "~6.4.0",
"tslib": "^1.10.0",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.803.24",
"@angular/cli": "~8.3.24",
"@angular/compiler-cli": "~8.2.14",
"@angular/language-service": "~8.2.14",
"@types/express": "^4.17.0",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "^5.0.1",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"nodemon": "^2.0.3",
"protractor": "~5.4.0",
"ts-loader": "^5.2.0",
"ts-node": "~7.0.0",
"tslint": "~5.15.0",
"typescript": "~3.5.3",
"webpack-cli": "^3.1.0"
}
}
请帮助我解决这个问题或建议我任何其他更可行的方法。
使用 encapsulation: ViewEncapsulation.None
创建一个 ThemeComponent
并将此组件中的所有样式视为全局样式。然后,您可以将此组件放在应用程序的任何位置,并使用 *ngIf
有条件地应用这些样式。为每组要动态更改的不同样式创建不同的 ThemeComponent
。
如果您不介意在构建中包含样式,您可以将不同的样式添加到 styles.scss
文件中。
styles.scss
//common rules go here
//...
//customer specific rules below
body.customer1{
// ...rules for customer 1
}
body.customer2{
// ...rules for customer 2
}
然后,在您的应用程序组件或您认识客户的任何组件中,将相应的 class 动态添加到 body 元素。
component.ts
import {DOCUMENT} from "@angular/common";
import {Renderer2} from '@angular/core';
constructor(@Inject(DOCUMENT) private document: any, private renderer: Renderer2)
{
}
//add this when you subscribe to route change, or ngOnInit
this.renderer.addClass(this.document.body, 'customer1');//or customer2
备选
您也可以根据当前客户直接在您的组件中添加正确的css link。但是,使用这种方法,我认为 css 不会在您加载页面时内联,因此显示可能会慢一点
const link = this.renderer.createElement('link');
this.renderer.setAttribute(link, 'rel', 'stylesheet');
this.renderer.setAttribute(link, 'href', 'customer1.css');
this.renderer.appendChild(this.document.head, link);