Skip to content

Releases: css/csso

1.5.4

27 Jan 12:43
Compare
Choose a tag to compare
  • one more fix (in restructRuleset this time) with merge of rulesets when a ruleset with same specificity places between them (#264)
  • disable partial merge of rulesets in @keyframes rulesets (until sure it's correct)

1.5.3

25 Jan 12:16
Compare
Choose a tag to compare
  • don't override display values with different browser support (#259)
  • fix publish issue (one of modules was published in development state)

1.5.2

24 Jan 20:09
Compare
Choose a tag to compare
  • don't merge rulesets if between them a ruleset with same specificity (#264)

1.5.1

14 Jan 23:08
Compare
Choose a tag to compare
  • ensure - is not used as an identifier in attribute selectors (thanks to @mathiasbynens)
  • fix broken justDoIt() function
  • various small fixes

1.5.0

14 Jan 20:53
Compare
Choose a tag to compare

The main changes of this release are about compressor. It significant refactored in two aspects: code simplicity and performance. Also a new AST format for compressor was introduced.

Let's start with clarification on the new AST format. As you may know csso uses gonzales to parse CSS to get AST. In the past it was one of fastest detailed CSS parsers written in JavaScript. But now gonzales isn't fast enough and hasn't support for some new things that were added to CSS last years. Further more gonzales uses arrays to describe AST nodes that isn't verbose, slow and expensive for memory. Also its format has several design mistakes and unsuitable for transformations as well.

Therefore, the replacement of the parser became obvious. But it isn't so easy since every single part of csso depends on AST format. Another problem is there is no suitable detailed CSS parser that can be a replacement for gonzales. So I have started working on this sort of parser a сouple of months ago. But still a lot of work to be done. Until that I decided to do first step for parser replacing by introducing new AST format (for now for internal usage only). Currently gonzales is used for getting initial AST which after that is converted into internal format. Theoretically it's possible to write AST convertors for other parsers too. Thus csso became less dependent on the parser.

Actually new format appeared in the middle of refactoring to simplify code and improve readability. But first tests showed performance boost too despite AST conversion overhead. That was the sign that we are on the right way.

Earlier source code of compressor was too complicated and was located in a single file. Now it is splitted into simple modules grouped by phase of processing: cleaning, compressing and restructuring. It makes dealing with compressor's source code much easier. Moreover, beside improved readability, the new AST format helped to simplify the source code since this format uses objects instead of arrays to describe AST nodes, has no redundant things and much more suitable for transformations.

Before we talk about performance, let's look at comparison table first (the table is based on css-minification-benchmark):

Library 1.4.4 1.5.0 Diff
960.css (9989 bytes) 142.71 ms 116.89 ms 1.2
animate.css (71088 bytes) 432.12 ms 290.27 ms 1.5
blueprint.css (17422 bytes) 179.81 ms 150.66 ms 1.2
bootstrap.css (147427 bytes) 1022.78 ms 547.48 ms 1.9
font-awesome.css (28746 bytes) 173.37 ms 93.74 ms 1.8
foundation.css (200341 bytes) 1308.3 ms 648.62 ms 2.0
gumby.css (167123 bytes) 1537.72 ms 452.67 ms 3.4
inuit.css (53049 bytes) 160.17 ms 103.83 ms 1.5
normalize.css (7707 bytes) 10.73 ms 9.58 ms 1.1
oocss.css (40151 bytes) 111.71 ms 75.98 ms 1.5
pure.css (31318 bytes) 132.55 ms 76.67 ms 1.7
reset.css (1092 bytes) 24.15 ms 7.2 ms 3.4

As you can see, csso 1.5 is about 1.2–3.4 times faster than previous version. Take in account that those numbers contain time of all operations, i.e. parsing, compression and translation. In 1.4 compression takes more than ¾ of total time, but the new version takes less than a half of it. In fact compression become much faster than changes in total time because parsing takes significant time (one more reason to change parser) and has not changed.

As was mentioned above, some part of the performance boost due new AST format. It's not the single optimisation. Restructuring algorithms were also improved, redundant calculations and actions were removed, creating and copying of data structures was reduced, various caches and indexes are using now, some heuristics based on CSS specifics were used. Also final restructuring steps perform without a loop now. This loop was very expensive because snapshots (AST translating to string) were made in the beginning and in the end of each iteration and compared to check that iteration has good progress. It led to a lot of memory consumption and , even to processing freeze on large files. For example test file (3.7Mb) in issue #201 was never processed whereas now it takes about 12 seconds to be done (not so good but better than infinity). It is also worth noting that memory consumption has also been reduced by more than a half.

It's not the end of the compressor refactoring. The restructuring algorithms still need to be replaced for better ones that produce better results. More optimisation could be done when the parser will provide more details about CSS structure. So new improvements are coming.

Change log

Parser

  • attach minus to number

Compressor

  • split code base into small modules and related refactoring
  • introduce internal AST format for compressor (gonzalesinternal and internalgonzales convertors, walkers, translator)
  • various optimizations: no snapshots, using caches and indexes
  • sort selectors, merge selectors in alphabet order
  • compute selector's specificity
  • better ruleset restructuring, improve compression of partially equal blocks
  • better ruleset merge – not only closest but also disjoined by other rulesets when safe
  • join @media with same query
  • outputAst – new option to specify output AST format (gonzales by default for backward compatibility)
  • remove quotes surrounding attribute values in attribute selectors when possible (issue #73)
  • replace from0% and 100%to at @keyframes (#205)
  • prevent partial merge of rulesets at @keyframes (#80, #197)

API

  • walker for gonzales AST was implemented

CLI

  • new option --stat (output stat in stderr)
  • new optional parameter level for --debug option

1.4.4

10 Dec 12:13
Compare
Choose a tag to compare
  • prevent removal of spaces after braces that before identifier that breaking at-rules expressions (#258)

1.4.3

04 Dec 20:47
Compare
Choose a tag to compare
  • fix unicode-range parsing that cause to wrong function detection (#250)

1.4.2

09 Nov 21:05
Compare
Choose a tag to compare
  • allow spaces between progid: and rest part of value for IE's filter property as autoprefixer generates this kind of code (#249)
  • fixes for Windows:
    • correct processing of new lines
    • normalize file content in test suite before comparing
  • fixes to work in strict mode (#252)
  • init compressor dictionaries for every css block (#248, #251)
  • bump uglify-js version

1.4.1

20 Oct 20:28
Compare
Choose a tag to compare
  • allow merge for display property (#167, #244)
  • more accurate rect (clip property value) merge
  • fix typo when specifying options in cli (thanks to @Taritsyn)
  • fix safe unit values merge with keyword values (#244)
  • fix wrong descendant combinator removal (#246)
  • build browser version on prepublish (thanks to @silentroach)
  • parser: store whitespaces as single token (performance and reduce memory consumption)

1.4

16 Oct 14:52
Compare
Choose a tag to compare
1.4

Back project to life. Changed files structure, cleaned up and refactored most of sources. Closed 60+ issues.

Common

  • single code base (no more src folder)
  • build browser version with browserify (no more make, and web folder), browser version is available at dist/csso-browser.js
  • main file is lib/index.js now
  • minimal node.js version is 0.12 now
  • restrict file list to publish on npm (no more useless folders and files in package)
  • add jscs to control code style
  • automate gh-pages update
  • util functions reworked
  • translator reworked
  • test suite reworked
  • compressor refactored
  • initial parser refactoring

API

  • new method minify(src, options), options:
    • restructuring – if set to false, disable structure optimisations (true by default)
    • debug - outputs intermediate state of CSS during compression (false by default)
  • deprecate justDoIt() method (use minify instead)
  • rename treeToString() method to stringify()
  • drop printTree() method
  • AST node info
    • column and offset added
    • ln renamed to line
    • fix line counting across multiple files and input with CR LF (#147)

CLI

  • completely reworked, use clap to parse argv
  • add support for input from stdin (#128)
  • drop undocumented and obsoleted options --rule and --parser (suppose nobody use it)
  • drop -off alias for --restructure-off as incorrect (only one letter options should starts with single -)
  • new option --debug that reflecting to options.debug for minify

Parsing and optimizations

  • keep all exclamation comments (#194)
  • add /deep/ combinator support (#209)
  • attribute selector
    • allow colon in attribute name (#237)
    • support for namespaces (#233)
  • color
    • support all css/html colors
    • convert hsla to rgba and hls to rgb
    • convert rgba with 1 as alpha value to rgb (#122)
    • interpolate rgb and rgba percentage values to absolute values
    • replace percentage values in rgba for normalized/interpolated values
    • lowercase hex colors and color names (#169)
    • fix color minification when hex value replaced for color name (#176)
    • fit rgb values to 0..255 range (#181)
  • calc
    • remove spaces for multiple operator in calc
    • don't remove units inside calc (#222)
    • fix wrong white space removal around + and - (#228)
  • don't remove units in flex property as it could change value meaning (#200)
  • don't merge \9 hack values (#231)
  • merge property values only if they have the same functions (#150, #227)
  • don't merge property values with some sort of units (#140, #161)
  • fix !important issue for top-right-bottom-left properties (#189)
  • fix top-right-bottom-left properties merge (#139, #175)
  • support for unicode-range (#148)
  • don't crash on ruleset with no selector (#135)
  • tolerant to class names that starts with digit (#99, #105)
  • fix background compressing (#170)

Small personal sidenote

We have been using csso in our building process for years. Not only as CSS compress utility, but also as a parser to get AST, transform it and pass to csso for compression.

All those years it worked stable enough and various bugs usually were not an issue. I have even rewritten some util functions to use it instead of csso functions. But project has no maintainer for years. In spite of the opinion that csso is dead, it has its own audience and number of downloads continues to grow. It's sad that many issues were left with no attention. Moreover I wanted to improve it to make CSS compression results much better and predictable.

That's why I've decided to change the situation. I’m happy that project's owners gave me this opportunity. I became maintainer of csso and started bringing it back to life.

As a first steps I've changed files structure, cleaned up and refactored most of sources. Now it has single code base, with reworked test suite, jscs for code style check, browserify to build the bundle, automated gh-pages publishing etc. All aim to ensure that nothing prevents us to move forward.

After initial refactoring and a bunch of bug fixes, it's now clear to me that all parts of csso need to be reworked. First of all compressor's struсtural optimization algorithms should be replaced for others, that are safer, faster and more efficient. Parser should become compliant to standards, with support for new CSS features and more predictable. When this is done, we can try new structural optimizations, that no one has tried before. That is the main reason why I've decided to work on csso.

Stay tuned!

@lahmatiy