Before the holidays, I was in the market to pick up a new pair of dress pants. Like you, I was pressed for time juggling work, family and social obligations, so I leaned on a time-honored tradition of people with more programming knowledge than fashion sense. Buy the same pair of dress pants you have, but this time in a different color. Unfortunately, this was only the beginning of my journey and involved more of my technical skills than should have been required to buy a damn pair of slacks.
Buying Pants
Since I already knew what pants I wanted, I headed to the multi-national clothing store’s website. I quickly added the item in the color and size I wanted to my shopping cart. I started the checkout process by providing my first and last name. Then I was presented with one of those address fields that suggests a list of addresses you can select as you start typing. I clicked on the correct address, and it filled out the address, city, province and postal code fields for me, which I appreciated as it saved me some typing. Then I filled out my credit card information and clicked "Purchase".
The purchase failed, and the form reported that I needed to fill out my first or last name. Weird, that’s literally the first thing I did, and visually, I could see my name in both of those fields, but whatever, I re-typed my name and clicked "Purchase" again.
It failed for a second time with the same error. At this point, I thought that it must be a problem with my ad blocker as it occasionally causes issues with shopping carts, even though your checkout experience should work even when your user has an ad blocker. So I disabled my ad blocker, refreshed the page, filled out the form again, and clicked on the "Purchase" button one more time.
Same. Damn. Error.
"The definition of insanity is doing the same thing over and over again and expecting a different result."
Digging into someone else’s website
Now that I could reproduce the error with the ad blocker turned off, I formulated a theory of what was wrong with the site. I surmised that the input fields for first and last names must be a React Controlled Component that wasn’t correctly updating React state with their input values. At least, that was my guess based on no evidence other than my twenty years of experience building for the web.
So I opened the dev tools in my browser, navigated to the network control panel, selected JavaScript in the filter and reloaded the page. The total amount of JavaScript loaded by this checkout page:
4.7 MB of JavaScript
That’s right, 4.7 MB of JavaScript code was downloaded, parsed, interpreted and compiled so I could fill out a form. If you think that sounds reasonable, I’ve got news for you. It isn’t.
Being presented with 4.7 MB of obfuscated, minimized JavaScript code, I decided it wasn’t worth the effort to debug the root cause of the issue. Instead, I figured I could disable JavaScript and submit the HTML form, have the server side do validation and fulfill my order. So I turned off JavaScript and refreshed the page.
Nope, nada, zippo, zut, nothing. No HTML form fallback. Instead, all I got was a blank page. There was no way to checkout without JavaScript.
Am I being unreasonable?
At this point, I have to ask the question, “Am I being unreasonable in expecting the site to work with JavaScript?” I mean, everyone has JavaScript enabled, right?
As the above link indicates, there are many reasons why JavaScript may fail in a browser, including but not limited to ad blockers and corporate firewalls. Even without JavaScript, the website owners could have provided an HTML form-based fallback solution so that I could still order my pants. You might think that’s a ton of extra work (it isn’t), and there is no precedence in the real world.
Except there is, and it is called a Credit Card.
Original photo by Avery Evans on Unsplash
Credit cards are a real-life progressive enhancement success story. When credit cards were first introduced, they used these clunky carbon copy swiper machines to make a copy of your credit card number. You then signed the original receipt, which you got to keep with copies going to the store and the bank.
I told my daughter that this is how things used to work, and she looked at me like I was nuts. If you are of a certain age, you will fondly remember the chu-chunk sound these machines made.
Later on, a magnetic strip was added to reduce the paperwork needed to record the transaction. Then it was followed up by the chip and pin approach and finally where we are today with tap to pay. Credit cards have gotten progressively easier to use and more secure.
However, if something goes wrong with the tap-to-pay reader, you can always use chip and pin instead. I’ve seen places drag out those old carbon copy swipers in some rare cases, like when the power is out.
They’ve got it figured out. Once you decide to give them money, they don’t give you any reason not to spend it. So why do we give folks a reason to leave our websites without completing their purchase when we have a reasonable fallback?
Is this common?
Sadly, yes.
Canadian Tire is one of my frequently visited retailers, especially during the pandemic. For those of you who are not familiar with Canadian Tire it is a big box store. It sells more than tires just like Wal-Mart sells more than just walls.
Taking a quick look at its checkout page, I see:
- 4.5 MB of JavaScript loaded
- Shopping cart information doesn’t load when ad block is enabled
- Blank white screen when JavaScript is disabled
Nintendo eStore?
- 4.5 MB of JavaScript loaded
- Works with ad block enabled
- Blank white screen when JavaScript is disabled
Home Depot?
- 4.5 MB of JavaScript loaded
- Works with ad block enabled
- Blank white screen when JavaScript is disabled
The above is unacceptable. Large code bundles correlate to longer load times. Longer load times lead to smaller conversion rates. Maybe major brands like these can afford to drive away customers but can you?
Where do we go from here?
First, start performance budgeting your sites to avoid adding excessive amounts of JavaScript.
Second, test your site with an ad blocker turned on. Recent reports indicated that 26% to 40% of web surfers use an ad blocker. You don’t want to drive customers away because your checkout flow depends on some third-party JavaScript that is routinely blocked.
Finally, if you are building an eCommerce site, think about building out HTML first to ensure that there is always a way for people to pay you. I hear that’s an essential step in making money. If you are thinking about building a new site, why not give the HTML first framework, Enhance a spin?
Oh, and I never did buy those pants.
Addendum
Since my epic failure to secure some pants, the multi-national retailer has fixed the bug that prevented me from completing my order. They’ve also slimmed down the total JavaScript payload from 4.7 MB to 2.3 MB, which is an improvement but still not great. It still doesn’t work without JavaScript.
Top comments (8)
It's not only unreasonable, it is stupid. Using modern frameworks tailored to the job, like MarkoJS or Solid.js / SolidStart (still in beta), you get usable sites even without JS and with far less JS than that.
The main reason nothing works without javascript is "tracking".
Everyone wants things tracked in a way that their marketing team can view the data and make business decisions about that data. Not a single service that tracks things does it without javascript, mostly because it's a freaking hassle trying to do things without javascript. So, i really don't expect anyone to give up their JS code just for the fraction of the population that turns it off on purpose [no one has it off by accident]
Every user wants to claim they don't want to be tracked, but user behavior shows we very much love being tracked and offered things we like and shown content we like versus generic content and ads. It's human nature.
As for the size of the JS code; 2.5MB, 4.5MB, that's really not that much.
Assuming it's a proper ecommerce application with half a dozen payment methods, i expect more event.
It adds up quick and if done right it should be loading the scripts where they are needed. A cart or checkout page is expected to be heavier depending on all the features they require to make their customers happier, drive conversations and keep their marketing team happy with data. That's just business.
Yes, I understand the need to track user behaviour but often, these eCommerce sites over track. For example, Canadian Tire - 13 trackers, Nintendo - 10 trackers and Home Depot has 21 trackers. There has to be a lot of duplication you can get rid of in that situation to reduce the total amount of JS loaded by the page.
All of those bullet points you listed are valid uses of client-side JS, however, you still need to do server-side validation, so your site should still allow people to buy things if JS is disabled or blocked.
I'm not saying you don't do those things. What I am saying is to start with a working HTML form solution and progressively enhance it with JavaScript. If you start with a JavaScript first solution you often have issues with graceful degradation. In some cases, ad block prevents the entire checkout page from rendering. That's bad for business as now folks have no way to give you money.
I don't disagree with what you're saying, but you go and convince Nintendo and Home Depot [massive corporations] to do that when they have 10 levels of people each decision goes through and it usually comes from the top with "implement this or that service" versus "how can we track this more efficiently".
21 trackers is a bit much, but honestly, 10 isn't. Especially if they're using GTM which includes multiple in one. For all you know there's only 3 or 4 services collecting data, but they have multiple scripts firing, each one built by business needs and not giving a crap about 3rd party sites using their scripts.
Business needs always screw up dev wants :) It's nice to want to do that and control it on your own sites, but good luck getting large companies to care about that when it's sooooo far from their bottom line of concerns.
I have worked for massive corporations like IBM and Adobe and it is possible to convince them to do the right thing. Especially when you can correlate reducing the number of 3rd party trackers/JS to faster page loads and higher conversion rates, just because big companies are making this mistake doesn't mean you should too.
Corporations only do this if it benefits their bottom line. Like you said :)
They won't do it if it doesn't benefit the business.
I also didn't say i do it. :) I only make fast websites :)
But project managers and product owners want to use what's popular and is talked about (Angular/React) instead of seeing if there's an alternative that could have added improvement and benefits.
Well, is not really that they want, rather than they're too busy figuring roadmaps, scope creep, legacy code maintenance, and many more other things to care about these user-facing concerns...
Yup, so it is up to us as developers to argue there is a better way for the users and for the company's bottom line.