当我尝试使用PlatformRef::bootstrapModule(...)
渲染Angular模块时,出现错误:
ReferenceError:未定义文档
很显然,Angular尝试使用document
in Node.js environment where it's not present(因为它不是浏览器环境)。
如何解决此问题?
@Injectable()
export class MyDomRendererFactory2 implements RendererFactory2 {
private renderer: MyRenderer;
constructor(eventManager: EventManager) {
this.renderer = new MyRenderer(eventManager);
}
createRenderer(hostElement: any, type: RendererType2): Renderer2 {
return this.renderer;
}
begin?(): void { throw new Error("Method not implemented."); }
end?(): void { throw new Error("Method not implemented."); }
whenRenderingDone?(): Promise<any> { throw new Error("Method not implemented."); }
}
async function generate<M>(moduleType: Type<M>) {
try {
const extraProviders: StaticProvider[] = [
{ provide: Compiler, useFactory: compilerFactory => compilerFactory.createCompiler(), deps: [CompilerFactory] },
];
const platformRef = platformDynamicServer(extraProviders);
const moduleRef = await platformRef
.bootstrapModule(
moduleType,
{
providers: [
{ provide: ResourceLoader, useValue: new ResourceLoaderImpl(`src\\app`), deps: [ ] },
{
provide: RendererFactory2,
useClass: MyDomRendererFactory2,
deps: [EventManager],
},
],
});
const appComponent = moduleRef.injector.get(AppComponent);
console.info(appComponent.title.toString());
} catch (error) {
throw new Error(error.toString());
}
}
在这一点上,它基本上什么也不做。
@Injectable()
export class MyRenderer implements Renderer2 {
data: { [key: string]: any; };
destroy(): void { }
createElement(name: string, namespace?: string) { }
createComment(value: string) { }
createText(value: string) { }
destroyNode: (node: any) => void;
appendChild(parent: any, newChild: any): void { }
insertBefore(parent: any, newChild: any, refChild: any): void { }
removeChild(parent: any, oldChild: any): void { }
selectRootElement(selectorOrNode: any) { }
parentNode(node: any) { }
nextSibling(node: any) { }
setAttribute(el: any, name: string, value: string, namespace?: string): void { }
removeAttribute(el: any, name: string, namespace?: string): void { }
addClass(el: any, name: string): void { }
removeClass(el: any, name: string): void { }
setStyle(el: any, style: string, value: any, flags?: RendererStyleFlags2): void { }
removeStyle(el: any, style: string, flags?: RendererStyleFlags2): void { }
setProperty(el: any, name: string, value: any): void { }
setValue(node: any, value: string): void { }
listen(target: any, eventName: string, callback: (event: any) => boolean | void): () => void { return null; }
constructor(private eventManager: EventManager) {}
}
通过“ url”(实际上不是URL)猜测源文件,并读取文件的所有文本。
@Injectable()
export class ResourceLoaderImpl extends ResourceLoader {
constructor(private _cwd: string) {
super();
}
get(resourceFileName: string): Promise<string> {
return new Promise<string>((resolve, reject) => {
glob(`**/${resourceFileName}`, { cwd: this._cwd, }, (globError, matches) => {
if (globError) reject(globError.toString());
else
readFile(path.join(this._cwd, matches[0]), (readFileError, data) => {
if (readFileError) reject(readFileError);
else resolve(data.toString());
});
});
});
}
}
import { ResourceLoader } from '@angular/compiler';
import { Compiler, CompilerFactory, Injectable, Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2, StaticProvider, Type } from '@angular/core';
import { EventManager } from '@angular/platform-browser';
import { platformDynamicServer } from '@angular/platform-server';
import { readFile } from 'fs';
import * as glob from 'glob';
import * as path from 'path';
import 'zone.js';
import 'zone.js/dist/long-stack-trace-zone.js';
import { AppComponent } from './app/app.component';
import { AppModule } from './app/app.module';
我还尝试提供像这样的custom document
object:
import { JSDOM } from 'jsdom';
const jsdom = new JSDOM(`<html></html>`);
export function document() { return jsdom.window.document; }
通过在DI中注册它:
{ provide: DOCUMENT, useFactory: document, deps: [] }
仍然出现相同的ReferenceError: document is not defined
错误。
我的问题的根源是RendererFactory2
无法解析为MyDomRendererFactory2
。相反,使用了标准的NgModule的DomRendererFactory2
...这是我在调试过程中在providers
中观察到的:
答案 0 :(得分:0)
如果您使用的是服务器端,则必须添加该平台是浏览器还是服务器,因为服务器端支持中不提供文档,窗口之类的关键字
您可以从角度使用isPlatformBrowser。 https://angular.io/api/common/isPlatformBrowser