Rsass 0.26.0 released
Posted 2022-09-18 20:04. Tagged rust, project, css, rsass, sass.
More than three months after the last release, is is now the time to announce rsass 0.26.0. There is a bunch of breaking changes and a bunch of improvements. The changelog has the whole (too long) list.
But this time, some of the changes may go a bit deeper. As usual, the breaking changes is breaking mainly to users who in some way modify the global context from rust code, maybe by providing their own builtin functions or maybe just by inserting a global variable.
Also this time, there is an improved way of calling ructe from a cargo
build.rs program, see the Cargo section below.
Builtin functions and their arguments
A BuiltinFn is now a dyn Fn(&ResolvedArgs) -> Result<Value, CallError> + Send + Sync
(earlier, the argument was a ScopeRef and the error type was
rsass::Error).
The ResolvedArgs type provides functions get and get_map to get an
argument converted to a specific type, either by TryFrom<Value> for the
type or by a given conversion function.
If the conversion fails, the (display formatted) error will be combined
with the argument name into a CallError::BadArgument.
There is also similar get_opt and get_opt_map for optional arguments
(i.e. arguments where null values are allowed).
If something other than argument parsing can go wrong in your function,
creating an Invalid::AtError (and a CallError from that) is probably
the best way to handle that.
Contexts and files
The easiest way to get some css data is still like this:
let css = compile_scss_path?;
The body of that function now looks like this:
let = for_path?;
context.with_format.transform
Here, FsContext is a specialization of Context for loading files
from the file system.
Apart from loading files, the Context also provides the global
Scope, which can be modified to provide extra “builtin” variables,
functions or modules.
For a full example, see the rust_functions.rs test.
Here’s a tiny example providing the global variable $project while
transforming path.
let = for_path?;
context.get_scope.define?;
context.transform
Cargo
When running ructe from a cargo build.rs program, the following way of
calling rsass can be used:
let = for_path?;
context.transform
This doesn’t look like a big change, but using a CargoContext (which
is just type alias for a Context where the loader is a CargoLoader)
have two benefits:
First, the path is resolved relative to the crate root (the directory
containing your Cargo.toml) rather than the current working directory.
Secondly, both for the given path and for any paths loaded when handling
the scss (due to e.g. @use or @import), the CargoLoader emitts
special messages telling cargo that those files are used in the build, so
the build.rs program gets reexecuted if needed when rebuilding the
project.
Ructe
Updating ructe to 0.15.0 includes an update of rsass to 0.26.0.
Ructe also declares a built-in function, static_name, that takes the
source name of a static file and returns an url name, i.e. a name
including a content hash for cache-busting.
Error handling
Earlier versions of rsass had an rsass::Error enum with lots of variants
that was returned from most functions in the crate.
In this version, there is still an Error enum, but it has fewer variants
(and the fallback variant with just a message string is used a lot less,
even though some uses still remains).
Many of the old variants are now covered by Error::Invalid(Invalid, SourcePos), which holds an Invalid (what went wrong) and a SourcePos
(where it happened).
Internally, some functions now returns a Result<T, Invalid> to be
combined with a source position as the error propagates.
Other functions have other specific error types, such as ScopeError and
the CallError mentioned above.
More to come
Rsass is far from done.
Lots of things remains before I’ll call it 1.0.
Probably the biggest one is placeholder selectors and the @extend
directive.
To be able to do that, there are two things missing; selector functions
and a css data tree.
Many selector functions require a deeper understanding of css selectors than what is currently encoded, to be able to answer questions like “do this complex selector select a proper subset of what that complex selector selects”. I’m not yet sure how a css selector should be represented in rsass to be able to do that efficiently.
Css output is almost just a list of rules, but there is also @
directives, such as @media, which contains another list of rules and
possibly @ directives.
Currently, rsass has a data type for a single css rule, but when a rule is
completed it is written to an output buffer, and that buffer is the only
representation of the completed css.
To be able to find earlier rules to extend, a full data tree is needed.
That should also provide some nice separation between the transformation
(sass to css) and the formatting (css data model to css text buffer).
So, lots more to come at https://github.com/kaj/rsass. I hope to see you there!
Comments
Write a comment