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 Universal Support #109

Closed
Joniras opened this issue Dec 23, 2017 · 12 comments
Closed

Angular Universal Support #109

Joniras opened this issue Dec 23, 2017 · 12 comments

Comments

@Joniras
Copy link

Joniras commented Dec 23, 2017

Could you please add Support for Angular Universal ?

I get this Error when trying to start the Server:

var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer;
                                                                                     ^
ReferenceError: window is not defined

Or is there any workaround to get this working ?

@reblace
Copy link
Contributor

reblace commented Dec 23, 2017

I don't think that ngx-leaflet is explicitly doing anything that would prevent server side rendering; however, I can't say the same for Leaflet itself. What's the context of the error? Do you have some source you can share?

@Joniras
Copy link
Author

Joniras commented Dec 24, 2017

However its still the library (beacuse it wraps leaflet itself) that is not angular-universal capable.
Sorry i dont have a context (because of webpack bundling) but #62 is looking the same (its closed but no resolved yet).

@reblace
Copy link
Contributor

reblace commented Dec 24, 2017

Leafet references the DOM and the browser window objects. Since you're presumably using server side rendering, the window object doesn't exist (there's no window on the server). See this article https://malcoded.com/posts/server-rendering-pitfalls for some details on these kinds of issues.

If you expect the map to be interactive (i.e., allowing zoom/pan), you can't render the map server side because the JavaScript that controls the interactions has to run client-side.

ngx-leaflet only deals with exposing Leaflet to Angular. AFAIK, it isn't doing anything that would make it incompatible with server side rendering (e.g., DOM manipulation or accessing global window object). In fact, there's nothing specifically that I can do with ngx-leaflet to influence whether it's compatible with server side rendering at all. That's determined by your application configuration and/or Leaflet itself. There are tricks you can play to shim Leaflet's various dependencies, but I'm not sure that is a very clean solution.

What we typically do for our customers is set up static HTML pages that load self-contained Angular application bundles for each individual page. That way, SEO works and we don't have to worry about 3rd party libs that aren't compatible with server side rendering. Honestly, it's way simpler that way than trying to get Angular Universal working with 3rd party JavaScript libraries as you are.

@reblace
Copy link
Contributor

reblace commented Dec 30, 2017

I'm going to close this since I don't think there's anything we can do with this plugin specifically to add support for Angular Universal. This is more of a general issue of how to make Leaflet compatible with Angular Universal. Whatever techniques or solution is discovered for that could likely be used with ngx-leaflet without requiring changed to ngx-leaflet itself. Thanks for bringing up the issue, though and read through my previous comment for some pointers for finding a solution.

@reblace reblace closed this as completed Dec 30, 2017
@Joniras
Copy link
Author

Joniras commented Jan 5, 2018

What we typically do for our customers is set up static HTML pages that load self-contained Angular application bundles for each individual page.

Could you maybe give me a link on how to do this ? i am not exactly sure what you mean.

But thanks anyway for the support 👍

@reblace
Copy link
Contributor

reblace commented Jan 6, 2018

Basically, you don't use Angular Universal. Instead, you break up your site into different html pages that are cached and served by the server (by a CDN or Wordpress or something).

With a single page app, you would have your "app-component" embedded in the index.html file and then Angular would bootstrap and load. And, you use angular/router to navigate between parts of your app.

Angular universal runs a headless browser and generates HTML snapshots of the Angular app, which works fine for relatively static apps (e.g., search/results or information presentation). But, when you try to get into interactive components (maps/graphs/etc), they need browser-side Javascript to be interactive.

With the approach I'm describing, you'd have several html pages with "app-component" in them and each page would load a different angular bundle with just the stuff you want on each page. You wouldn't use angular/router in this case, you'd just navigate between static pages that bootstrap different Angular apps. In this case it'd be really important to keep the apps small and use AOT to keep the load time fast. But, since you're splitting your app up into different pages, it would probably be easier to use lazy loading and bundling to keep the initial load small and fast.

I don't really have any links to share. I'd just be running the same google searches you would. Thanks for the feedback though!

@Joniras
Copy link
Author

Joniras commented Jan 11, 2019

Ok i now took a complete different approach for all that are interested:

  • I created a small angular-project with only leaflet (and my logic of displaying markers) in it
  • Instead of the leaflet element i made an iframe
  • The Iframe displays only the map (and my markers)
  • Communication between my app and the map (the iframe) is made with postMessage

I am aware that this solution is not the cleanest and is also not possible for everyone but for me it worked and maybe i could help someone with it.

Now for meAngular-Unviersal works with Leaflet included (somehow).

@betojsx
Copy link

betojsx commented Jan 31, 2020

Hi, @Joniras could you share how you embed the iframe with leaflet? Not sure if I get it. Is it a standalone angular project?

I'm facing this problem right now and waste a lot of time trying to solve it. Would love you could provide some more info

@Joniras
Copy link
Author

Joniras commented Feb 2, 2020

Yes its a standalone angular project and it just embeds an iframe to a subroute of my server (eg: /leaflet) which then gives me the index.html of the leaflet project and leaflet is therefore never rendered on the server.

@bluehalo bluehalo deleted a comment from hsuanweifu Sep 9, 2020
@OleksandrYatsiuk
Copy link

@WilliamRClark
Copy link

@OleksandrYatsiuk This article is basically telling me to toss the ngx-leaflet library, and use a service to inject the raw leaflet library.

It looks like I did find a way to get this to work with the Scully.io library (https://scully.io/docs/learn/getting-started/overview/). Unlike Angular Universal, it doesn't rely on running the app in Node which avoids this issue entirely. Note that this component doesn't really get pre-rendered, so you do get hit with the gets for the map pieces.

@WilliamRClark
Copy link

@OleksandrYatsiuk I updated my example of the pre-rendering failure using this library with a pre-rendering solution using Scully.io. https://github.com/WilliamRClark/leaflet-static-demo is the repo which demonstrates the issue using angular universal. Checkout the Scully branch to see what needs to be done to pre-render your app using Scully instead of Angular Universal.

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

5 participants