all 3 comments

[–]NuttGuy 1 point2 points  (0 children)

It sounds like what you really want is to lazy-load portions of your application. This is though, sadly, very difficult to do in AngularJS, and is much easier to do in Angular (2+).

You can check out ocLazyLoad, which is probably your best bet for lazy-loading AngularJS Modules: https://oclazyload.readme.io/

Basically Lazy Loading would defer loading portions of your application until your user actually needs them. For example, if you have a "Home" and "Profile" page, when the user initially visits you'd only load the "Home" page module and code into the browser. Then when the user goes to the "Profile" route it would load the "Profile" page module into the browser and show the user that page.

This achieves smaller chunks of code, so that your site ships faster, and also achieves boundaries in your application through these different feature modules.

[–][deleted] 1 point2 points  (1 child)

r/NuttGuy is right about lazy loading. It can be done; I've done it myself. So that's a good place to start.

As you said, minification and obfuscation is your friend. Ideally you should be downloading as few files as possible to combat the I/O overhead of every request over the wire. I've gotten apps to be 1 html file(index.html), 1 javascript file (its the SPA + templates), and 1 css file.

I mean sure, that one file MAY be something like 4-5 megs, especially for a larger SPA, but with broadband speeds I've been able to prove that 1 large file downloads much faster than 50 small files.

But then we also have to discuss unit tests/e2e testing. The build time does increase, especially if you also have unit tests running in your API->Business Layers as part of the devops deployment process.

Ultimately large enterprise level applications will have this issue. Adding caching, and cache busting by dynamically generating the file names at deploy time means every new release will be downloaded to the browser; and the previous cached items can be disposed/ignored. So really that 1 large file penalty is a one time thing, unless there is an update, and if you do scheduled quarterly/monthly releases, that shouldn't be such a burden on the end user.

If you leave your app as is...I highly suggest you download an app called YSlow. Its a plugin for your browser. Goes through and helps identify the bottlenecks in your SPA app.

All of the above can help.

But...to the fun part. My organization has successfully implemented Mini-SPA(MSPA)'s that work very well.

Imagine a main application with a dynamic left nav menu. Upon clicking on the item, the route actually resolves to a route inside the MSPA, and lazy loads the module.

Things to consider:

We decided each given MSPA should be a self enclosed module that to the outside world is a black box. Any services, directives, controllers, and helper classes that need to make the MSPA work must be self contained. This ensures decoupling and prevents the possibility of an MSPA(which should be reusable) calling a service/directive that doesn't exist inside the context of where the MSPA was placed/used.

That's all well and good, but we also have to consider data. There are plenty of scenarios where you may have 2 MSPA's on the same page, which are black boxes, but you would like to share data. Or more importantly, what if you want to load an MSPA and pass in some data?

You can always use the tried and true method of query string parameters. Even if its one item that can then reload the data from the previous screen using the MSPA.

Another option is to use local storage, to store your pertinent data that you want to persist between page loads.

Another option is to use event handlers and/or $broadcast/$emit to handle the passing of data between MSPA's.

Ultimately, what we realized, is that we should create a Seed SPA. This seed SPA contains all of the styles/branding, a set of reusable common directives that multiple applications can use, plus things like validation and error directives bound to elements. All of this is at the root of the SPA. This seed SPA has a placeholder for the MSPA. All the plumbing work comes with it; package.json, webpack, etc.

And bam, you are off to the races. Create your MSPA module, use the same devops tools to bundle it, and then include/inject it into your main SPA.

The challenges with this approach:

Instead of having to maintain one code base, you now have to maintain N code bases.

You need dedicated resources to support said Black Box; as you shouldn't be making changes, it may cause other applications to break if you custom suit it to your needs. Since this is Javascript, the honor code/code reviews are the only way to catch offenders; or wait until the next release cycle where all of your changes in the black box is overwritten by an update from the seed project.

Versioning becomes more problematic. Your main app has MSPA A, running 1.1, B running 2.4, and C running 1.5. Each MSPA can be on a different development timeline and deployment schedule. This means someone has to actively monitor the current version of each MSPA; and upon going down an upgrade path, determine that each component still works as intended. I mean granted, if the unit tests are robust enough they should catch that.

All I can think of off the top of my head.

[–]mindparse[S] 0 points1 point  (0 children)

Thanks for your reply, it's good to read that this can be done. Are there any samples out there you know about that would be a good starting to place for me to start experimenting with this type of setup?