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

Angular 4.x integration #83

Closed
MarkPieszak opened this issue Feb 7, 2017 · 41 comments
Closed

Angular 4.x integration #83

MarkPieszak opened this issue Feb 7, 2017 · 41 comments

Comments

@MarkPieszak
Copy link
Member

MarkPieszak commented Feb 7, 2017

Some notes:

Approximate boot-server API will be:

platform
  .bootstrapModuleFactory(MyAppModuleFactory)
  .then((ref: ApplicationRef) => ref.isStable.filter(v => v).toPromise())
  .then(() => {
     return { 
       html: platform.injector.get(PlatformState).renderToString()),
       meta: platform.injector.get(MetaServce)
     };
  } 
  .then(result => /* do magic */ )
  .then(() => platform.destroy());

Then we'll integrate it with .NET to render the Title & Meta tags in the MVC view template.

This is also connected to #10

@MarkPieszak MarkPieszak added this to the 1.1-Angular4.x milestone Feb 7, 2017
@kukjevov
Copy link

Any news here? Are you planning to update this for beta.8 or will you wait for rc.0 ng4 ?

Thank you for great job here :-)

@MarkPieszak
Copy link
Member Author

I'll be updating very shortly currently testing it out to make sure and give feedback to the team, I'll make a PR to the repo in the next day or two!

When it gets in let me know if any issues pop up for you! @kukjevov

@kukjevov
Copy link

Hello :).

I can see that you are already working on it, it is just great :). I want to ask you are there any changes required from https://github.com/aspnet/JavaScriptServices project to make angular4 working? Are you planning to update also their template for Angular2Spa, or you are going in different direction as they are going ?

Thank you :)

@MarkPieszak
Copy link
Member Author

So far everything is going well! I'm currently creating a wrapper for the .NET integration so it will automatically try to pass down Title/Meta & Styles tags separately (for you to parse yourself on the .NET side).

Yes I was going to send a PR to the JavaScriptServices repo as well! Some main differences will be that we'll no longer use the TagHelper, and that the code will either be triggered in the Controller Action, and passed down via ViewData, or in the .cshtml file itself.

I'll message you as soon as I get a more polished PR to get in here so you can test it out and give me any feedback! Sorry for the delay, I'm making sure to give any feedback back to the team quickly so everything works flawlessly for .NET as well.

Cheers

@hheexx
Copy link

hheexx commented Mar 3, 2017

Hi Mark!

I know you are redoing angular-asp integration now so I wanted to ask if we can make a way that if angular router can't find a route that it send's that info to asp so it can set http status code to 404.

Important for SEO.

@MarkPieszak
Copy link
Member Author

Hey @hheexx
So I'm going to be gone this next week so I can't imagine I'll be able to put anything up just yet (I'd rather make sure everything is ironed out and totally production ready!) It shouldn't be an issue to have both AoT and ng 4.x though no worries :)

As for the 404, if you refresh the page here: It actually already does Render the 404 on the server through the Angular app: http://aspnetcore-angular2-universal.azurewebsites.net/not-found

You want .NET to handle that instead?

@AbrarJahin
Copy link
Contributor

I think that is not possible to handle 404 page by the server because angular works after server HTTP done and it works on the pages what is not existing on the server.

So, 404 page should be handled by angular as far as I know.

if you @hheexx need to use a server rendered 404 page then you should use that inside angular 404 page with a service, as far as I know.

Isn't it right @MarkPieszak ?

@hheexx
Copy link

hheexx commented Mar 5, 2017

Mark, you can see in developer tools.
404 page you shared is still served with http status code 200.
https://i.gyazo.com/ce381a772a4ca7b47e1f1dc0c760dc7f.png
That is not good for SEO. Google does not understand it's 404 page.

It is ok that 404s are served from angular but we just need a way for a angular to pass right status code to asp with rendered string so asp can set correct status code.

@hheexx
Copy link

hheexx commented Mar 14, 2017

How it's going @MarkPieszak ?

Just to remind you, it's really burning under my feet xD

@dguisinger
Copy link

Hey @MarkPieszak any comments on where this is at? I saw you commented in your last ng4 branch checkin that you were shelving changes for now.

Any timeline for when things will be ready? ng4 release should be almost any day now.

Also, I hate to be that person, but any chance you can write a walkthrough on how to convert a project that was built from the version included in JavascriptServices back in November. I've slowly been working through all of the changes, but things are vastly different and not really a drop-in replacement if you already built a project off of the old code.

@MarkPieszak
Copy link
Member Author

MarkPieszak commented Mar 17, 2017

Glad you asked I'm actually working on it now :)

Using the latest RC5 that was released a second ago today 👍 screenshot below
image


I'm actually trying to mirror more closely to Steve's JavaScriptServices to make life easier for people, there have been some recent big changes to the App structure but they seem to be causing more problems than helping, so I'm going back to a more simpler structure :)

I'll do the best I can do document an upgrade strategy as well! @dguisinger @hheexx @kukjevov

Expect something in here by the latest Sunday.
4.0 official release is next week 💯

@dguisinger
Copy link

Great, looking forward to it.

Any idea how to solve this? I had your code up and running, and I can't figure out what I changed but now I'm getting:
NodeInvocationException: The Node invocation timed out after 60000ms.
You can change the timeout duration by setting the InvocationTimeoutMilliseconds property on NodeServicesOptions.

I kept increasing the timeout, but it seems to top out at 60 seconds even if I put 120 seconds as the setting. If I turn off server side rendering things work just fine. The lack of visibility into what is going on here is quite frustrating, I've been stuck on this all day.

@MarkPieszak
Copy link
Member Author

What code are you trying to run? The code in the ng4 branch is very old, I have everything locally win the latest stuff 😓 I'll push up the updated code today though so you guys can take a look. One of the last remaining issues is animations breaking on the server but Vikram and Alex are working on that one.

I'll keep you posted today as I get stuff in here.

@dguisinger
Copy link

hah yeah, I've been using your 2 week old code... I think part of it may be just the size of the project, my modules aren't lazy loading at the moment. I don't suppose you've been working to add AoT compiling support to your web pack example that's included, without it you can't lazy load modules when webpack is used. I miss the days of everything being built right into the visual studio build chain, you have so many tools in this template I don't fully understand yet

@MarkPieszak
Copy link
Member Author

Yeah the whole ecosystem / build tools / etc have changed pretty dramatically the past 2-3 years.
Lazy-loading will work fine with the latest stuff no worries there! :)

@MarkPieszak
Copy link
Member Author

MarkPieszak commented Mar 21, 2017

image

So it's basically all set, I'm just cleaning up the Repo in the morning, I think it's best to simplify it again a little bit (and take it back to the 1 project way it was before).

In the screenshot above we have everything being abstracted out automatically, and those things are all rendered by .NET. :)

Sorry about the delay, 4.0 release should be Wednesday, just wanted to iron everything out beforehand.

@dguisinger @hheexx @kukjevov

@hheexx
Copy link

hheexx commented Mar 21, 2017

Hi @MarkPieszak,

Looking good :)

Can you test/confirm following use cases:

  1. cannonical url
    <link rel="canonical" href="https://blog.example.com/dresses/green-dresses-are-awesome" />

  2. hraflang
    <link rel="alternate" hreflang="es" href="http://es.example.com/" />

  3. right http status code
    comment 9

@MarkPieszak
Copy link
Member Author

As for canonical, I'll provide a nice LinkService class that'll automatically grab them (if you have any link info setup in your router : data {}

image

Is canonical and that alterante something that is changed per Route or a global thing?
You'll be able to just make some Meta or Link elements default if they never change.

@hheexx
Copy link

hheexx commented Mar 21, 2017

per route.
alterante should link url-s in different languages. It should be connected to i18n systems.

@kukjevov
Copy link

kukjevov commented Mar 22, 2017

Hi @MarkPieszak,

i have been working on my own solution for angular 4.0 SSR and everything around it, since we are using angular in both Java and .Net environment in our company. I had great inspiration from you and from FrozenPandaz ng-universal-demo. Thanks to both of you i have working solution so far. You can check it https://github.com/kukjevov/ng-universal-demo/tree/mine if you want, maybe have some notes, suggestions for me :). You will not be able to run it since i am using some packages which are not in public npm repository.

But still i have managed to enable also preboot. You can quite easily switch among, compilation with aot, ssr, prod, hmr.

But why am i writing :). I need your advice.
How to make XhrRequest working on Server side if there is some authentication (Windows Authentication, Cookies authentication, Basic Http Authentication), since all of these require either user interaction or presence of cookies which are provided by browser automatically?

