You're running a legacy codebase, supporting browser from 2013 and you want to avoid that your users are unable to use your service with your next release or you want to enrich your user experience with a new feature, but not writing more legacy code and not ship more polyfills.
Here is my approach how to write code in 2021, even on existing codebases.
the unused code dilemma
Modern browsers do not need many polyfills and on executing of you bundle, they skip the polyfills they do not need, resulting in unused code. Another flavour of unused code are components which are bundled but not used on that page for example.
The screenshot above is from the stackoverflow homepage and chromes code coverage tool. A high unused code number does not always points out a problem it is more a sign that a deep dive into that bundle might be valueable.
whose impacted the most?
Assuming you ship polyfills to support IE11 plattform, this code will run on a desktop machine, a desktop cpu & ram environment. Maybe the hardware is a little bit outdated and this audience might be used to "wait a little" for webpages to respond.
But chances are real that this audience may able to upgrade to a modern browser, but as long as the page is working on the old browser, there is no need to meet a new browser.
A good read on that topic is "The Mobile Performance Inequality Gap, 2021".
de-bundling vs caching vs unused code
With http/2 a GET-request is not that expensive anymore, a good idea might be de-bundling your assets (css and js) and deliver only page-needed assets.
On the other hand you will feel on every subsequent page that more assets need to be downloaded, which makes a next page feel a little bit slower.
So you might think it is a good practice to bundle all js and css into one big file each, ship it on first impression, the browser caches it and every subsequent page feels fast. But some visitors will not visit any second page, because the first impression with all that unused but downloaded, parsed and executed code they were scared away.
steps of gracefully upgrading your codebase
step 0: keep focus on developer experience
I assume some people can create highly optimized build pipeline to split everything into its pieces and polyfilling here and there where it is needed, maybe on serverlevel (node,nginx,apache,etc.) regarding every requests' user agent.
Coming from a polyfilled one-for-all-bundle you should go one step by another and always take all team members with you. By setting up a pipelined tooling like this, local developing may becomes unpleasent.
If you keep local developing pleasant it will directly improve your codebase quality because every developer understands the whole buildingprocess and feels more home with it. If a build pipeline does code optimization, some might get lazy during developing because "it is handled in build step X".
step 1: tell your user as soon as possible about it
As soon as you make the decision to write code that might not run in your current audience browser, add an info icon that tells your users, that upcoming versions might not work in their browser and give a hint to up to date browsers.
At least provide the 4 major browsers in that list (firefox, edge, chrome, safari) and when you know about specific browsers your visitors like to use, add this to.
For example: the next big version will use es modules - tell your user about it, even if your roadmap tells q3 2022 for that feature.
You want to build a new feature with a modern js framework, tell users which might not be able to use this feature with their current browser.
step 2: use progressive enhancement technologies
Don't read a
user agent and decide if your code will work in future or not. Make yourself a list of features you are using and build a custom shaped feature detection script to match every users browser to meet your requirements. In the early 2010's we usually put a modernizr copy into the
<head> and used nearly nothing from it. So check only for features you will use and keep that list updated.
And, as I wrote in step 1, tell your visitors as soon as possible that they might run into trouble with their current setup.
For example: the next version or a feature will user CSS custom properties. Add an feature detection script and let your visitors know about it.
step 3: include only what is needed
This advice aims to 3rd party plugins or frameworks. Always keep an eye on the size of anything 3rd party you use in your project. I use bundlephobia with every new package I include into a project. For example if you need a markdown processor in your frontend you can choose between snarkdown or markdown if both fullfill your requirements.
By using a ui-framework, for example bootstrap, you should only import that css and js code, which is used in your project, and do not import all of it.
step 4: after the launch
You released that feature or the next version and finally some browsers are not able to run your project anymore.
Now it is important to keep that feature detection and user hinting advice in your project. Add a little vanilla js/css/html code to your project, which works in all browsers and telling your visitors to upgrade their browser, if an error occurs.
As soon as you put out the unsupported browsers of your quality-assurance line you do not see how your project is rendered on this browsers and you might be suprised what an IE11 will render to the user. A server side rendered js framework page will create some output, a client side rendered js framework page will lead to a blank? page but maybe there is a static header and footer which is displayed.
So make sure to catch every user whose browser got trouble consuming your site and provide information how to visit your page probably.
step 5: track this data
In every step before, you must track users whose browser is not able to run your page probably. You might think that IE11 is your problem, but by collecting every user running into an non working page, you get out of this "Browser XY is blocking us to move on" and you start to address your codebase issues.
With that data, you can make edjucated guess' if you need to include one more polyfill to cover more visitors.
When upgrading your codebase from legacy to legacy@next ;-) you should inform your users as soon as possible when there is a plattform support change.
Do not use any kind of user agent sniffing to adress not supported plattforms, use accurate feature detection to find all unsupported browsers.
Keep an eye on every 3rd party codepieces and check if there is a lightweight alternative for that usecase.
Track all this data and adjust your codebase if you find a user setup that did not meet your requirements and you were not aware of.
You might be interested on that read: "Remove dust from a legacy project" here in this blog.