是否可以根据条件导入模块?仅当角度2通用应用程序在浏览器中呈现而不在服务器中呈现时,才特定导入外部模块。
此问题与某些PrimeNG模块相关,这些模块依赖于浏览器功能,只能在浏览器中呈现。在服务器渲染中省略它们会很棒,因为日历和其他组件对SEO来说并不重要。
目前,如果关闭服务器渲染,我可以渲染Calendar组件。但服务器会产生错误' ReferenceError:事件未定义'当我在app.module.ts中包含以下代码并打开服务器渲染时,在button.js中。
import { CalendarModule } from 'primeng/components/calendar/calendar';
@NgModule({
...
imports: [
...,
CalendarModule
]
})

有角度提供了一个isBrowser条件。
import { isBrowser } from 'angular2-universal';

但我不知道如何将它用于条件导入。有没有办法为模块做到这一点?
答案 0 :(得分:5)
因此,有一种方法可以在浏览器中呈现PrimeNG组件,并在服务器呈现时省略它们。这些问题帮助我开始挖掘正确的方向:
angular-cli: Conditional Imports using an environment variable
How can I conditionally import an ES6 module?
虽然服务器渲染我使用了渲染简单输入字段并使用相同选择器'p-calendar'的模拟组件。我在app.module中得到的最终代码。
...//other imports
import { isBrowser } from 'angular2-universal';
let imports = [
... //your modules here
];
let declarations = [
... //your declarations here
];
if (isBrowser) {
let CalendarModule = require('primeng/components/calendar/calendar').CalendarModule;
imports.push(CalendarModule);
}
else {
let CalendarMockComponent = require('./components/primeng/calendarmock.component').CalendarMockComponent;
declarations.push(CalendarMockComponent);
}
@NgModule({
bootstrap: [AppComponent],
declarations: declarations,
providers: [
... //your providers here
],
imports: imports
})
要使模拟组件支持[(ngModel)]绑定,请使用本教程。 http://almerosteyn.com/2016/04/linkup-custom-control-to-ngcontrol-ngmodel
import { Component, forwardRef } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CalendarMockComponent),
multi: true
};
@Component({
selector: 'p-calendar',
template: '<input type="text" class="form-control"/>',
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
})
export class CalendarMockComponent implements ControlValueAccessor {
private innerValue: any = '';
private onTouchedCallback: () => void = () => {};
private onChangeCallback: (_: any) => void = () => {};
//From ControlValueAccessor interface
writeValue(value: any) {
if (value !== this.innerValue) {
this.innerValue = value;
}
}
registerOnChange(fn: any) {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any) {
this.onTouchedCallback = fn;
}
}
答案 1 :(得分:1)
不需要动态脚本加载的模块导入的替代解决方案:您可以使用服务器应用程序的compilerOptions.paths
文件中的tsconfig.json
选项将导入的模块重定向到仅服务器版本:< / p>
{
...
"compilerOptions": {
...
"paths": {
"path/to/browser/module": "path/to/server/module"
}
}
}
当构建服务器应用程序时,编译器将导入服务器模块而不是浏览器模块。
答案 2 :(得分:-1)
我也想回答。这是我的解决方案。 您需要在此处创建三个环境:
src/environments/server/environments.ts
src/environments/browser/environments.ts
src/environments/environments.ts
然后在构建部分的 angular.json 中为浏览器欺骗文件:
"configurations": {
"dev": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/browser/environment.ts"
}
]
},
"production": {
...
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/browser/environment.ts"
}
]
}
}
以及服务器:
"configurations": {
"dev": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/server/environment.ts"
}
]
},
"production": {
...
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/server/environment.ts"
}
]
}
}
因此我们可以使用变量 environment.isServer
import { environment } from '../../environments/environment';
...
environment.isServer ? MapMockModule : MapModule,
如果不清楚,您可以在sourse
上查看示例