What do you think...single page vs multi page?

I’m going to go against the grain here:

SPAs can be good, but also they can be very problematic. I would caution anyone to think about this approach seriously before investing a significant amount of time–especially if the page will be large/complex with lots of elements. I say this from hard-fought experience trying to deal with serious issues with my own large SPA.

SPAs do have their place and are useful for things like small/medium sized dashboards to help minimize server/db requests and improve load times and user experience. HOWEVER, for larger and more complex pages with lots of different elements, conditionals, etc SPAs can be a challenge–dare I say a ‘nightmare’–to work with in bubble. Backtracking and undoing this approach after you’ve gone down that road is an equal nightmare.

If you are going to build an SPA, employ the KISS principle.

In my own case, I did not use KISS. I built a very polished (see: bloated and convoluted) page template with lots of elements and conditionals and states. I then copy/pasted my template elements for all of my necessary ‘sub pages’. At the time, I was full-throated SPA-guy and my guiding philosophy was that our user would deal the longer page load time of my large SPA because of the benefits I mentioned above.

What I didn’t count on were the performance issues editing this page inside the bubble editor and the performance of the page itself after loaded.

tl;dr I’m currently going through the process of splitting up my SPA into individual pages and its a bitter divorce.

Basically my large SPA choked the bubble editor performance so much as to basically become impossible to work with effectively. I didn’t come to this decision lightly (or quickly) because of the effort involved to do this. I first scanned the forums first looking for any answer to help speed up performance like turning off the issue checker using issues_off=true, refreshing the browser every 20 minutes, etc, faster development hardware (I have a late-model i7) .

Even with all of the above maxed out, I had persistent performance lags. I would constantly wait in anticipation after clicking elements and expressions wondering ‘did it register my click?, I don’t want to click again if it did’. Running live previews took 20-30 seconds to load. Its no wonder though, after pulling a chrome page load audit my downloaded page data weighed in at over 20MB! this is downloaded every.single.time. Yikes.

I’ve seen an increased mention lately to use ‘reusable elements’ to help break up the complexity of these larger SPAs and help boost editor performance. While this does help editor performance, it does not speed up page load time. Reusable elements are downloaded, in full with your page/ . Even if you don’t care that it will take your user longer to load the page, remember that you need to load the page all the time while developing. This can sting when trying to iterate through changes. Additionally, running your large page takes away from overall performance and this impacts the editor too.

For larger designs with lots of element, I’d recommend the more traditional approach of making individual pages with reusable elements for top navigation, sidebar, and footer.

6 Likes

Hi @jon2

I also went through this long and painful path that cost me months of work. I understand the feeling very well. My discovery was to transfer as many operations as possible in the API Workflows (BackEnd Workflows) and the use of reusable elements. Good luck in this conversion!

9 Likes

With the arrival of global variable plugins this has become an excellent option. Especially as you can work on a single page at a time without having to develop on the main SPA page.

However, IMHO most apps should employ a combination of single page and multipage methods.

4 Likes

Couldn’t agree more. Everything has its place and SPAs do work well in many circumstances. I have SPAs that work great! Since this design concept seems to be getting increased traction here in the forums, I wanted to offer some less talked about advice that I wish I had receive before I started out with my problem page:

You can run into scalability issues fairly quickly if your page / sub page design is complex enough.

2 Likes

This is a great perspective, @jon2. Thank you for sharing! One of main things I was hoping to pull from this discussion was experience (everyone here has added their own insights and experience, which is great!)…

It can be hard to determine the right direction based on suggestions alone because what works for one person might not work for another. When it comes to something like this, it can be case by case and really depends on goals and individual needs.

While many people swear by a SPA structure, your experience really highlights different aspects to consider.

Thanks for sharing your insight!

PS: I put together another video highlighting the MPA side vs the SPA side shown in that original video. There’s a ton to consider (which is clear from this discussion!), but it goes through some of the bigger and more general benefits of going the MPA route if anyone’s interested.

2 Likes

Absolutely. SPAs can be effective and I have several of them that work well. I would do them again for the right use-case. Its all about your needs.

The SPA design concept seems to be getting some good traction here on the forums, and so I wanted to add a voice of caution–advice I wished I had received myself–to those who are considering it before they embark on their build:

  • SPAs have scalability limits (in terms of your ability to effectively edit them).
  • These limits can be reached sooner than you think if your page or ‘sub page’ design is complex enough. (My page was very complex)
  • When you’ve reached the limit (which is really your own limit of patience). The solution is to split up the SPA or redesign which is very time consuming.
2 Likes

Hi John,

Question on this one! I tried moving workloads to the Backend by scheduling an API workflow a few seconds into the future ( say 5 seconds) in the hope of unburdening the process. Now this will probably flag my way of understanding how it works, but I noticed loading time would just increase with the amount of seconds I would put in there as if the system just waited that time and would then execute the API workflow. What is your experience and how do you transfer the operation if you need the results fast?

@jamesbond Is there a way to ‘get’ the first template to use?

You just mentioned everything I am currently struggling with in my SPA. I better start splitting things up into a MPA right away. A bitter divorce indeed.
Thanks @jon2
Thanks @romanmg

So far I am going SPA. My app has a fairly complex set of user search capabilities that results in a scrolling RG of results from a 5000+ entry dataset. I am still constructing it, but so far so good. I’ve read of editor slowness in the forum but personally haven’t experienced it (I’m on a professional plan).

