Skip to main content
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with: Jeff Coughlin
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with: Jeff Coughlin

JavaScript Application Size Shouldn't Affect Performance

By
Published in , Comments (7)

I listen to a lot of podcasts in an effort to gain a better perspective on software development. And one sentiment that I've heard repeated a number of times across different podcasts is that as the size of a JavaScript application increases, its performance decreases. This is often touted as a reason to switch from one JavaScript framework to another—that some magical threshold has been reached. But, this sentiment makes little sense. The size of a JavaScript application should be completely disconnected from the performance of said application.

David, in Schitt's Creek, saying, Hmmm, a bold claim.

To be clear, there are performance characteristics that do go down in relation to the size of a code-base:

  • Build and compile times may increase as more files are added to a code-base.

  • Deployment windows may increase in duration as the size of deployable artifacts increases.

  • Larger servers may take longer to come online when scaling up.

  • Initial load times of an application may increase if the client has to pull-down larger files when initially loading the page.

  • Initial load times of an application may increase if small changes to an application invalidate large portions of the browser cache.

But, these are all up-front costs, most of which are entirely hidden from the end user. And, these are not the performance problems that people are discussing on podcasts. From what I can parse out of these conversations, people believe that the runtime performance of an application decreases as the overall size of the application increases.

The runtime performance of a JavaScript application can only ever be impacted by the volume of data being displayed on a given page (and the strategies with which said data is being fetched). The runtime performance of any given page has nothing to do with the size and scope of the overall application.

How could it? To put it in concrete terms, that's akin to saying that the very existence of an "Admin page" will negatively impact the rendering and interaction speed of a "Shopping cart page". But, these two pages probably don't even reference each other? So, what exactly is impacting performance?

If you have a data grid and you try to render 100,000 rows; and then reactively update the data in those rows; then, yeah, that page may be really slow. And switching to a different rendering strategy (such a row virtualization, pagination, or lower-level APIs) for that page may help speed things up. But, your 100,000 row data grid has nothing to do with the overall size of the application. And such an exceptional edge-case probably shouldn't affect your overall choice of technologies.

Earlier today, I wrote a post about how many people view code through a magical lens. I believe that this magical perspective on code relates directly to this notion that the size of a JavaScript application has a meaningful impact on its performance. When you lose sight of the actual mechanics of the request-response life-cycle, it's easier to be influenced by the size of an application because at least it gives you something to consider.

But consider what happens when you move from one page of a JavaScript-based, Single-Page Application (SPA) to another page:

  1. The user clicks a link.
  2. The browser URL updates.
  3. The JavaScript application framework reads the new URL.
  4. The JavaScript application framework pattern matches the new URL against the route tree.
  5. The JavaScript application framework unmounts the current View components.
  6. The JavaScript application framework mounts the new View components.
  7. Your View components render some data.

Rendering a route within a SPA is just a series of commands. And, none of these commands is impacted by the overall size of the application. And, I believe that it's logically sound to argue that if the performance of any one route isn't directly impacted by the size of an application, then the performance of all the routes together isn't directly impacted by the size of the overall application.

Aside: You could maybe argue that the number of routes affects the performance of pattern matching during navigation; but, I've never seen or heard of that being an issue for anyone. Furthermore, if it were an issue, it would be an issue regardless of which framework you were using.

Perhaps I'm missing something subtle about this argument that isn't being well articulated on podcasts. If so, I would love to better understand what people are thinking. But, as a general rule, if someone says something to the effect of, "we have to switch JavaScript frameworks because our application has hit a size threshold", I would dismiss that sentiment out-of-hand until that person provides a concrete and compelling argument. Because, otherwise, that sentiment simply makes no sense on its own.

Reader Comments

15,841 Comments

Over on Twitter, Zac Spitzer raised a good point. I think it's a bit tangential to this conversation, but it's worth sharing:

Let me guess you have a modern phone and a powerful laptop?

Here, Zac is rightly pointing out that on low-end devices, the size of a JavaScript file does absolutely impact both the download times and the parsing times (and probably the execution times) in a way that most of the people who read this blog are probably not familiar with. I, myself, haven't had a "feature phone" since 2006; and, I'm almost always on a WiFi connection.

And, frankly, most of my online experience is on a Desktop computer. All to say, the point is well received.

That said, I am calling this line of thinking somewhat tangential to the spirit of the post since I don't believe this is the conversation that is being had on the podcasts. When it comes to low-end devices, I believe many more considerations have to take place. Such as, should we even have a SPA? Or should we have an MPA (multi-page application) with maybe no JavaScript at all?

357 Comments

I think there's one large issue with your thinking here. You used this as an example:

"How could it? To put it in concrete terms, that's akin to saying that the very existence of an "Admin page" will negatively impact the rendering and interaction speed of a "Shopping cart page". But, these two pages probably don't even reference each other? So, what exactly is impacting performance?"

In a traditional MPA, it doesn't not. But in a SPA, even if you aren't viewing the admin page, the contents still need to be loaded. It may not be visible in the DOM tree as the route isn't there, but when you do change to it, that information has to come from somewhere, right? The components that make up the Admin page need to be rendered, event listeners setup, etc.

While "in waiting" it may not have a large impact on memory, it doesn't have 0 impact.

Right?

15,841 Comments

@Raymond,

This is true - all of the code does take up some amount of memory and parsing time, even if a page isn't rendering a specific route. Some of this is mitigated by using lazy-loading in the routers (which I think all of the modern SPA frameworks have at this point). Of course, even with lazy loading, as you visit more and more routes, more and more code is parsed and loaded into the runtime memory.

And, if that does becomes too much of a performance problem, switching to some completely different style of application - such as a multi-page application (or maybe something like Hotwire / HTMX) - might be worth considering. Though, I have to imagine that by the time you hit a performance problem in your SPA, such a migration to a totally new architecture would be a monstrous task!

I think what I am mostly reacting to is the idea that—if you're in the SPA world—that any of this is affected by you choice of framework. As in, "Angular/Vue/Svelte/etc will only get you so far, but then you'll hit scaling problems and you have to switch to React" (as an example). But, every single SPA framework is going to have the same exact set of resource constraints.

2 Comments

@Ben,

Just to chime in a little, in regards to performance, there probably isn't much difference in what framework you use.

But what keeps me out of the cool kid club is not wanting to use a JS framework at all.

As Ray hinted, a JS Framework embeds HTML code (in Javascript) that renders ALL your pages, so there is a cost. Maybe a small one depending on your connection speed.

But in my minority opinion, you don't need a JS framework. Especially if you build your own API.

You can still have a Javascript frontend, but instead use vanilla javascript, and less of it. You can use vanilla CSS too.

The idea is to build a thin client that fetches more HTML from your API, and less JSON. It works really well.

It frees you from complications such as framework version compatibility, builds, typescript, and countless dependencies.

Nothing against JS frameworks, they do help provide conventions for teams to follow, I'm just offering an alternative.

15,841 Comments

@Bill,

To be honest, I struggle with this one. And the bee that keeps getting in my bonnet is the scoped CSS that the front-end frameworks provide (ie, CSS blocks that are dynamically scoped to only apply to a small subset of the HTML). I believe that custom web components can help with this; but, I haven't looked too much into them; and, the bits that I've seen seem to also require some strange build steps.

I've been very enamored with the idea of HTMX and Hotwire Turbo for sending HTML over the wire. I'm curious to know if you use things like that; or, if you're API just returns HTML. I'd like to know more about what your solution actually looks like.

2 Comments

Hey @Ben thanks for asking.

I think you might be referring to frameworks that build a series of web components isolating CSS in the shadow dom.

In my view, that approach is an example of overcomplication. You don't need the shadow dom, just a better approach in writing CSS. At least for most situations.

To help, here are a couple ways CF devs can live without the pain.

If you need an app to perform like a SPA, but need server side rendering, all you need is a small amount of vanilla javascript that intercepts events such clicks and submits. In turn, javascript fetches the page from a URL, then updates the dom. This concept is just like HTMX or Hotwire, however you might be better off writing the JS yourself. The only drawback is it does not separate a frontend from a backend (that is, if you consider that drawback).

If you want a separate frontend without server side rendering, you can build an app with vanilla javascript and vanilla CSS (even better with custom web components). For me, I found my stride by bundling vanilla javascript modules and vanilla CSS using Vite. No offense to the TS crowd, but you don't need that either. The concept is to fetch unstyled HTML from your API using all the CFScript tags we love and make life easy. The result is shipping less javascript, and deploying anywhere.

For Javascript, one guy I admire is Chris Ferdinandi of Go Make Things. I believe we share the same ideals.

Hope that helps!

15,841 Comments

@Bill,

Ha, funny that you mention Chris Ferdinandi at the end, because I was about to say that he has a utility web component, <ajax-form> , that sounds like it's very similar to what you're proposing (ie, intercepting actions and executing fetch() commands).

I am actually quite keen on the idea. A year or so ago, I updated this blog to use Hotwire Turbo, which basically does this ... expect with like 300kb of library code 😜 But, my experience with it has been mixed. It has some bugs that have been hard to fix; and have required me to back those area of the application out of Turbo and just use an explicit fetch() calls (such as the Preview of the comment that is rendering right now below as I type).

I'm curious to know more about your strategies for writing CSS. I feel like I've gone all over the place. One of the easiest, albeit brute-force, approaches that I've used is to prefix class with an incrementing number. Like, c1-, c2-, c3-, to create a namespace. Example (using LESS CSS nesting):

.c13 {
	&-widget { .. }
	&-header { .. }
	&-body { .. }
	&-call-to-action { .. }
}

Then, in my HTML, I'll have to make sure I include those namespaces:

<div class="c13-widget">
	<header class="c13-header"> .. </header>
	<div class="c13-body">
		<button class="c13-call-to-action">
			Do it!
		</button>
	</div>
</div>

Essentially, I'm trying to manually apply the name-spacing that frameworks like Angular would have given me for free.

Post A Comment — I'd Love To Hear From You!

Post a Comment

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel