angular / universal

Server-side rendering and Prerendering for Angular
MIT License
4.04k stars 483 forks source link

Can't use/inject REQUEST and RESPONSE in the browser #709

Closed samvloeberghs closed 7 years ago

samvloeberghs commented 7 years ago

I tried to inject (a stub for) the REQUEST in the browser bootstrap file like this:

import 'zone.js/dist/zone';
import 'reflect-metadata';
import 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { CompilerOptions } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { REQUEST, RESPONSE } from '@nguniversal/express-engine/dist/src/tokens';
import { BrowserAppModule } from './app/browser-app.module';

const compilerOptions: CompilerOptions = {
  providers: [
    {
      provide: REQUEST,
      useValue: {}
    },
    {
      provide: RESPONSE,
      useValue: {}
    }
  ]
};

platformBrowserDynamic().bootstrapModule(BrowserAppModule, compilerOptions);

as this mostly resembles how the bootstrapping is done in the express engine. But this doesn't work, but it does compile and build. I can get full access to the REQUEST on the server, but in the browser I get this error: ERROR Error: No provider for InjectionToken REQUEST!

I tried the same providers in the root Module. Same result.

Inject the REQUEST like this, anywhere in the application: constructor(@Inject(REQUEST) private REQUEST: any) {} and run the application. It will work on the server side but emit an error in the browser ( see stacktrace below )

That I can inject the REQUEST ( and/or RESPONSE ) also in the client side code. The values should just be mocked as empty or filled in where possible, like for example the document.cookies

samvloeberghs commented 7 years ago

Example project: https://github.com/samvloeberghs/ng-universal-demo

(outdated) Injection of the REQUEST: https://github.com/samvloeberghs/ng-universal-demo/blob/master/src/app/home/home-view.component.ts#L14

(outdated) (Trying to) Stub the REQUEST and RESPONSE: https://github.com/samvloeberghs/ng-universal-demo/blob/master/src/main.browser.ts#L11

samvloeberghs commented 7 years ago

@FrozenPandaz I think you are the best one to take a look at it please .. ( also according to my chat with @manekinekko ) Thanks a lot in advance!

MarkPieszak commented 7 years ago

Move those into your browser-app.module (the REQUEST/RESPONSE providers) and you should be all set. Also for REQUEST you could just pass back cookie: document.cookie since the browser has access to those, instead of an empty {}. https://github.com/MarkPieszak/aspnetcore-angular2-universal/blob/master/Client/app/browser-app.module.ts#L56-L57

Hope that helps!

samvloeberghs commented 7 years ago

@MarkPieszak your solution doesn't work in my case. The same error keeps popping up.. Am I missing something? As I said I tried this before, only did not do it with the factory pattern..

I've updated the example repo I created and more specifically here: https://github.com/samvloeberghs/ng-universal-demo/blob/master/src/app/browser-app.module.ts

samvloeberghs commented 7 years ago

hi guys, sorry about the push, but this is completely blocking my development.. As you said before it should be possible, but the example repo that I made ( which is a fresh clone + import of the request ) doesn't work out..

julienR2 commented 7 years ago

@samvloeberghs and @MarkPieszak, I have the same problem.. In my case I'm trying to access the cookies on the server side (on client side I use ng2-cookies). I was using this way on angular 2: server.ts

res.render('../dist/index',` {
    req: req,
    res: res,
    cookies: req.cookies
  });

then in server.module.ts

function getCookies() {
  return Zone.current.get('req').cookies;
}
...
{ provide: 'Cookies', useFactory: getCookies },
...

any-component.ts

constructor(@Inject('Cookies') private cookies)
...

But it doesn't seems to work anymore neither..

And I just tried the new InjectionToken<string>('REQUEST'); but I got nothing on the server. Also get the same error as @samvloeberghs (No provider for InjectionToken REQUEST!) when reproducing.

Any hint we could explore ?

MarkPieszak commented 7 years ago

I haven't used the express engine in a little while but that's strange since they're definitely being passed in here : https://github.com/angular/universal/blob/master/modules/ng-express-engine/src/main.ts#L129

@frozenpanda have you ran into this?

julienR2 commented 7 years ago

I read again the initial issues description by @samvloeberghs and I realize now that I have the oposite problem.. Providing REQUEST in the browser.module.ts as suggested by @MarkPieszak DO work for me. However on the server-side I still got the No provider for InjectionToken REQUEST! error...

Indeed it's strange since it is well provided by the ng-express-engine... Still investigating..

julienR2 commented 7 years ago

@FrozenPandaz on a fresh clone of your repo ng-universal-demo, I reproduce the same behavior. I get the Server Side error No provider for InjectionToken REQUEST!, but get the provided REQUEST on client side.

FrozenPandaz commented 7 years ago

Sorry about this, while there seems to be many issues regarding the request and response tokens, i do not think this is one of them. I'm able to use them without AoT here

https://github.com/FrozenPandaz/ng-universal-demo/tree/request

Adding another implementation as a provider in your browser.app.module should do the trick..

(Build is acting up right now because of something related to AoT)

samvloeberghs commented 7 years ago

I'm gonna try out your solution tonight.. But if it's not working with AoT it's pretty useless.. edit: verified that it works in a JIT build, AOT still fails. The solution provided in https://github.com/angular/universal/issues/713 I'd also rather avoid..

julienR2 commented 7 years ago

Ouf I finally got it ! Thanks to your last update of the readme of the ngExpressEngine @FrozenPandaz !

So far I was creating a file request.ts with..

import { InjectionToken } from '@angular/core';
export const REQUEST = new InjectionToken('REQUEST');

.. then adding the REQUEST provider to browser modules, and injecting the REQUEST wherever I needed.

However with this I had a No provider for InjectionToken REQUEST on the server side, even if the ngExpressEngine should set the providers here https://github.com/angular/universal/blob/master/modules/ng-express-engine/src/main.ts#L129 as you pointed out @MarkPieszak.

After reading the update of the readme, I used the InjectionToken from import { REQUEST } from '@nguniversal/express-engine/tokens'; instead of my own requests.ts file. And it now works !

The problem seems to come from not using the same InjectionToken variable that the one set in the provider. Which make sens.. I probably got confused because I used to set providers using a string ({ provide: 'example', useFactory: getexample },) instead of a InjectionToken.

Does it make sens ? I hope I've been clear enough in the explanation !

Thanks for your help !

samvloeberghs commented 7 years ago

still doesn't work with AOT on my side.. Can't do more than provide the example repo.. run it and see it failing :)

julienR2 commented 7 years ago

Yep not working in AOT.. and this solution doesnt work for me either https://github.com/angular/universal/issues/713 Still No provider for REQUEST

samvloeberghs commented 7 years ago

it seems so strange tough, as using different providers for server and browser seems to be working fine, if imports don't come from a library. So my gut feeling says that the problems reside in the express engine module. If I would have the time to play around with it I would to see what it requires to get it to work, but have too much commitments at the moment..

vikerman commented 7 years ago

Is this resolved after adding the ngc compilation?

samvloeberghs commented 7 years ago

@vikerman still need to validate.. will try to do it in the upcoming days edit: JIT works, AOT works, wicked :) thanks a lot! @MarkPieszak @FrozenPandaz @vikerman

phil123456 commented 6 years ago

we update our project and have that very same issue

julienR2 commented 6 years ago

@phil123456 Did you update your project taking in account this breaking change ? https://github.com/angular/universal/blob/master/CHANGELOG.md#500-beta6-2018-02-28

sjsnider commented 6 years ago

@samvloeberghs I was just trying to running your Universal Test (https://github.com/samvloeberghs/ng-universal-demo) and I get that no Provider for InjectionToken Request error. Any chance you would have a moment to update with the working version? Would be much appreciated, thanks!

samvloeberghs commented 6 years ago

@sjsnider I haven't update it in years.. You can best checkout this updated project, where my original demo was also based upon.

sjsnider commented 6 years ago

Thanks, I got it working, just had to slightly change the import of the REQUEST to import { REQUEST } from '@nguniversal/express-engine/tokens'; and then inject the REQUEST optionally,

  constructor(
    @Optional()
    @Inject(REQUEST)
    private request: any){}

Thanks for the great start!

angular-automatic-lock-bot[bot] commented 5 years ago

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.