About “Zero Dependencies”

Andrea Giammarchi
6 min readApr 12, 2020

--

There’s a (not really) new trend of describing “zero dependencies” on the Web, especially when it comes to components. This post is just about analyzing the real meaning of “zero dependencies” applied to the Web.

Once upon a time …

There were few groups of professionals responsible for defining standards for the masses, with at least these goals in mind:

  • ensure great accessibility to be as inclusive as possible
  • ensure a great amount of customization, either UI related or behavioral
  • ensure backward compatibility, aka long term support out of the box

These people provided at least 3 great technologies to address these points: HTML, CSS, and JavaScript.

These technologies can be basically copy/pasted around the globe, and work as expected in mostly every possible device on earth.

Modern Web Development

Bundlers, libraries, helpers, frameworks, compiler, pre-processors, post-processors, nowadays nobody seems to deal directly with those 3 primitives anymore, and the majority of the teams are used to bloat their toolchain to simplify their daily tasks, trusting the framework, or any library of choice, to end up doing the right thing on the standards side.

I’m guilty myself on this regard, ‘cause’ I don’t code anymore 100% raw standards and I use, or develop, helpers, whenever I find those convenient.

Pseudo Dev Dependencies

If we are using some module to build and deliver our project, it’s OK to have these kind of dependencies. However, if other projects would also need one of our dev-dependencies in order to consume our offer, that’s a proper toolchain dependency … examples:

  • requiring the usage of TypeScript is a toolchain dependency
  • requiring the usage of Svelte is a toolchain dependency
  • requiring the usage of React is a toolchain dependencey
  • requiring the usage of Babel, Rollup, or any other out-of-the-box bundler, is a toolchain dependency

The consumers of our project must make a decision: add these dependencies into their workflow, or look for something else.

Of course, if a project is widely adopted, those developers won’t have any friction in using our offer, but we can’t really say sentences like:

“it has zero dependencies, other than React”

Or better, we could say that, sure thing, but React is not a library you can consume by simply including a <script> tag in your HTML page, and its whole layout is not something you can copy and paste somewhere else and get it working right away.

React, as well as Svelte and many others, require toolchain support to both create and consume components, and while this is fine, it’s far away from being a “zero dependency”, as it’s rather closer to a dependency lock-in.

Are we OK with being locked-in behind the scene to deliver what we need? Great, let’s keep shipping awesome stuff, remembering that what we consider “zero dependencies” is, however, a lie we don’t need to tell ourselves.

Client Side Dependencies

While needing to setup a toolchain to have something working can be considered the least portable solution across teams or already live projects, many other projects offer that “plug and play” simplicity brought in by the Web platform: we add a <script> tag, eventually a <link> one too, and we’re ready to go 🎉

Let’s take bootstrap as example, just to name one apparently used by 20% of the entire Web, and think about the following:

it has zero dependencies, other than jQuery

See? Here we go again, we’re locking-in ourselves behind a library this time, and if we’re OK with that, we can keep working with bootstrap and maybe drop any other library that does things in a jQuery fashion/style, as those will be redundant, while we want to keep our code DRY and consistent, right?

The key-difference with this approach, compared to the “need for tool” one, is that copy/pasting layout and scripts across multiple sites will just kinda work, making our components portable for every occasion.

As a matter of fact, that’s indeed the biggest strength of bootstrap: it’s portable, and it can be incrementally adopted; it doesn’t need any special tool to work in already existing projects and, since bootstrap covers 1/5th of the entire Web, we can safely say that this approach has proven to work.

The Library Size

Currently, jQuery weights between 24K, slim version, and 30K, once minified and gzipped, and while that’s not super lightweight, it’s also not so bad, if we consider the ideal performance budget of 170K.

The best part of having one library across multiple components though, is that its size gets incrementally dissolved.

Two bootstrap based elements would use the same jQuery version, and so will three, splitting those 30K into 15, 10, … or 1K, if we have 30 components.

Now imagine using uhtml instead, or even uce, which is 3K, so that we can use 99% of that 170K budget for our own components 😉 … back in the topic!

Zero Dependencies … maybe

If we deliver pure CSS without needing any toolchain, and we do the same with JavaScript and HTML, we can finally claim the following:

“it has zero dependencies, other than a browser”

Achievement unlocked: we have the most Web portable code of them all 🎉

When it comes to components though, the best primitives to do so are Custom Elements, and these might require polyfills, so that here we go again:

“it has zero dependencies, other than a polyfill”

The whole difference between a polyfill and a library is that the former costs zero extra bytes in the long term, and it doesn’t require any work to be dropped later on: you literally remove that <script> tag once the time is right, and call it a day, hence it’s an easy win for everyone!

Regardless, we’re back into having some dependency, even if it’s one that is more convenient, as it’s never on our way, and doesn’t ask us to write code any differently than the way we’d do with standard JavaScript.

What Is The Best Option?

It depends. Writing JS without any library/helper is the closest approach to “zero dependencies”, but this approach usually fails in delivering a better experience if all internal common helpers are bundled per each component.

In such case, using a common library that helps simplifying most tasks pays back if the amount of components is bigger than 2 but, of course, the smallest the library, the better, and I suggest max 10K for any library/helper.

It’s also worth saying that while Custom Elements are the best platform primitive to create sharable components across the Web, bootstrap, as well as wickedElements and hookedElements, are all about graceful enhancement, removing the need for polyfills, hence providing an alternative that’s also still far away from the “zero dependencies” myth.

On the other hand, the tiny and mighty uce simplifies Custom Elements built-in creation, meaning it can incrementally enhance regular elements on demand so that the HTML page would have virtually “zero dependencies”, and only compatible browsers would eventually see enhancements, in case we don’t want to include a polyfill.

However, if everything we do is based on React and we’d like to share components based on such stack, we should just go ahead, as React is something we consider a core dependency anyway, so that similarly to the bootstrap + jQuery case, its weight will be irrelevant, yet let’s keep the 170K max initial bundle size in mind.

And Svelte is not different: as long as it’s understood developers needing Svelte components need to add Svelte in their pre-processing flow, and the same goes for Vue.js and friends, we shouldn’t bother too much with portability: we’re locking-in our components behind a tool-based stack, instead of a runtime library/helper.

As Conclusion

Creating Web pages or components can be done in many ways, and in the latter case, adding just another script or helper to make such components work is more than fine, as long as the production size is kept under control, which is all JS in < 170K for the first meaningful script.

Using tools to either consume or create components is fine too, and it’s also OK to combine all these techniques together.

After all, the goal should be to create the best possible experience, ideally for both developers and users, and thankfully there are so many helpers to do so.

Keep aiming at this “zero dependencies” Chimera though, is kinda wrong, ’cause it’s always practically a lie we don’t need to tell ourselves.

It’s OK to have the right amount of dependencies for a project, accordingly to its needs, and we should stop being afraid of dependencies: as simple as that.

--

--

Andrea Giammarchi

Web, Mobile, IoT, and all JS things since 00's. Formerly JS engineer at @nokia, @facebook, @twitter.