-
Notifications
You must be signed in to change notification settings - Fork 197
Open
Description
Hi
When we prerender the angular repo, we always get below error message:
NullInjectorError: R3InjectorError(AppServerModule)[ApplicationModule -> ApplicationRef -> ApplicationInitStatus -> InjectionToken Application Initializer -> [object Object] -> TranslatesService -> InjectionToken REQUEST -> InjectionToken REQUEST -> InjectionToken REQUEST]:
NullInjectorError: No provider for InjectionToken REQUEST!
those are our pretender and translate service files
prerenter.ts
import { environment } from './src/environments/environment';
// for debug
require('source-map-support').install();
const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs.readFileSync(path.join(__dirname, '.', 'dist', 'index.html')).toString();
const win = domino.createWindow(template);
const files = fs.readdirSync(`${process.cwd()}/dist-server`);
global['window'] = win;
Object.defineProperty(win.document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true,
};
},
});
global['document'] = win.document;
global['CSS'] = null;
// global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
global['Prism'] = null;
// Load zone.js for the server.
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
import { join } from 'path';
import { enableProdMode } from '@angular/core';
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();
// Express Engine
import { ngExpressEngine } from '@nguniversal/express-engine';
// Import module map for lazy loading
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
import { renderModuleFactory } from '@angular/platform-server';
import { ROUTES } from './static.paths';
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const mainFiles = files.filter((file) => file.startsWith('main'));
const hash = mainFiles[0].split('.')[1];
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require(`./dist-server/main.${hash}`);
import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';
import { NgxRequest, NgxResponce } from '@gorniv/ngx-universal';
const BROWSER_FOLDER = join(process.cwd(), 'static');
// Load the index.html file containing referances to your application bundle.
const index = readFileSync(join('dist', 'index.html'), 'utf8');
let previousRender = Promise.resolve();
// Iterate each route path
ROUTES.forEach((route) => {
const fullPath = join(BROWSER_FOLDER, route);
// Make sure the directory structure is there
if (!existsSync(fullPath)) {
let syncpath = BROWSER_FOLDER;
route.split('/').forEach((element) => {
syncpath = join(syncpath, element);
if (!existsSync(syncpath)) {
mkdirSync(syncpath);
}
});
}
// Writes rendered HTML to index.html, replacing the file if it already exists.
previousRender = previousRender
.then((_) =>
renderModuleFactory(AppServerModuleNgFactory, {
document: index,
url: route,
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP),
{
provide: REQUEST,
useValue: { cookie: '', headers: {} },
},
{
provide: RESPONSE,
useValue: {},
},
{
provide: NgxRequest,
useValue: { cookie: '', headers: {} },
},
{
provide: NgxResponce,
useValue: {},
},
{
provide: 'ORIGIN_URL',
useValue: environment.host,
},
],
}),
)
.then((html) => writeFileSync(join(fullPath, 'index.html'), html));
});
translatesservice.ts
import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
import { DOCUMENT, isPlatformBrowser, isPlatformServer } from '@angular/common';
import { REQUEST } from '@nguniversal/express-engine/tokens';
import {
TranslateService as NGXTranslateService,
MissingTranslationHandler,
MissingTranslationHandlerParams
} from '@ngx-translate/core';
import { MetaService } from '@ngx-meta/core';
import { Observable, of } from 'rxjs';
import { ILang } from './translates.interface';
import { UniversalStorage } from '@shared/storage/universal.storage';
const LANG_LIST: ILang[] = [
{
code: 'en',
name: 'English',
culture: 'en-US'
},
{
code: 'ru',
name: 'Русский',
culture: 'ru-RU'
}
];
const LANG_DEFAULT: ILang = LANG_LIST[0];
const STORAGE_LANG_NAME: string = 'langCode';
@Injectable()
export class TranslatesService {
constructor(
@Inject(PLATFORM_ID) private _platformId: Object,
@Inject(DOCUMENT) private _document: any,
@Inject(REQUEST) private _request: any,
@Inject(NGXTranslateService) private _translate: NGXTranslateService,
@Inject(MetaService) private _meta: MetaService,
@Inject(REQUEST) private _req: any,
@Inject(UniversalStorage) private _appStorage: Storage
) { }
public initLanguage(): Promise<any> {
return new Promise((resolve: Function) => {
this._translate.addLangs(LANG_LIST.map((lang: ILang) => lang.code));
const language: ILang = this._getLanguage();
if (language) {
this._translate.setDefaultLang(language.code);
} else {
this._translate.setDefaultLang(LANG_DEFAULT.code);
}
this._setLanguage(language);
resolve();
});
}
private _getLanguage(): ILang {
// fix init cookie
this._req.cookie = this._req.headers['cookie'];
let language: ILang = this._getFindLang(this._appStorage.getItem(STORAGE_LANG_NAME));
if (language) {
return language;
}
if (isPlatformBrowser(this._platformId)) {
language = this._getFindLang(this._translate.getBrowserLang());
}
if (isPlatformServer(this._platformId)) {
try {
const reqLangList: string[] = this._request.headers['accept-language'].split(';')[0].split(',');
language = LANG_LIST.find(
(lang: ILang) => reqLangList.indexOf(lang.code) !== -1 || reqLangList.indexOf(lang.culture) !== -1
);
} catch (err) {
language = LANG_DEFAULT;
}
}
language = language || LANG_DEFAULT;
this._appStorage.setItem(STORAGE_LANG_NAME, language.code);
return language;
}
private _getFindLang(code: string): ILang | null {
return code ? LANG_LIST.find((lang: ILang) => lang.code === code) : null;
}
private _setLanguage(lang: ILang): void {
this._translate.use(lang.code).subscribe(() => {
this._meta.setTag('og:locale', lang.culture);
this._document.documentElement.lang = lang.code;
});
}
public changeLang(code: string): void {
const lang: ILang = this._getFindLang(code);
if (!lang || lang.code === this._translate.currentLang) {
return;
}
this._appStorage.setItem(STORAGE_LANG_NAME, lang.code);
this._setLanguage(lang);
}
public getLangList(): Observable<ILang[]> {
return of(LANG_LIST);
}
public getCurrentLang(): string {
return this._translate.currentLang;
}
}
export class CommonMissingTranslationHandler implements MissingTranslationHandler {
handle(params: MissingTranslationHandlerParams) {
if (
params.key.match(/\w+\.\w+/) &&
params.translateService.translations['ru'] &&
!params.translateService.translations['ru'][params.key]
) {
console.warn(`Нехватает перевода для "${params.key}"`);
}
return params.key;
}
}
Could you help ?
Metadata
Metadata
Assignees
Labels
No labels