Skip to content

Releases: parcel-bundler/lightningcss

v1.21.2

02 Jul 02:56
Compare
Choose a tag to compare

Fixes

  • Propagate error location info to JS in bundler APIs – 91ec8d3
  • Omit analyzeDependencies option from bundler APIs in TypeScript definitions – ae97aa1
  • Fix deduplicating multiple copies of the same rule – a8d909a

v1.21.1

25 Jun 02:01
Compare
Choose a tag to compare

Fixes

  • Ensure fallback rules for logical properties are before nested rules – e66d99c
  • Fix Safari compat data for ::marker pseudo element – cff779d
  • Add compat data for ::part pseudo element – fbf0d24
  • Avoid splitting and vendor prefixing :is() when we can safely unwrap it – 8d94ea1
  • Ensure split incompatible rules get the correct vendor prefix – d6e1295
  • Add semicolon after declarations if preserving nesting – acde78b
  • Preserve license comments at the start of a stylesheet – 5cec8be
  • Do not crash on currentColor in color-mix() or relative color syntax – 20c9612
  • Specify exact version of lightningcss-derive in Rust crate – 1203368

v1.21.0

07 Jun 05:58
Compare
Choose a tag to compare

This release includes new features to improve compatibility of output CSS with your browser targets, and safely remove old fallbacks that aren't needed anymore. It also gives you more control over exactly how CSS is compiled, and fixes some bugs.

Preserve manual fallbacks

Lightning CSS will now preserve manually provided fallback values when some of your browser targets do not support the last one. For example, in the following rule, if some targets didn't support the max function, both declarations would be preserved. Otherwise, if we are sure that all targets support it, Lightning CSS will drop the fallback declaration.

.foo {
  margin-right: 22px;
  margin-right: max(4%, 22px);
}

This is supported for many types of values such as lengths, colors, gradients, images, font styles, etc. It uses compatibility data from caniuse and MDN to determine if each value is supported.

Include and exclude options

You can now control exactly how Lightning CSS compiles using the "include" and "exclude" options, in addition to the existing "targets". This allows you to explicitly turn on or off certain features, which overrides the defaults based on the provided browser targets. For example, you might want to only compile colors, and handle auto prefixing or other features with another tool. Or you may want to handle everything except vendor prefixing with Lightning CSS. These options make that possible.

An enum of available feature flags is provided, and you can use the bitwise OR operator to combine flags together, e.g. Features.Nesting | Features.Colors. There are also some flags which turn on multiple other flags at once, e.g. Selectors, Colors, and MediaQueries. The playground has been updated to show these flags and includes checkboxes to turn them on or off.

import {transform, Features, browserslistToTargets} from 'lightningcss';
import browserslist from 'browserslist';

transform({
  // ...
  // Turn on color and nesting compilation, regardless of browser targets.
  include: Features.Colors | Features.Nesting,
  targets: browserslistToTargets(browserslist('last 1 Chrome version'))
});

The Rust API has been updated to accept a new Targets struct instead of Browsers. This includes browser targets as a sub-field, along with the include and exclude options. See docs.rs for more details.

Split selector lists when unsupported

Lightning CSS will now automatically split selector lists when your browser targets don't support some selectors. This avoids a case where browsers ignore the whole rule if only some selectors are unsupported. It takes advantage of :is() forgiving selector lists where possible, otherwise generates multiple rules. For example:

:hover, :focus-visible {
  color: red;
}

will be compiled to the following if :focus-visible is not supported by one of your targets:

:is(:hover, :focus-visible) {
  color: red;
}

If :is() is unsupported, or if the selectors have different specificities, Lightning CSS will output the following instead:

:hover {
  color: red;
}

:focus-visible {
  color: red;
}

Non-standard selector compatibility

Some frameworks like Angular and View support some non-standard selectors, such as the ::v-deep pseudo element, >>> and /deep/ combinators, and :deep(<selector-list>) syntax. These are now able to be parsed and preserved as is by Lightning CSS. Unknown pseudo elements now allow arbitrary selectors after them unlike normal standard pseudo elements. Unknown functional pseudo selectors will preserve their arguments unmodified. Non-standard combinators can be enabled by adding the following option when compiling:

{
  nonStandard: {
    deepSelectorCombinator: true
  }
}

More

v1.20.0

19 Apr 22:29
Compare
Choose a tag to compare

This release implements tons of new CSS features, including improved media and container query parsing, support for new selectors, improved minification by removing duplicate rules, updated compat data, and support for compiling multiple files at once in the CLI!

Media and container queries

Lightning CSS now parses the values of each media query feature according to the type defined in the specification. This enables it to generate fallbacks for range syntax with the correct types (e.g. (color > 2) compiles to (min-color: 3)).

We now also automatically output modern range syntax when the browser targets allow it, which reduces the size of the output. For example, (min-width: 300px) will compile to (width >= 300px) when targeting modern browsers.

Lightning CSS will now add vendor prefixes to the resolution media query as well. This will generate the -webkit-device-pixel-ratio and -moz-device-pixel-ratio media queries where needed.

For container queries, we now support style queries. This allows you to customize the behavior of an element when a parent container's style matches a certain value.

@container style(--variant: accent) {
  .foo {
    color: slateblue;
  }
}

Finally, in the custom visitor API, you can now return media queries using raw values rather than manually constructing the AST. This wraps each style rule in an @media rule with (min-width: 500px):

transform({
  // ...
  visitor: {
    StyleRule(rule) {
      return {
        type: "media",
        value: {
          rules: [rule],
          loc: rule.loc,
          query: {
            mediaQueries: [
              { raw: '(min-width: 500px)' }
            ]
          }
        }
      };
    }
  }
});

Selectors

Lightning CSS now supports the :nth-child(An+B of S) selector, which lets you select the nth child matching a specific selector. For example, you could use article:nth-child(2 of p) to select the 2nd <p> element within an <article>.

We also now support the ::view-transition pseudo elements, which are used by the View Transitions API now implemented in Chrome.

Properties

We now implement vendor prefixing for the text-size-adjust property, for the -webkit and -moz prefixes. This property adjusts the size of text on mobile devices.

Minification

Lightning CSS will now automatically remove duplicate style rules, even when they are not adjacent. For this to be safe, the rules must have exactly the same selectors and properties, and the last matching rule wins. This could be useful when using atomic CSS libraries which generate a rule per unique property.

.green {
  background: green;
}

.red {
  background: red;
}

.green {
  background: green;
}

is minified to:

.red{background:red}.green{background:green}

Updated compat data

We also updated our browser compatibility data, allowing less prefixes and fallbacks to be generated.

  • :dir and :fullscreen are now natively supported in Safari 16.4
  • Native CSS nesting will be output when targeting Chrome 112 or Safari 16.5
  • Media query range and interval syntax will be output when targeting Chrome 104, Firefox 102, or Safari 16.4
  • lab and oklab colors are now supported in Chrome 111

CLI improvements

The lightningcss CLI can now process multiple files at once! You can specify each filename to compile, or use a glob that your shell expands. When multiple files are input, you need to use the --output-dir or -d option instead of --output-file or stdout. This will output each processed file into a directory with the corresponding filename.

lightningcss --minify -d dist src/*.css

Lightning CSS will also now automatically create any missing directories in the --output-file or --output-dir path, so you don't need to run mkdir beforehand. Thanks to @lucasweng for contributing this!

v1.19.0

13 Feb 15:28
Compare
Choose a tag to compare

This release includes several features and improvements for the custom visitor API, including support for defining how to parse custom at rules. In addition, lots of bug fixes are included for auto prefixing, selector downleveling, and more.

Custom at-rules

When Lightning CSS does not know how to parse an unknown at rule, it stores the prelude and body as a list of raw tokens. Without a definition for how a rule should be parsed, Lighting CSS doesn't know how to interpret it. Tokens are fine for simple use cases, but if you are building a custom visitor plugin that processes a custom at-rule, and want it to integrate with the rest of CSS, it is useful to define how the rule should be parsed and interpreted. In this release, a new customAtRules option has been added to the API to enable just that.

For example, here is how you could define an @mixin rule which expects a custom identifier as its prelude, and a style-block as its body. This allows nesting declarations and rules just like other at-rules like @media and @supports.

{
  customAtRules: {
    mixin: {
      prelude: '<custom-ident>',
      body: 'style-block'
    }
  }
}

With that, you can parse code like this:

@mixin foo {
  color: red;

  &.bar {
    color: green;
  }
}

Lightning CSS also validates the code and will emit syntax errors when it doesn't conform to the syntax definition. Another nice part is that we use this definition to automatically infer the TypeScript types for these rules when used in custom visitors.

Check out the documentation to learn more!

Features

  • Implement support for parsing custom at rules in JS bindings (#395)
  • Support raw property on returned declarations in visitors (#385)
  • Support raw values in visitors that return tokens (f9ed30f)
  • Make more AST properties optional in visitor return types (3fc05a9)
  • Add substitute_variables function to UnparsedProperty in the Rust API (#388)
  • Add Implement Property::set_prefix function (a19228d)
  • Merge non-adjacent @layer rules (6419d54)
  • Short-circuit on error in Rust visitor API (#406)
  • Support nesting selector at the root, which is transformed to :scope (4443411)

Fixes

  • fix: <layer-name> should be escaped (#383)
  • WASM: Only use import.meta.url in fallback scenario (#410)
  • Publish docs for optional features on docs.rs (#407)
  • Support node in wasm package (#387)
  • Fix parsing oblique angles in font-style descriptor (0e84e8e)
  • Update autoprefixer data for text-decoration (a58ea6f)
  • Bump mdn compat data (59cbc02)
  • Fix downleveling selectors in :is, :where, and :has (31fc453)
  • Fix serializing :host and ::slotted selectors (482fc40)
  • Copy license into all npm packages (856d460)
  • Improve deserialization error messages for custom visitors (331c8a9)
  • Fix cue-region-function ast types (6a53944)
  • Fix serializing currentColor (fcf4127)
  • Use unpkg module option in docs for wasm (f394b50)

v1.18.0

04 Jan 16:58
Compare
Choose a tag to compare

This release adds support for custom transform visitors written in JavaScript, which lets you extend Lightning CSS with support for custom CSS syntax extensions, perform build time transforms, and more. It also adds support for nested @container and @layer rules, implements vendor prefixing for @supports, adds support for compiling from stdin via the CLI, and reduces compile times for the Rust crate by adding feature flags.

Custom transforms

The Lightning CSS visitor API enables you to implement custom non-standard extensions to CSS, making your code easier to author while shipping standard CSS to the browser. You can implement extensions such as custom shorthand properties or additional at-rules (e.g. mixins), build time transforms (e.g. convert units, inline constants, etc.), CSS rule analysis, and much more.

The API is designed to call into JavaScript as little as possible. You provide functions for specific types of values you're interested in such as Length, Url, or specific properties or rules. Lightning CSS fully parses all CSS rules and properties (with individual type definitions!), and only calls your plugin when it visits a value type you need to transform. This granularity improves performance, and also makes it much easier to build plugins since you don't need to worry about parsing values or selectors yourself. You can return a new value from a visitor function, or even remove or replace a value with multiple values in some cases. Check out the docs for more details!

Custom transforms have a build time cost: it can be around 2x slower to compile with a JS visitor than without. That being said, it is around 6x faster than equivalent postcss plugins in my testing. While standard CSS features should continue to be implemented in Rust as part of Lightning CSS core, the plugin API can help you migrate from other tools while supporting non-standard syntax extensions you might use. We look forward to hearing your feedback!

Playground updates

The Lightning CSS playground has also been updated to support visitors, which makes it easy to play around right in your browser. It also has a new editor experience powered by Code Mirror including syntax highlighting and inline errors. Check out an example with a custom visitor to see what it can do.

New docs

The Lightning CSS website has also been updated to include documentation for all of the features, including transpilation, CSS modules, bundling, and minification.

Features

  • JavaScript visitor API for custom transforms – #363
  • Add visitor support to WASM build via napi-wasm – #373
  • Parse @container and @layer block rules nested within style rules – 615893c
  • Add projectRoot option and use relative paths for CSS module hashes – 33febb4
  • Implement vendor prefixing for @supports787f46f
  • CLI support for piping – #380
  • Introduce "bundler" feature flag – #358
  • Put all of serde behind feature flag – #360
  • Introduce "visitor" feature flag – #367
  • Add sourcemap feature – #372
  • Remove derive-move – #377

Fixes

  • Fix important declarations within nested at rules – 6a7d19e
  • Remove parentheses from supports condition AST – 87ca705

v1.17.1

30 Nov 17:15
Compare
Choose a tag to compare

Fixed a regression where zero lengths were serialized without a unit in custom properties, which could break calc() usages. 0afccf9

v1.17.0

29 Nov 17:17
Compare
Choose a tag to compare

This release includes support for the new nesting syntax, a new Rust visitor API to make building custom transforms easier, support for page margin at rules, and several other improvements and fixes.

New nesting syntax

The CSS nesting support has been updated to relax some of the rules around where the & selector is required, following the latest spec changes. The & selector is now automatically inserted with a descendant combinator when not already present, unless it starts with an element selector. The @nest rule is deprecated, and will print a warning.

.foo {
  color: red;

  .bar {
    color: blue;
  }
}

compiles to:

.foo {
  color: red;
}

.foo .bar {
  color: blue;
}

Playground

Visitor API

The Rust API now includes a Visitor API, allowing you to much more easily traverse the style sheet and implement custom transforms. You can visit rules, properties, and many common value types such as lengths, urls, custom functions, etc.

For example, this visitor converts all pixel values to rems.

struct MyVisitor;
impl<'i> Visitor<'i> for MyVisitor {
  const TYPES: VisitTypes = visit_types!(LENGTHS);

  fn visit_length(&mut self, length: &mut LengthValue) {
    match length {
      LengthValue::Px(px) => *length = LengthValue::Rem(*px / 16.0),
      _ => {}
    }
  }
}

stylesheet.visit(&mut MyVisitor);

You must declare what types of values you want to visit with bitflags via the visit_types macro. This enables us to completely skip visiting entire branches of the AST when they don't contain any relevant values, statically, at compile time, which improves performance. For example, if you declare you only want to visit urls, we don't need to visit any properties that don't contain URLs somewhere in their type (recursively). Check out the documentation for more details.

You can also implement support for parsing custom at rules (e.g. Tailwind's @apply), by providing a custom AtRuleParser implementation. The parsed rules are stored in the stylesheet using a generic parameter. See the example for more details.

Other fixes and improvements

  • Support for margin at rules within @page80a982a
  • Simplify :is() selector when only a single simple selector is provided as an argument – b870d1f
  • Fix ARM linux GLIBC requirement – 5098cae
  • Fix parenthesization of media queries – 5a12639
  • Bump napi-rs – 9f2e369
  • Expose and add docs for selector module – e31234f

v1.16.1

06 Nov 17:48
Compare
Choose a tag to compare

Bug fixes

  • Parse :nth-col() and :nth-last-col() selectors – @yisibl in #302
  • Use :is for non-leading nesting with multiple compound selectors – 8652701
  • Fix flipped border-bottom-right and border-bottom-left in shorthands – @LeoniePhiline in #308
  • Fix auto prefixing for browser versions greater than the latest – @mischnic in #326

CLI features

v1.16.0

20 Sep 03:19
Compare
Choose a tag to compare

This release adds support for the new relative color syntax, improves support for quoted CSS animation names, and fixes some bugs.

Relative color syntax

Lightning CSS now supports the new relative color syntax in the CSS Color Level 5 spec! This allows you to use math functions like calc() to manipulate the channel values of a source color, and to convert between color spaces. This is not yet shipping in any browsers, but Lightning CSS will do this manipulation at build time when possible, so that it works in any browser today!

Here's a simple example, which uses the lch color space to darken slateblue by 10%. This is done by using the l channel value in a calc() expression, and preserving the c and h channels as is.

.foo {
  color: lch(from slateblue calc(l - 10%) c h);
}

This will output:

.foo {
  color: lch(34.5711% 65.7776 296.794);
}

And, when lch colors are not supported by your browser targets, Lightning CSS already supports outputting fallbacks for older browsers:

.foo {
  color: #4e42b1;
  color: lch(34.5711% 65.7776 296.794);
}

Check it out in the playground!

Note that due to being a build time transform, CSS variables are not supported as source colors since the variable value may change at runtime. We'll have to wait for browser support for that.

Other fixes and improvements

  • Support for parsing the border-spacing property – @yisibl in #294
  • Avoid converting animation: "none" to animation: "none" none@yisibl in #295
  • If the browser doesn't support #rrggbbaa color syntax, output transparent instead of rgba(0, 0, 0, 0)@yisibl in #296
  • Support parsing angles with unitless zero in gradients and transforms – cbd392f
  • Bump parcel_sourcemap dependency to fix parsing source maps without sourcesContent, and improve base64 performance – 061c0c2