Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server side rendering #144

Open
ghost opened this issue Oct 29, 2018 · 1 comment
Open

Server side rendering #144

ghost opened this issue Oct 29, 2018 · 1 comment
Milestone

Comments

@ghost
Copy link

ghost commented Oct 29, 2018

Hi there,

I'm struggling to impelement the localize-router package with an Angular Universal set-up (with the most recent version of Angular 6). When I just try to implement the server-side intialization suggestions in the app module I'm running into the following issue

error TS2304: Cannot find name 'require'.

The working example that is mentioned in the documentation is working with quite an outdated version of Angular (2 and the RC of universal). When I am trying to build this, I am running into the following issue:

Local workspace file ('angular.json') could not be found.

Then I tried to copy the solution design as in the working example and impelemented it in my own project, with the following files:

  • index.ts
  • app.node.modules
  • server.ts adjusted
  • server.routes.ts

But still I'm running into issues:

src/app/app.node.module.ts(23,10): error TS2304: Cannot find name 'require'.
src/app/app.node.module.ts(58,10): error TS2554: Expected 3 arguments, but got 2.
src/app/app.node.module.ts(88,7): error TS2345: Argument of type '{ provide: typeof LocalizeParser; useFactory: (translate: TranslateService, location: Location) =...' is not assignable to parameter of type 'LocalizeRouterConfig'.
Object literal may only specify known properties, and 'provide' does not exist in type 'LocalizeRouterConfig'.

Can someone maybe update the working example to a newer angular version or maybe describe in more detail which steps should be taken to let the localize-router package work well with Angular Universal/server-side rendering?

Thanks in advance!

@meeroslav meeroslav added this to the Version 2 milestone Nov 5, 2018
@ghost
Copy link
Author

ghost commented Nov 5, 2018

Hi @meeroslav. Last week I tried a lot of steps to solve the problem. The status of my solution now is:

  • Client side the package is working excellent
  • Server side (when I disable javascript in my browser) it doesn't work, I get a blank page

With the appRoutes mentioned beneath I get the following:

undefined 'this is the routing'
[ { children: [ [Object], [Object], [Object], [Object], [Object] ],
    path: 'nl' },
  { path: '', redirectTo: 'nl', pathMatch: 'full' },
  { path: '**', redirectTo: '', pathMatch: 'full' } ] 'this is the routing'

So it looks like the routing is undefined the first time (server-side).
Would be awesome if you have suggestions to fix this.

What I tried for now

  1. I added a working translateloader, browser and server according to this solution:

translate-server-loader.service.ts

import { Observable } from 'rxjs/Observable';
import { TranslateLoader } from '@ngx-translate/core';
import { makeStateKey, StateKey, TransferState } from '@angular/platform-browser';

declare var require: any;
const fs = require('fs');

export class TranslateServerLoader implements TranslateLoader {

    constructor(private transferState: TransferState) {
    }

    public getTranslation(lang: string): Observable<any> {

        return Observable.create(observer => {
            // const assets_folder = join(proc.cwd(), 'dist', 'server', this.prefix);
            const jsonData = JSON.parse(fs.readFileSync(`dist/******/assets/locales/${lang}.json`, 'utf8'));

            // Here we save the translations in the transfer-state
            const key: StateKey<number> = makeStateKey<number>('transfer-translate-' + lang);
            this.transferState.set(key, jsonData);

            observer.next(jsonData);
            observer.complete();
        });
    }
}

translate-browser-loader.service.ts

import { Observable } from 'rxjs/Observable';
import { TranslateLoader } from '@ngx-translate/core';

import { makeStateKey, StateKey, TransferState } from '@angular/platform-browser';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { HttpClient } from '@angular/common/http';

export class TranslateBrowserLoader implements TranslateLoader {

    constructor(private transferState: TransferState,
        private http: HttpClient) {
    }

    public getTranslation(lang: string): Observable<any> {

        const key: StateKey<number> = makeStateKey<number>('transfer-translate-' + lang);
        const data = this.transferState.get(key, null);

        // First we are looking for the translations in transfer-state, if none found, http load as fallback
        if (data) {
            return Observable.create(observer => {
                observer.next(data);
                observer.complete();
            });
        } else {
            return new TranslateHttpLoader(this.http, './assets/locales/', '.json').getTranslation(lang);
        }
    }
}

  1. Based on the documentation provided at the package and the solution above I implemented a server loader:
import { LocalizeParser } from 'localize-router';

declare var require: any;

import { Routes } from '@angular/router';
const fs = require('fs');

export class LocalizeServerLoader extends LocalizeParser {

    public load(routes: Routes): Promise<any> {

        return new Promise((resolve: any) => {
            const data = JSON.parse(fs.readFileSync('dist/**************/assets/locales.json', 'utf8'));

            this.locales = data.locales;
            this.prefix = data.prefix;

            console.log(this.routes, 'this is the routing');

            this.init(routes).then(resolve);
        });

    }
}
  1. In my server module I have the following:

app.server.module

    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: translateFactory,
        deps: [TransferState]
      }
    }),
    LocalizeRouterModule.forRoot(appRoutes, {
      parser: {
        provide: LocalizeParser,
        useFactory: (localizeFactory),
        deps: [TranslateService, Location, LocalizeRouterSettings]
      }
    }),
  1. In my browser module I have the following:
    app.browser.module
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: exportTranslateStaticLoader,
        deps: [HttpClient, TransferState]
      }
    }),

    LocalizeRouterModule.forRoot(appRoutes, {
      parser: {
        provide: LocalizeParser,
        useFactory: (translate, location, settings, http) =>
          new LocalizeRouterHttpLoader(translate, location, settings, http),
        deps: [TranslateService, Location, LocalizeRouterSettings, HttpClient]
      },
    }),
  1. My app routes (same in browser and server module)
export const appRoutes: Routes = [
  {
    path: 'example',
    component: ExampleComponent
  },
  {path: '', redirectTo: '', pathMatch: 'full'},
  {path: '**', redirectTo: '', pathMatch: 'full'}
];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant