mirror of
https://github.com/danog/dart-sass.git
synced 2024-11-26 20:24:42 +01:00
52 lines
2.8 KiB
Markdown
52 lines
2.8 KiB
Markdown
|
# Differences from Ruby Sass
|
||
|
|
||
|
Dart Sass was created and architected by Natalie Weizenbaum, the lead designer
|
||
|
and developer of Ruby Sass. Its architecture is informed by lessons learned from
|
||
|
working on the Ruby implementation, and as such differs in a number of key ways.
|
||
|
This document is intended to record the differences and to act as a guide to
|
||
|
Dart Sass for developers familiar with Ruby Sass.
|
||
|
|
||
|
1. The biggest difference is that Dart Sass intentionally tries to minimize the
|
||
|
number of whole-stylesheet compilation phases. Ruby Sass loses a lot of time
|
||
|
to the raw mechanics of AST traversal, so minimizing that should produce
|
||
|
enough benefit to offset the more complex code.
|
||
|
|
||
|
The parse phase and the CSS serialization phase both still exist and do more
|
||
|
or less the same thing as in Ruby Sass. However, the perform, cssize, and
|
||
|
extend phases are now a single perform phase. This phase executed SassScript
|
||
|
and builds the final CSS syntax tree from the resulting information. Extends
|
||
|
and bubbling are applied as the tree is being created.
|
||
|
|
||
|
The nesting verification phases have been removed in favor of more thorough
|
||
|
parser-based checking for appropriate nesting, as well as dynamic
|
||
|
valid-parent checks in the perform phase where necessary.
|
||
|
|
||
|
2. Dart Sass uses entirely separate abstract syntax trees for the Sass input
|
||
|
than for the CSS output, rather than having some node types shared between
|
||
|
them. This better models the fact that the data being consumed from the user
|
||
|
is very different than the data being emitted. In particular, the input data
|
||
|
often has SassScript in places where the output needs to rely on plain CSS
|
||
|
for proper formatting.
|
||
|
|
||
|
3. The abstract syntax trees are all immutable. This is enabled in part by #2,
|
||
|
since there's no need to set resolved data on a node that was not previously
|
||
|
resolved. Immutability makes code dealing with the ASTs much easier to reason
|
||
|
about and consequently to refactor.
|
||
|
|
||
|
4. There's no distinction between the statement-level parser and the
|
||
|
expression-level parser. This distinction in Ruby Sass was an artifact of the
|
||
|
original indented-syntax-only implementation and didn't really provide any
|
||
|
utility.
|
||
|
|
||
|
5. The parser is character-based rather than regular-expression-based. This is
|
||
|
faster due to Dart's well-tuned support for integers, and it gives developers
|
||
|
finer control over the precise workings of the parser.
|
||
|
|
||
|
6. The parser is more switch-based and less recursion-based. The Ruby Sass
|
||
|
parser's methods returned a value or `nil`, and much of its logic was based
|
||
|
on trying to consume one production and moving on to another if the first
|
||
|
returned `nil`. This makes parsing tend towards `O(n)` in the number of
|
||
|
productions. The Dart Sass parser instead checks the first character (or
|
||
|
several characters if necessary) and chooses which production to consume
|
||
|
based on those.
|