Hacker News new | past | comments | ask | show | jobs | submit login
Ask HN: What are the common pitfalls/problems of Single Page App's?
13 points by rajangdavis on Feb 15, 2016 | hide | past | favorite | 18 comments
I am working on a Single Page Application (SPA) using Angular 1.5 and while I have spent a lot of time building it, I keep reading about various "issues" regarding javascript frameworks in general. To be specific, I am building the server side API as well as the front end, so I have a lot of freedom to adjust both sides as much as needed (which can be good and bad).

I feel like a SPA style app works well with the use case of the site I have been building in that we are making it easier for our customers to find their information in the shortest amount of time possible (think Google for product support).

With that said, I have a bias towards this design choice because I built it. I know that I might be missing something and I want to consider more use cases than what I can come up with.

What I want to know is when does it make sense to use a more traditional server-client architecture? I had read about Twitter reverting back from a SPA to server rendering, but I feel like their use case was specific to their needs or to a specific metric and possibly user experience for their site (lower time to first tweet, smaller page load, and cleaner URL's).

I am aware of SEO drop with Angular, but I feel like problems like clean URL's, back button not working, and UI thrashing are fairly solveable by good planning (in the case of the URL's) and Web Workers (to address UI Thrashing).

I chose Angular because I was already very familiar with it and I found it to be fairly flexible for what I need it to do, it just needs some nudging at times (ng-if vs. ng-show/hide). Also, at the time, I couldn't get the JSX tooling for React to work properly and I think Babel couldn't do transpiling for the latest version of React at that time (I think it was around 1.4). I had used Mithril which was a huge joy and very powerful, but the way my site works (it's an Oracle product using PHP/CodeIgnitor), I couldn't get the client side routing to work properly.




Speaking as a backend dev who generally avoids writing client-side code, the biggest problem that I've had is figuring out the "right" way to build the fucking thing. The JS fatigue is real.


What kind of stack are you working with? Honestly, this isn't the first time I tried building this on the site that we have, but this has been the farthest I have gotten without UI jank or slow initial loading. I would have much preferred to use Mithril, but I couldn't get the routing how I liked it; this is more of how the server is set up which I have limited access to.


Been looking at Ember, Angular 2, and Backbone + React. It's all just such a CF though. I was reasonably okay at Angular 1.x apps, but the learning curve is just so steep with these new frameworks that I don't even know where to begin. I've been making okay progress with Backbone and straight jQuery, but jQuery is slow and huge, so I'm slowly coming around to the idea of replacing it with something else.


I really liked Mithril, I would recommend checking it out. It definitely is kind of weird to write out your HTML with javascript, but it gets easier as you go along. The performance is ridiculous as well and it was a lot easier to troubleshoot as well. Also, the code kind of aligns with a JSON structure, so if you have a lot of control with the server response, it's really simple to grok how to structure your front end code.


- Angular doesn't enforce a convention. This gives you flexibility at the cost of zero convention. Developers tend to abuse this flexibility "because they can do it this way instead of that". Choose a convention among all the methods possible, then stick with it.

- Angular can be hard to debug when using some architectures. Two-way binding is pretty hard to track down. Scope inheritance is also a pain, especially with nested controllers, or when devs just stick everything to the root scope and expect it to be there when it doesn't at times. Even tools like Batarang and Inspector can be a pain to use.

- Long-running SPA's tend to accumulate unreleased memory if not managed properly. When stuff like this happens, worst case scenario is to have the user reload the page and lose state. Not taking this seriously, the browser may crash. You don't want this to happen in the middle of an operation, like say, a payment.

- State management is also a pain to work with. I often hear our devs talk about "invalid state". How can it be invalid? That's unless not all changes are accounted for. This is where the Flux architecture shines, as it isolates state in one location, away from the moving parts, and state only mutates via one mechanism - actions.

- It's huge size. One issue with Angular is that it uses too much boilerplate code, most of which is because of the structure and dependency injection mechanisms. Minifiers can only do so much to lessen the size, and not sure if Rollup can do much against these helper structures.


I am going to respond to each point

- Nailed it on this comment. I have been trying to figure out something that "makes sense" in terms of file structure and even code organization. So far, it hasn't been too much of a hindrance, but it I know the more code I write, the more unwieldy things will probably get.

- This is something that I have been very aware of and the way I have been handling it is limiting the number of controllers in general so I do not introduce new scopes. For the most part, all of the pages do not need to introduce new scopes and the data should be consistent across the pages anyways, so this hasn't been too much of an issue (yet).

-I haven't had this issue yet, but I haven't sufficiently tested this. From some initial testing, the memory footprint has been pretty light, but I need to do a lot more on this end once I have completed more of the app.

-State management hasn't been too tricky because there's only two states that I really care about: whether a user has logged in or if they are logged off. This part I have been addressing by loading JSON for contact information into the page to both limit the amount of AJAX requests and to enforce routing. Fortunately, this state is also managed by HTTPS Cookies so this is handled server side as well.

-I don't know how to validate or dispute this, but it looks like loading the minified scripts from CDNJS for both Angular and React were the same filesize. In any case, I have been using A LOT of what comes with Angular out of the box and have been using the UI Router library as well as the ng-Sanitize library for what I need. Haven't had too many issues with this.


In my experience SPA load rather fast. Only the first load and some crazy animations are really an issue.

And the first load issue can be circumvented with pre-rendering the first page on the server.

I tried this with React and it worked like a charm. It even went so far, that the whole page doubled for SPA and complete-server-side app, when JS was deactivated.


That sounds really cool! How simple/difficult was it to set up the prerendering and what kind of stack are you running?


The only ugly part was getting the client side React to pick up the server side markup when it comes "pre-filled" with dynamic data.

The client needs to use the same data or else it will throw away the whole markup and re-render it.

Fetch the data on the server before you render.

Render the (static) markup with React and the data.

Send the markup AND the (serialized) data to the client.

The client will render the markup normally before React kicks in.

The client React then needs a way to use the serialized data with the pre-rendered markup.

Redux, for example, is a way to pass down this data to every component, so it's available at render.

Normally, when writing React apps, you can simply load data async and show a place-holder while the request runs.

If you want to render on server, all the data has to be fetched before, if it's loaded async, so the server can render synchronously.


If you need to load everything up front then you might need a loading page like Gmail has


I feel like Web Workers have been a HUGE help in this regard.


I don't know if that's true.

I read that the workers can't get font measurements, which prevents layouting on webworkers.


You don't have access to the DOM with Web Workers but you can still perform an AJAX request and load in the data without disrupting the thread that renders the HTML. I highly recommend checking out the Pokedex progressive Web app for such a use case.

I use it on the first page load so that I can get all of the data I need for most of the routing upfront so that I don't need to perform an AJAX request for every state change. I was originally having the server render JSON inline with HTML but Web Workers ended up being faster.


Angular gives you plenty of room to shoot yourself in the foot via premature optimizations and over engineering. Multiple times a day you need to step back, gather outside feedback, and look at the big picture.

Also, get designer(s) involved in the process ASAP.


1. Perceived render speed. You'll spend a lot of time tweaking your views (nested ones in particular) to load and render as fast as good old HTML rendered on the server. 2. You already mentioned: SEO. But if this app of yours is behind a login that is not a problem.


Right now the render speed is good, but could be better.

One strategy that seems to work for this project has been to load in large, JSON objects using web workers while the first page is loading. This will allow the page to load and not disrupt the view rendering.

From there, I can use the large JSON objects to build the nested routes. I will use one view and link to it but add parameters to filter out the data. Ng-if has been making the rendering way way way faster going this route.

On a slow connection, two things that slows down the entire app is AJAX calls and rendering images. That is why I have tried to pull in the large JSON objects upfront so that the initial load might take an extra half second, but the rest of the app navigation is speedy.

SEO is my biggest concern, but for now, I am thinking I can use older links and do a 301 redirect to the needed resource. The only issue that I foresee is that I cannot do a server-side render; I was thinking of just routing bots to a non-ajax site so we can still get good SEO but it's while before I will get to this part.


Curious, how are Web workers helping you counter UI Thrashing?


Web Workers essentially make your Javascript multi-threaded. What this means is you can run multiple processes concurrently. You do not have access to the DOM with Web Workers, but they are really handy for anything that is long running or memory intensive. The benefit of this is that you can allocate Web Workers to fetch data or run some long process and this will not disrupt the rendering thread within the DOM.

Initially, I was having the server load up large JSON objects inline with the DOM so that I could avoid doing multiple AJAX calls. This worked with 2 very large JSON Objects, but as soon as I hit 3, the page would have a noticeable jank trying to evaluate these JSON Objects and render the page.

I remembered this article from Hacker News a while back (http://www.pocketjavascript.com/blog/2015/11/23/introducing-...) and started using Web Workers based on the speed of the app (it's pretty fast, check it out pokedex.org). There was a HUGE difference with having that first initial page load with the AJAX calls in the background. The only thing I would recommend is that you should make your first page load not contingent upon any AJAX calls or any loops (ng-repeat in the case of Angular). This will allow you to load in the page without having to wait for any response from the server and usually, the page will load alongside the data retrieved from the Web Workers.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: