Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Less v5 & v6 Roadmap (WIP) #39

Open
matthew-dean opened this issue Sep 12, 2023 · 0 comments
Open

[RFC] Less v5 & v6 Roadmap (WIP) #39

matthew-dean opened this issue Sep 12, 2023 · 0 comments

Comments

@matthew-dean
Copy link
Member

matthew-dean commented Sep 12, 2023

This supplants this issue.

TODO - Does this repo need to exist? If it's just for meta-discussions, I think it could move into the DIscussions tab on the Less repo.

Less 5.x Roadmap

(Prep for Less 6.x)

Add deprecation warnings when parsing / evaluating

Changes

  • Add support for :extend(.foo !all) vs :extend(.foo all)
  • Add support for --custom: @{variable}; (see below)
  • Add selector() function as special parsing in a (variable) declaration value or function argument
  • Add custom() function as special parsing of a custom declaration's value
  • There are a number of examples in Less tests of invalid CSS for input CSS. There is no contractual guarantee that Less support invalid CSS (outside of known legacy hacks), so invalid CSS should be removed from .less tests, such that a more accurate spec-compliant parser doesn't bork on those tests
  • Add a deprecation warnings for the following things. Note that warnings will be suppress-able with an additional option.

WARN when

  • calling a mixin without parentheses e.g. .mixin;
  • when encountering unknown parsing in a variable declaration value (when falling back to permissive parsing)
  • using ./ (forced division) operator. It's really not necessary and requiring parentheses around division is fine.
  • putting whitespace between mixin name and parentheses in a mixin call
  • leaking (unlocking) variables and mixins into parent scope. There are accessors and other chaining features to be introduced in Less 6.x
  • leaking parent scope into caller scope. (Mixin calls have access to parent scope. This is unnecessary as you can just pass what you want into the mixin, and it also makes a mixin definition harder to reason about.)
  • using :extend(.foo all) instead of extend(.foo !all)
  • using --custom: @variable <-- this is ambiguous and problematic, the only supported form should be: --custom: @{variable};
  • using @plugin
  • using Math.ALWAYS
  • using strictUnits: false
  • putting @charset at any place other than the start of a .css or .less file, or using a variable in a @charset

ERROR ?

  • Compiling a remote Less file should automatically disable @plugin and any other JavaScript evaluation - see this advisory. (Unless we figure out a way to isolate JS execution -- maybe running Deno.)

Less 6.x Roadmap

TODO - break out as separate, linked READMEs?

Changes

  • Replace Less parsing / evaluation engine with Jess (a language-agnostic stylesheet engine).
  • Discontinue support of Less plugins in favor of Jess plugins? (It's not clear there can be 100% compatibility since Less plugins are Less AST-specific. The only possible way to do this would be to do a lot of work to expose Jess AST nodes as Less AST nodes to a Less plugin, and Less AST nodes are very messy / inconsistent, so my preference would be migration documentation).

New

1. @from as replacement for @plugin - drop-in JS/TS modules

Uses native dynamic imports vs eval'd Function calls.

@from './values.ts' import (width);

2. Namespacing for Less functions

No more inherent conflict between Less functions and CSS functions. The author can signal exactly what they mean.

@from '#less' import (rgb);

.box {
  color: rgb(fade(@my-color, 10%));
}

...or:

@from '#less' import * as less;

.box {
  color: less.rgb(fade(@my-color, 10%));
  background-color: rgb(var(--some-runtime-var));
}

3. @use as replacement for @import

Polluting the @import at-rule has had lots of unforeseen consequences, so continued use of it would be deprecated. Unlike @import, @use will not leak into child imports, making it easier for IDE features like auto-complete when opening a child import.

Old:

@import './variables.less';
@import './somefile.less';  // variables.less is leaked into somefile.less
@use './variables.less';
@use './somefile.less'; // no leakage ("somefile.less" must also call `@use './variables.less'`)

.box {
  color: @some-var; // (from variables.less)
}

4. @include as alternative replacement for @import

Will only render qualified rules, without importing variables or mixins.

5. @reference as replacement for @import (reference)

Will only include variables and mixins. Like @use, will not leak variables into child imports / references. Will also be able to be used repeatedly without an explicit (multiple) flag.

6. Replacements for @import (css) './myfile.less' and @import (less) './myfile.css' features

@include (css) './myfile.less';
@include (less) './myfile.css';
// can also write:
@use (less) './myfile.css';

7. Unlike Sass, Less will support native CSS Nesting:

.box {
  &.foo { color: blue; }
}

...evaluates to:

.box {
  &.foo { color: blue; }
}

whereas:

.box {
  // note the hyphen
  &-1 { color: blue; }
}

...evaluates to:

.box-1 { color: blue; }

Note, however, that &-1 will be deprecated and will trigger a warning. The preferred form for Less moving forward for "merging" selectors will be a function-like &()

e.g.

.box {
  &(-1) { color: blue; }
}

i.e. you can also force a merge by doing:

.foo {
  &().bar { color: blue; }
}

...which will evaluate to (like classic Less):

.foo.bar { color: blue; }

8. Better :extend -- converts to :is() wrappers.

Example:

.one.two.three {
  color: blue;
}

.foo:extend(.one);
.bar:extend(.two.three);
.four:extend(.two);
.five {
  :extend(.one.two.three !all);
}

would evaluate to:

:is(:is(.one, .foo):is(:is(.two, .four).three, .bar), .five) {
  color: blue;
}

Variable expansion in a selector

This should function similarly to above, where we don't have to combine imported variables with the other list. Meaning, we can just do:

@list: h2, a, li;

.child @{list} {
  color: blue
}

This will result in (the much less computationally-expensive):

.child :is(h2, a, li) {
  color: blue
}

Future feature: Extend should consider :is() and :where()

Given this:

:is(.foo) {
  color: blue;
}
.bar:extend(.foo);

This should result in:

:is(.foo, .bar) {
  color: blue;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant