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