Why Node Sass broke your code and SemVer

I had hoped this post would never be needed. However as is often the case what we maintainers assume is common knowledge in reality is far from it. Firstly lets make sure we’re on the same page.

What is Node Sass

Node Sass is a Node.js implementation of the hugely popular Sass project, except that it’s not. Actually Node Sass is a very thin JavaScript layer on top of LibSass, which is a C/C++ implementation of the Sass Language.

We are Sass

Sass is both a language and a compiler. The Sass compiler is written in Ruby and although being nearly ubiquitous in our industry, it has long been plagued by slow compilation times.

Originally started by the creator of Sass, Hampton Catlin, LibSass is C/C++ implementation of the Sass language. In leu of a formal language specification our goal is simple, and we’re very close.

Produce semantically equivalent CSS to that of the Sass compiler

LibSass, along with Node Sass, are official Sass Foundation projects and we work closely with the Sass team to ensure we are able to meet this lofty goal.

The advantage of building a C/C++ implementation is that most languages can easily interface with it. As a result we’ve seen an explosion of Sass implementations in .Net, Perl, Python, Java, Haskell, Php, Go, and even Ruby! This is only possible because these libraries defer the work of compiling Sass code to CSS to LibSass, and focus their efforts on building APIs for their respective languages.

LibSass is a Sass compatible language implementation. This means we have entered into an agreement that code that compiles with the Sass compiler, will produce semantically equivalent CSS when compiled with LibSass, and vice verse. This has a couple interesting properties for what constitutes a bug in LibSass

  • if Sass code that compiles with the Sass compiler fails to compile with LibSass, it’s a bug.
  • if Sass code that compiles with the Sass compiler and LibSass but results in semantically different CSS, it’s a bug.
  • if Sass code that compiles with LibSass fails to compile with Sass compiler, it’s a bug.

The last point is important, and is the focus of this post.

SemVer

Whenever anyone choses to use open source software they’re entering into a contract. In the Node.js community this contract, for the most part, is semantic versioning (SemVer). It’s a simple contract

  • we the maintainers promise not to make changes to documented public APIs that may knowingly break your code without a major version increment.
  • we the user promise to only use the documented public APIs, and not get angry when an undocumented API changes breaking our code.

The recent v3.5 has caused some Sass code that previously compiled fine with Node Sass, to start throwing fatal errors. Many of you reading this, and angrily opening issues see this a gross violation of SemVer — and by extension our contract with you.

The newly introduced fatal error is with regards conditionally defining mixins, functions and imports.

This is something that is not now, or ever, been allowed in the Sass language. Having said that these invalid operations had previously worked in LibSass and were reported as bugs which were promptly fixed.

Mistakenly allowing this was a violation of our agreement to be compatible with the Sass language since this code would not have compiled the Sass compiler.

Relying on bugs is no different to relying on an undocumented API and violates your contract with us.

We’re sorry

Firstly I want to start by saying we, the LibSass and Node Sass teams, understand why you’re angry and we’re sincerely sorry for any difficulties we’ve caused you.

With that said we stand by these changes, and ask for your understanding.

If your code does not compile with the Sass compiler, it is broken, and will eventually break in LibSass and Node Sass without warning.

Performance Engineer at 99designs. Maintainer of LibSass and Node Sass.

Performance Engineer at 99designs. Maintainer of LibSass and Node Sass.