Hacker News new | past | comments | ask | show | jobs | submit login
Libsass – C implementation of a Sass compiler (github.com/hcatlin)
117 points by kudu on Nov 26, 2013 | hide | past | favorite | 75 comments



Wow, didn't expect to see this at the top of HN. Thanks kudo for promoting the project!

Aaron Leung and I have been working on this for a while. I'm the original creator of Sass and Aaron is a badass computer linguist. Hoping to announce some big new features around the end of the year.

Official site is at: http://libsass.org Or, follow us on Twitter for more updates: @hcatlin & @akhleung


Yes, playing catch-up with Ruby Sass has been difficult (the sophistication and subtlety of some of Sass's features are impressive), but we're hoping to make some big leaps by the end of the year!


Are you planning on creating the sass-convert utility?


I'm sure I'm not the only person who's spent more time than they should trying to decide whether rebuilding sass would take longer overall than just waiting for the ruby one to finish compiling something :)

Thanks for this!


a bit of optimization in $src/libsass/copy_c_str.cpp

        char* copy_c_str(const char* orig)
        {
                size_t len =  strlen(orig) + 1 ;             
                char* copy = (char*) malloc(sizeof(char) * len );
                memcpy(copy, orig, len);
                return copy;
        }


Uh, okay. I didn't read the original, sounds somewhat scary.

Anyway, please don't cast the return value of malloc() in C (http://stackoverflow.com/a/605858/28169).

Also, of course len should be const and sizeof (char) should be removed. Also testing whether malloc() succeeded before relying on the result being valid is a good idea (but perhaps there's machinery in place to abort on error), as is deciding what to do if the input string is NULL.


Anyway, please don't cast the return value of malloc() in C (http://stackoverflow.com/a/605858/28169).

It's C++.


Wouldn't this be even better:

    return( strdup( orig ) );

?


or maybe just #define copy_c_str strdup ?


Thanks, I'll give it a try and benchmark it. Also, pull requests are welcome for this sort of thing!


[deleted]


it will; he allocates and copies strlen()+1 bytes


No problem, thanks for your work on Sass! I suggest linking to the website from the GitHub repo, I hadn't seen it.


JFYI: The link to SassC on http://libsass.org is broken.


This is great as compilation in ruby really is painfully slow for anything substantial, but I wonder about the choice of an independent project vs. forking the ruby compiler and optimizing the bottlenecks with C extensions. Might that allow you to fix the most serious issues without having to worry about maintaining feature parity in a completely separate code base?

In any case, nice work. I look forward to trying it out in my next project.


One benefit of being a separate project is that it can be used with non-Ruby wrappers. See node-sass https://github.com/andrew/node-sass as an example.


And consequently from that project: https://npmjs.org/package/grunt-sass

Since I'd guess most people interested in the node version will want the grunt one.


I have been all too pleased to move away from the ruby based compiler and just use a pure grunt workflow. It is vastly faster and lighter weight.

From what I understand there are some limitations to the implementation, but I haven't encountered any so far.


The few issues I've run into are that I can't use Compass and I can't have Source Maps (yet).

Instead of Compass, I've switched to using Bourbon (bourbon.io) but may consider just using Auto Prefixer in future dev efforts.

Source maps I can live without since I haven't gotten used to them. I know it's in the works or at least being thought about: https://github.com/hcatlin/libsass/issues/122.


Ruby is fast in non-benchmark jobs like text processing. It's not ruby slow, it's sass's implementation of dependency analysis slow. Good compilers in Ruby, like Slim is even faster than most template engines in Javascript or Go.


Can you provide a source for the first statement? It seems unlikely to me that a language implementation is going to be fast on text processing which is essentially a aggregate task of what most benchmarks try to profile individually, but I could be missing something less obvious.


Ruby has many high level text operation abstractions, which is not included in most other languages. But in micro-benchmarks we need to ensure all the languages use the same algorithm, or similar code to do the job. Then the high level methods, which are usually better optimised, are usually forbidden.

In the computer benchmark games (http://benchmarksgame.alioth.debian.org), most of the benchmarks are heavy on floating-point arithmetic or raw loops, which are completely not for the case of web applications. You can also see in text benchmarks like regex-dna, Ruby performs much faster.

If you do benchmarks regardless the implementation details. You may find Ruby can be several times faster than Java in cases like AES encryptions: https://gist.github.com/luikore/7746976 --- though this is not a valid micro-benchmark, it is in fact comparing JCE and OpenSSL. But this is what real-world programs do and the speed of calculating Mandelbrot sets or simulating n-body systems really doesn't matter.


I'm periodically updating a PHP binding to libsass on my companies github account here: https://github.com/sensational/sassphp

It was my intention of keeping up with releases, but it looks like updating it periodically to git HEAD of libsass might be what's needed. I'll look into getting the submodule updated to a later release today.

That said: last summer when I started maintaining this fork of an earlier binding, I noticed that libsass (even tag RELEASE-1.0) was in a bit an early state of development: HEAD was flat-out segfaulting and RELEASE-1.0 was producing miscompilations.

I've reported a few bugs but in the end, we've settled back with ruby sass for the time being. The speed up is nice, but only if the library is actually producing valid output without crashing.

Maybe by now this is better and I should give it another go :-)

Also, I'm certainly no C++ programmer and thus this might be common, but their template based parser with a lot of implementation code in a header file kind of scares me (https://github.com/hcatlin/libsass/blob/master/prelexer.hpp)


We did a lot of development during the summer (including a rewrite that was long overdue), so there were a few segfaults back then. The library should be pretty stable now though -- we've embedded it into our SDK and build system, and it's been working fine.

As for the parser -- that started out as an experiment of sorts. I wanted to do something like parser combinators (but for scanning), and I decided to templatize the whole thing so that all of the scanning code would be generated at compile-time. If I were to redo it, I'd probably use expression templates (which I didn't know about at the time).


For all the Go fans out there, I built a sass watcher/compiler using Go + libsass, I'd love to get some feedback. https://github.com/mfkp/gassy


Given that this is a C++ implementation, why the incorrect article and repo title?

Was it rewritten in C++ later on?

Otherwise, it seems interesting. I'll look into it.


> While libsass is primarily implemented in C++, it provides a simple C interface that is defined in [sass_inteface.h].


To be fair, that argument can be applied to most scripting languages:

A C header for a C++ library that integrates V8 and runs JS code can, according to your logic, count as a C implementation.


No, because it can't be used in straight up C, while C++ libraries that expose their functionality with valid C can.


I'm not a web guy, but isn't sass a CSS generator, as in something you run once before deploying anything? What's the advantage of speed for something like this?


Real world example: our project was taking almost 1 minute to compile via Ruby (all CSS).

Using sassc (libsass) that went to 5 seconds.

Development was where we saw real gains, different sections that would take 4-6 seconds to compile, went down to <500ms (our asset watcher is smart enough to compile only blocks of Sass files that are associated, not the entire site's Sass). Meaning that in the time it takes you to switch to your browser and refresh, the Sass would be compiled to CSS.

Made my devs life much, much better!


Whoa! 5 seconds is still a long time. If you don't mind me asking, how many lines of SASS does the project have?


>22,000 according to wc -l /*.scss (thanks stackoverflow!).

Edit: > 24,000 (counting all files this time ;-)

But I noticed that files missing a newline at the end weren't being counted correctly (missing 1 line in the count).


With a C binding, this library is usable in more or less every language under the sun without messiness.

Written in the correct way, a library like this will compile and run on a 15 year old OS, and will probably run on plenty of OSes in 15 years. The dependency hell of building old language binaries with a dozen badly supported other libraries doesn't exist when you link to libc/libstdc++/etc.

There ought to be a speed advantage, but it definitely isn't the only motivation.


What do you mean by "written in the correct way"?


Written in a way to make the second half of that statement true :)

This involves things like keeping linked libraries to a minimum (and only to use ones which are commonly part of a default unix install), actually testing on a few different platforms, using standard build tools (despite their wonkiness), avoiding (compiler|architecture|OS)-specific features, and all sort of other guidelines that one should follow when trying to write portable software.


So, when big companies like Linkedin generate their Sass projects, it can take hours on a single machine. Tons of programmers all working in Sass.

At Moovweb, some of our customer's projects can take 30 seconds just for the Sass to compile for fairly straightforward sites.


Seriously? I believe you, but if it's taking hours then it seems like the problem isn't as much with SASS but rather the way they write CSS or their build process. If they only recompiled changed files, there's no way it could take "hours".

Even if they recompile everything... all CSS needs to be interpreted by the browser at some point. How much CSS do they have?

That being said, what are the speed comparisons like?


Yeah, I'd love to hear more from Hampton on the hours thing. What actually takes so long? Why does the number of developers matter? I've worked on some substantial (though not LinkedIn-sized) projects that used SASS and I've never clear seconds in compilation time.

Though I completely get the portability aspect.


They use https://github.com/linkedin/archetype which is an extension on top of Compass. Including all those libraries can mean a TON of memory and processing is required. Mixins calling mixins calling mixins. Plus, custom ruby extensions, etc. The needs of organizing hundreds of developers logically and making sure the code is optimized can be a hauss.


Thanks.


Hours?

Either they have several gigabytes of CSS output (ouch) or they're using a ZX-Spectrum as a build machine. Or, possibly, they're constantly recompiling, like doing a change in SASS a hundred times per second.

Otherwise, interpreted script-based parser (given that it's written properly, algorithm-wise) should be sufficiently performant to produce results in a sane time.


Ok, that's more drastic than I thought. I think I get the point now.


Saves a bit of time when you're in the edit your scss/sass files -> refresh browser workflow. A designer friend of mine always complains about how slow the ruby sass compiler is for larger projects, but he says the time saved in writing stylesheets with it beats the time spent having to wait for them to compile.


On huge projects, Ruby Sass can be quite slow, taking several seconds or even minutes to compile. If you have an interactive, iterative workflow where you're constantly refreshing the styles, having a faster Sass compiler can be a godsend.


Every tiny change requires a recompile. On a really complicated site, that could be 30 seconds or more. And CSS is a >visual< language, that looks subtly different in all browsers and eventually requires a lot of 'stabbing in the dark' to find the perfect compromise.


If you were making small changes to see what worked in different browsers, rather than editing the CSS or SASS, it may be more beneficial to use the browser's Web Tool to do it live!


Yes, but only when you are making small changes to a single, and relatively static, page. And, you need to make the same changes in every browser at once. And, then you need to verify that the css changes you made correspond to the sass changes you make in the main document.


Depends. Many newer frameworks (Rails, at least, specifically) do not pregenerate but instead compile on the fly and then cache, at least in development mode.

Also, the canonical SASS implementation is in Ruby, which is a fairly heavyweight dep if you need it JUST for to compile SASS


Faster deploys means more deploys means more features and fixes and a better chance of survival. See: John Boyd.


Speed of deployment, especially for larger sites with more CSS to process.


If you're in a language that allows C bindings, then it makes it easier to port a SASS library to that other language.



I've been maintaining a Perl binding to libsass.

CPAN page here: http://search.cpan.org/perldoc?CSS%3A%3ASass

Github here: https://github.com/caldwell/CSS-Sass


Let's get down to brass tacks—is there a ruby gem which can use this and drop into the Rails asset pipeline to speed it up? If not, what would be the best way to get that started?

Edit: found this: https://github.com/hcatlin/sassruby -- Looks like it's not quite mature enough, but promising!


> is there a ruby gem which can use this and drop into the Rails asset pipeline to speed it up?

Often the source of slowness in the asset pipeline is not the compilation but the asset pipeline itself. It does some weird stuff.

I'd imagine dropping a libsass based SASS compiler into a Rails app wouldn't actually translate into much of a performance improvement.


Any contribution to the project are seen as copyright assigned to Hampton Catlin, a human on the planet earth. Your contribution warrants that you have the right to assign copyright on your work. The intention here is to ensure that the project remains totally free (liberal, like).

That's a curious setup. The license is MIT so you're not getting the "if you distribute it you have to use the same license" that you get with GPL. So as long as the contributions use the same MIT license why does the author need copyright assignment? The MIT license is simple and standard enough that relicensing doesn't seem like a likely need.


Good question. I've gotten conflicting legal advice. Some say I need full signed contributor agreements for everything, no matter the license, and some say that's not needed at all. I opted for something in-between. Just a notice that could cover our ass in the future. Several big companies are working on submitting code, and so licensing there can get tricky... hence, just go overkill and never worry about it. ;)


Thanks for the reply. That makes sense. I don't see why saying "anything that's contributed is MIT licensed" wouldn't cut it but I'm no lawyer... :)


Unfortunately it only implements the curly-brace SCSS syntax, not the indented SASS syntax [1] (which is weird considering it's called Libsass, not Libscss), and there are no plans to support both syntaxes.

The companies I have worked for all use the indented syntax, since it meshes very well with HAML and CoffeeScript. But it looks like more people use the brace syntax (roughly 980k SCSS files on Github, vs. 85k SASS files).

[1] https://github.com/hcatlin/libsass/issues/16


I agree about fitting in well with HAML and CoffeeScript. You might also consider Slim as a less noisy HTML shortcut language.

This covers why I like Slim over HAML

http://me.phillipoertel.com/articles/2013/02/03/why-i-like-t...


I don't know. I wish developers could stop reinventing/tweaking stuff that isn't particularly broken (the differences between HAML and Slim, for example, are marginal and not really interesting) and start standardizing on something. Node, meanwhile, seems to have standardized on Jade.


We do want to support the indented syntax eventually (and I believe it should be possible with a relatively simple pre-processing step), but it's still a low priority compared to reaching feature parity with the canonical implementation.


I know this is completely juvenile of me, but I can't help but see "libs ass".

It's kind of like "xbone". I'm sure it's not intentional, but people will see it nonetheless.


So, three months ago they started using Travis CI and, as far as I can tell from looking at the results (https://travis-ci.org/hcatlin/libsass/builds), not once have the tests actually passed. (Builds 1 and 2 failed silently and build 8 didn't test anything. The rest were all detected as failing.)


Ah, that's because Travis is running all of the "to-do" tests as well. Reorganizing the tests and making Travis happy is ... well, it's on the to-do list.


Yeah, its run against the WHOLE sass spec!

Also, thanks for the supportive post!


It looks like C++ to me.


Do wanted to note that this does not work with Compass currently as Compass extends SASS with Ruby.


Are you aware of any plans for Compass to remove the Ruby dependency?


I don't know, but I suspect it doesn't looks positive. Compass haven't had any new releases for a year now.


Not true--there have been a series of alpha and now RC releases of 0.13. Chris and Nathan and the others are working on both Sass and Compass in parallel.


Thanks!

I just tried the pre-release version of 0.13. I found it was installing something with native binding? I believe it was one of the dependencies on Compass. I don't think this works well for us as our build process relies on Maven with JRuby to power Compass.


I think a better direction would be for projects to remove their compass dependency.


I really want a pure js impl.


Write one :)




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: