Adding modern JavaScript to legacy projects

Modernize your stack incrementally to reduce pain and inflammation

Upgrading old sites ain’t easy! In this series, you’ll learn how to incrementally add Vue.js to a legacy website. Part two is live!


Here’s a question for ya:

Do you need to be working with a blank slate to adopt a new front-end framework like React or Vue?

Many of the resources you’ll find about these technologies are written with the assumption that you’re starting a brand new project. While that’s helpful when you have the opportunity to start a project from scratch, the reality for most teams is a bit more complicated.

Here’s the reality for most of us:

  • We have lots of old projects sitting around with aging jQuery scripts that handle form submissions, sliders, YouTube videos, etc.
  • We want to learn new technologies and best practices, but our existing projects still need maintenance and new features
  • It’s not really practical to revamp our existing toolchains/build processes on these old projects for the sake of modern JS
  • Our customers’ needs and priorities change as our projects age, which sometimes means developing new features and functionality quickly

In that context, does it make sense to add modern frameworks to old projects, or should we just pile a few more noodles onto that delicious, delicious jQuery spaghetti? (Everybody does it, DON’T YOU ACT LIKE YOU DON’T. 🍝)

This is a question that only you can answer, as your users’ and clients’ needs are totally unique. But I’d argue that in some circumstances, it makes perfect sense to introduce a new framework like React or Vue, or any of the other super hip frameworks du jour, to an old project.

In fact, once you learn some basics, frameworks can help you get more work done at higher level of quality than if you’d piled on yet another jQuery plugin. (Side note: If we write jQuery spaghetti, what does that make jQuery plug-ins? jQuery meatballs? ¯\_(ツ)_/¯)

It might make sense to add a new framework into the mix as soon as your client requests any functionality that involves lots of state.

So how can we add new functionality based on new frameworks without breaking existing code, or otherwise making a mess of things?

Disclaimers

First, let me get this out of the way:

I’m not advocating that you add dependencies and complexity to your code all willy-nilly. Be thoughtful when adding any dependency (and therefore weight and technical debt) to your codebase.

For that matter, if you are dealing with an older codebase that has lots of jQuery spaghetti, have you looked into refactoring to make it more modular and sensible? Are you architecting your programs in a way that’s kind to future-you (and your teammates), and especially your users? Have you implemented coding standards or style guides?

There are lots of ways to create new functionality without adding dependencies. The question is ultimately: are the costs of adding a new tool worth the benefits to you and the users of your software? The answer to this question will vary from project to project and from developer to developer.

I’m just writing for those of you who might have decided yes, it’s worth it, but no, you’re not sure how to proceed, because so many dang tutorials assume you’re working on brand spankin’ new projects.

A brief word on framework choice

I like Vue because the runtime is smaller than React and React DOM (at around 59kb minified, it’s even smaller than jQuery!), its API is nice, it’s fast, and writing Vue templates and components feels like writing regular ole HTML, CSS, and JavaScript. No need to bend over backward to get it working with the DOM, or modern standards like Web Components. It’s generally a pleasure to work with. The docs are also really good.

So this tutorial series will be focused on Vue, but the principles are basically the same no matter what framework you choose. There’s no shortage of options out there. Enjoy React but worried about file size/performance? Preact is great. Interested in learning functional programming? Elm is cool. Prefer something tiny, event-driven, and DOM-centric? Choo’s got your back.

It doesn’t matter. Ultimately, most modern front-end frameworks help us:

  • Build complicated interfaces declaratively
  • Write more modular, maintainable, DRY code (AKA become a better developer)
  • Learn new skills and concepts that are useful outside the JavaScript framework party

They’re all useful tools. Don’t buy into the hype of any one framework; pick one that makes the most sense for you, and run with it.

jQuery is fine, seriously

I’d also like to note that frameworks and jQuery are not mutually exclusive. You can use them in tandem. jQuery makes DOM manipulation super duper easy. There is nothing wrong with that, despite what all the cool kids of JavaScript would have you believe.

jQuery gets a bad rap because so much terrible code is written with it, but it is a mature, flexible, awesome tool. If having the additional global dependency and 80-odd (minified) kilobytes makes sense for your use case, use it!

If you can eliminate jQuery (spaghetti) and requisite plug-ins (meatballs), by all means, do it. Frameworks and modern DOM APIs can obviate the need for jQuery. But don’t drop jQuery just because it’s “bad” or whatever. Use what works.

Alright, that’s it for disclaimers.

Let’s get started.

The scenario

Let’s say your client comes to you (or your boss) and says they need to add an ecommerce element to their site. Their business is expanding to sell a single, configurable product over ye olde interwebs. They don’t want to change the existing site for now, besides adding new functionality, and they don’t want to build a new site—too expensive.

Okay, cool. This is an old site with some jQuery functionality (maybe the contact form submits with jQuery.ajax and you’ve built some UI effects with jQuery.animate) and basic build tools, and now you need to add this new product configurator widget to the site. You work with UX and the client to come up with the following functional requirements:

  • Configurator opens in a modal
    • The user can dismiss the modal with the “Esc” key, by clicking outside the modal, or by clicking a “Close” button
    • If the user closes the modal, it should save their changes automatically and load them if they reopen the modal
  • Base configuration of the product is already set
  • The customer can adjust:
    • Product width and height
    • The size will have an upper limit of 600 on both axes, and a lower limit of 50 on both axes
    • Text on the product (up to the length of a Tweet)
    • Color scheme of the product
    • Three default color schemes, plus an option called “Custom”
    • Color pickers will appear for each color in the color scheme only if the “Custom” color scheme is selected
    • The product image will update as soon as a new color is chosen, text is written, or size is adjusted
  • The price should adjust dynamically based on the options the user has chosen
  • A “reset” button resets the configurator to its default state
  • An “Add to Cart” button adds the product to the user’s shopping cart
  • This should be reusable and extensible, in case the client needs to add more products or change existing ones

Yikes. That’s a lot of variables to work with.

How would you do this with vanilla JavaScript and jQuery?

You’d probably have to create some sort of event system to dynamically notify disparate parts of the UI as the user makes changes. You’d also need to figure out quick, efficient ways to swap out or update DOM elements, based on those events (which are ultimately tied to your application’s state).

You could do all that, but you may also know from experience that building something like that from scratch is tough and time-consuming work. You encounter unexpected bugs and edge cases, UI glitches happen when application state and your UI are out of sync, and once it’s done, since it’s totally bespoke, there’s not much documentation for your teammates (or future-you) to follow. It also wouldn’t be abstract enough to use across multiple projects.

In short, building things like this can be a nightmare that takes much longer than you initially anticipate, and comes with hidden costs.

Frameworks are built to solve all these problems in consistent, standardized ways, with plenty of documentation. So you decide to use one, instead of reinventing the wheel.

Vue doesn’t really require changes to your build process, depending on what you want to do with it. You can drop it in as-is. So, Vue it is.

You have a couple of weeks to get this feature out; you check out the codebase, create your feature branch, and you get to work.

To be continued

This post is 1500 words deep, but we haven’t written any code yet. I know, I know. We’ll get there.

In the next post, we’ll introduce Vue to our codebase simply, without changing our build processes or otherwise making our lives miserable.