That said, I’ve gone into this with the mindset that I have to keep everything as clean and light as possible. Whenever I add something that adds materially to load time or performance, I stop and try to figure out if there’s another way, or if I really need that function. It’s been some trial and error going through that process. As I get further into finishing and formatting hopefully performance continues to be fine.

Everyone’s project is unique though.

1 Like

Even though a lot of developers have hopped aboard the single-page application bandwagon lately, MPAs still have some advantages. If you need to create a dynamic solution with a limited data volume, single-page applications are the perfect match. You can read some topic-related articles like this one https://yojji.io/blog/spa-vs-mpa

@romanmg @jon2@ @patricia @jamesbond I’ve been taking a novel approach to SPA development lately, and wanted to offer it for the good of the order, as well as to request your feedback. My goals were to maximize performance while minimizing the time my team actually needs to spend in the editor, for all the reasons outlined above.

Essentially, each time a user loads our site, we download a list of all the site’s “views” and store it in a custom state. This data type is our abstraction for pages/subpages and contains all the information needed to build our UI dynamically.

Each time the user visits a new URL, we detect the change (using @sudsy’s excellent Sudsy plugin) and lookup the current view (from the library we downloaded earlier) by referring to the URL pattern. We set this view to a second custom state.

The view record contains an ordered list of “modules.” This custom type is the building block of our UI. Modules can be nested, have templates and contain fields for variable data.

The visual design of our modules are defined through templates, which are held in a series of very large reusable elements (shoutout to @ideable, @vlad and the folks at Airdev, who planted the seeds for this system). A given template might have several variants, which are defined via custom states and conditional logic.

On URL change, then, the following events occur:

  • We examine the URL pattern and set the current view
  • Referencing this custom state, we pull the appropriate modules into our Repeating Groups
  • The UI and data of each cell are defined in relation to the current cell’s module’s template, variant and fields.

The primary benefit of this setup, of course, is that it allows us to add, delete, reorder and tweak the UI for a given view without touching the editor at all. The only time we need to do that is when we want to add a new module or variant to our library, and then we do so in our reusable elements. Our extensive use of these reusables and repeating groups helps us keep the page as light as possible, as well as ensuring consistent padding, margins, etc.

We’re planning to build out a simple GUI that will allow us to edit views on the backend. So far very happy with the setup.

Cheers! :beers:

8 Likes

As an addendum: I’m wondering if it would be more performant to query the current view from the DB each time the URL changes, rather than downloading the full library of views (about 40 complex records) on initial site load and referencing this list on subsequent URL changes.

My thinking is that the way we’re doing it now is best. However, I’m still a rather novice Bubbler and have limited knowledge of the underlying technology.

We’d originally built out the entire view/module system using option sets, which worked well. However, the workflow was simply too clunky that way.

1 Like

I love this concept @ts11. I had actually asked @romanmg for input in her VIP group for the best way to go about something quite similar and she suggested dB not Option Sets but I’m not sure if there was reason for that. I have yet to find the time to build what I plan so I can’t say which will be better for me, Option Sets or dB, but the dB will at least allow more flexibility to change using a backend admin with user friendly UI rather than having to get my head around intangible option set attributes so I think I will go the dB way too.

My thoughts are that it will be more performant to query the current view each time the URL changes but it is likely to depend on your page design. For example if some modules are reused on many views then it might make sense to load those at initial load. At the very least it might make sense to have a standardised module, or modules, at the top of each page so those should be seen to load immediately and the modules below the fold could be loading whilst the user is getting their bearings.

Thank you for taking the time to post your approach because you have just helped me plan and prepare for my next project in the coming weeks.

2 Likes

Glad to hear it was helpful and that I’m not alone in my thinking on this. Best of luck on the new project!

Hey @ts11, I think this is really clever. Steve @sudsy put me onto your post and I’m going to try using this modular load it in my own application.

If you don’t mind sharing, would you be able to clarify what you’re doing to “examine the URL pattern and set the current view”? I’m sure I’ll figure it out eventually but any pointers/screenshots would of course fast-track me.

Did you end up testing your hypothesis re “query[ing] the current view from the DB each time the URL changes, rather than downloading the full library of views (about 40 complex records) on initial site load and referencing this list on subsequent URL changes.” My site is going to have hundreds of URLs so i’m leaning in that direction.

Thanks,
Chris

1 Like

Hi Chris! So glad you found my thinking useful. I’ve actually evolved this approach considerably since making my last post and have made a number of improvements, one of which relates to how I store and reference the view configurations. I’ve moved away from a typed approach and am instead storing the site configuration file (all views, modules, etc) in a single JSON text that is downloaded on initial page load and parsed with the help of @jon2’s JSON Machine plugin. This is a much more light-weight approach that has a number of other benefits, as well. I’ve tested most of the underlying assumptions implied by this approach, but am still in process of finishing my first build using it. I’m working to document my methodology, as well, and am happy to share that once it’s complete. Cheers!

5 Likes

Thanks for the update @ts11 . I’ll check out that plugin and keep an eye out for your methodology post!

Cheers,
Chris

1 Like

Absolutely! Cheers :beers:

@jon2 Brilliant! you saved me lots of time trying to solve the heights screen adjusts in one single page development, all i need to do is to turn back all the way to setup the groups as reusable elements, Have you or anyone faced any sort of white vertical spaces caused by Ext. vertical scrolling RG’s between the cells? and what the best way to avoid them.