And another thing is that i took different approach to rendering SSR from asp.net core. Since i am using Asp.Net Core MVC only as WebApi i did not want to use any cshtml. I was thinking about Middleware that will directly call same code (with slight modifications) as i have in my server.js

        if(!isServerRenderAvailable())
        {
            next();
            
            return;
        }

        getServerRenderFunc()(path.join(__dirname, wwwroot, 'index.html'), req.originalUrl, {baseUrl: "http://localhost:8888/"}, function(err, succ)
        {
            res.setHeader('Content-Type', 'text/html');

            res.end(err || succ);
        });

in repository above which will only render everything in string and return it to Asp.Net Core. But now i am fighting with thought if it is not better to run whole server.js on different port and proxy requests to this server? Why am i thinking about this solution? Because it would be easier to process cookies on Angular SSR, since you can use https://www.npmjs.com/package/cookies on both solutions with Asp.Net Core or directly only with Connect server. And maybe some other advantages could be there.

What do you think about this?
Thank you for any help :).

@hheexx
Copy link

hheexx commented Mar 24, 2017

Hi @MarkPieszak,

Angular 4 is released and this is sliding day by day for a month now.
Can we get any hard date when we can expect this to land or if you can land anything on a breach now.

If we can't get this in production by end of next week we have to switch to prerender.io or something similar.

@MarkPieszak
Copy link
Member Author

MarkPieszak commented Mar 25, 2017

Unfortunately the changes in both VS2017 & Angular 4.0 made things keep getting pushed back due to new and different errors...

I'm about to push up a WIP one, (The styles/meta/title are commented out, as the ASPnetEngine still needs a few tweaks, it'll also be on NPM when it's finished, it's inside the project at the moment) as of 4.0 release last night but they were with RC6) But that shouldn't be too tough to fix. I just figure you want something so you can get going at least.

When I fix the aspnetcoreEngine it'll fill in Title/Meta/Link/Style etc automatically, but it has everything else in place for it to work once the engine is done. .NET will handle them all now once it gets them parsed back.

At least now it's VS2017, and simpler as well.
I'll add more features in there soon, just want to keep it a little simpler than the way the repo got :)

@MarkPieszak
Copy link
Member Author

https://github.com/MarkPieszak/aspnetcore-angular2-universal/tree/angular4.0-NEW-wip

@hheexx
Copy link

hheexx commented Mar 27, 2017

Thanks a lot Mark!
I feel much better when I can work on something then when I sit helpless.

I have started integration. Had a problem with this bug
angular/angular#11580

I managed to fix it with seperate plugin config for client and server:

Client:
new webpack.ContextReplacementPlugin(/angular(\\|\/)core(\\|\/)@angular/, path.resolve(__dirname, 'notexist/')),

new webpack.ContextReplacementPlugin(/\@angular\b.*\b(bundles|linker)/, path.join(__dirname, 'notexist/')),

I don't really understand what I done, it was trail and error.

@hheexx
Copy link

hheexx commented Mar 27, 2017

Also, do we need this in packages "@angular/tsc-wrapped": "^0.5.0", ?
As I understand it's sub dependency of compiler.

@MarkPieszak
Copy link
Member Author

Probably don't need it, it'll be included anyway I believe.
Yeah those just change trailing lines during the webpack config, no worries. As long as it works 💃

@hheexx
Copy link

hheexx commented Mar 27, 2017

I'm currently stuck with very ungrateful error:

Exception: Call to Node module failed with error: Prerendering failed because of error: undefined

Any idea?

btw AOT is not in yet?

@hheexx
Copy link

hheexx commented Mar 27, 2017

Solved. reflact-metadata was missing.

@hheexx
Copy link

hheexx commented Mar 27, 2017

Mark,

What is a way to use isPlatformBrowser ?

if (isPlatformBrowser) {
}
if (isPlatformBrowser()){
}

or 3)

 constructor(@Inject(PLATFORM_ID) platformId: string) {
    if(isPlatformBrowser(platformId)){
}
  }

I'm pretty sure it's third option but then I get:
Error: Uncaught (in promise): Error: No provider for PLATFORM_ID!

@MarkPieszak
Copy link
Member Author

You're using it like so?

import { isPlatformBrowser } from '@angular/common';
import { PLATFORM_ID } from '@angular/core';

export class SomeComponent implements OnInit {
   
    private isBrowser: boolean = isPlatformBrowser(this.platform_id);`

    constructor(@Inject(PLATFORM_ID) private platform_id) {}

    ngOnInit() { // example usage, this could be anywhere in this Component of course
      if (this.isBrowser) { 
          alert('we're in the browser!');
      }
    }

You could also just create your own that would work sort of like the isBrowser we used to have in angular2-universal, just need to inject them like so instead @Inject('isBrowser') private isBrowser: boolean

// app.browser
@NgModule({
  providers: [
    { provide: 'isBrowser', useValue: true }
  ]
})

@dguisinger
Copy link

I applied your changes to my existing project and am having an issue with image references.

I'm assuming this has something to do with the webpack config changes but I am not that knowledgeable in configuring webpack; i compared your source to my old source and nothing stood out.

I'm getting the following:
Module not found: Error: Can't resolve './img/avatar-2.jpg'
Which is a client-side reference to wwwroot/img/avatar-2.jpg coming from
Any idea what changed? With newer versions of everything should I be referencing static content differently?

The stack trace is referencing:
@ multi webpack-hot-middlewear/client?path=%@F__webpack_hmr ./Client/boot-client.ts

@hheexx
Copy link

hheexx commented Mar 28, 2017

Yea @MarkPieszak. Like so.

Now I switched to your solution with isBrowser provider and it's much more elegant and more importantly - it's working.
Thanks!

@LiverpoolOwen
Copy link
Contributor

LiverpoolOwen commented Mar 28, 2017

ERROR in ./~/browserify-sign/algos.js
 Module not found: Error: Can't resolve './browser/algorithms' in 'C:\Users\o
wen\Source\Repos\Angular4Core\src\Angular2Spa\node_modules\browserify-sig
n'
  @ ./~/browserify-sign/algos.js 1:17-48
  @ ./~/crypto-browserify/index.js
  @ ./~/angular2-universal-polyfills/~/reflect-metadata/Reflect.js
  @ ./~/angular2-universal-polyfills/browser.js
  @ dll vendor

I am seeing this when running webpack on the WIP branch

@hheexx
Copy link

hheexx commented Mar 28, 2017

@LiverpoolOwen
I just had same error on build server.

Try deleting node_modules. That fixed it for me.

@LiverpoolOwen
Copy link
Contributor

Thanks @hheexx! I just ran an rm -rf node-modules and ran npm i then webpack and webpack --config webpack.config.vendor.js and it seems to be fine.

Although when I ran rm -rf node-modules and 'yarn' it tried running the webpack configs and hit the error again. Weird.

@MarkPieszak
Copy link
Member Author

Yarn might not be triggering the postinstall script?

@LiverpoolOwen
Copy link
Contributor

Yes that will be it thanks. Any update on the AOT? @MarkPieszak

@hheexx
Copy link

hheexx commented Mar 29, 2017

@MarkPieszak

In aspnetcore-engine.ts, is there any particular reason why you get meta and title from AST_DOCUMENT but you get style by cutting output html string?

There is a bug currently that meta tags are emitted twice because they are in html string placed in between multiple <style> tags so they are embedded in style.

I will try now to get style now from AST_DOCUMENT.

Edit: Ok, I am idiot. Didn't read commented code. Anyway, you should know that metas are in style.

@MarkPieszak
Copy link
Member Author

Meta are coming up between styles ? I'll take a look!

@hheexx
Copy link

hheexx commented Mar 29, 2017

I turned on your "Broken after 4.0 (worked in rc)" code and it's working for me so I switched to that.

@MarkPieszak
Copy link
Member Author

Merged into Master and going to tweak a few things right now, closing this out as we have 4.0 in Master at least 🥇

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

6 participants