Skip to content

Migrate Less compilation to ipl\Web\Less#5492

Open
lippserd wants to merge 5 commits intomainfrom
less
Open

Migrate Less compilation to ipl\Web\Less#5492
lippserd wants to merge 5 commits intomainfrom
less

Conversation

@lippserd
Copy link
Copy Markdown
Member

@lippserd lippserd commented Apr 9, 2026

Because the in-tree Less visitor requires wikimedia/less.php, that dependency has to live in icinga-php-thirdparty. icinga-php-library already carries Less-related code with the same dependency, so this PR consolidates everything into icinga-php-library and removes the duplicate in-tree implementation.

  • Remove the in-tree Icinga\Less\ visitor layer in favor of the shared ipl\Web\Less library, which maintains modernized equivalent CSS var replacement and light-mode functionality.
  • Strip unused variable-export support from LessCompiler — the feature was never used by any our modules or community modules.
  • Update LessCompiler to delegate to ipl\Web\Less, assembling sources via @import (less) directives; pass the $minify flag directly to render() instead of via a separate compress() call.
  • Modernize LessCompiler with PHP type declarations, short array syntax, and tightened PHPDoc.

For testing, use 7da4917 as the baseline, which adapts light mode rule evaluation order to match the new visitor.

Here is my test summary:

The stylesheets are nearly identical. All but one difference are cosmetic normalizations introduced by the new version of the wikimedia Less parser:

Category Example
Decimal leading zero .5em0.5em
Hex color shortening #dddddd#ddd
Color name normalization #ffffffwhite, #ff0000red
transparentrgba(0,0,0,0) fallback in var() expressions
Trailing .0 stripped 2.0em2em, 1.01
calc() kept as fractions calc(14.28571429%)calc(100% / 7)
Font shorthand explicit line-height 1em1em/1

There is one functional difference: the light-mode background color gains an extra level of indirection via a new CSS var call (because it uses @light-body-bg-color):

-  --body-bg-color: #f5f9fa;
+  --body-bg-color: var(--light-body-bg-color, #f5f9fa);

The new CSS var replacement visitor from ipl\Web runs independently from the light mode call visitor, and therefore also adds var overrides to such detached rulesets. Everything else is normalization noise.

closes #5457
requires Icinga/icinga-php-thirdparty#115
requires Icinga/ipl-web#365

This is a preparation for using the new Less utils from `ipl\Web` to simplify
the comparison of the old and new stylesheets.
This reverts commit 7c58b3c.

Remove variable exports as they were never used in our modules or community
modules, and using this feature is discouraged.
Replace the in-tree `Icinga\Less\` visitor layer with its equivalents
from `ipl\Web\Less`, where the same color-variable and light-mode
functionality is maintained as a shared library.

`LessCompiler` is updated to delegate to `WikimediaLessCompiler`,
assembling source via `@import (less)` directives and accepting a
`$minify` flag directly on `render()` rather than through a separate
`compress()` call.
Add missing PHP type declarations to properties and methods, replace long-form
`array()` syntax with short `[]` syntax, tighten PHPDoc comments, and correct
"LESS" to "Less".
@lippserd lippserd changed the title Use Less utils from ipl-web Migrate Less compilation to ipl\Web\Less Apr 10, 2026
@lippserd lippserd added this to the 2.14.0 milestone Apr 10, 2026
@lippserd lippserd marked this pull request as ready for review April 10, 2026 14:40
@lippserd lippserd requested a review from nilmerg April 10, 2026 14:40
);

if (in_array($path, $special)) {
putenv('ICINGAWEB_ENVIRONMENT=production');
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note that this must be removed before merging the PR.

@sukhwinder33445
Copy link
Copy Markdown
Contributor

sukhwinder33445 commented Apr 14, 2026

I compared the minified CSS output between the main branch and the less branch (both icingaweb2 and ipl-web) and found the following issues:

  1. Decimal leading zero: The change is applied in the wrong direction: 0.5em is being converted to .5em, but it should be the other way around (.5em → 0.5em) as you mentioned above.
  2. Missing semicolon: CSS properties before the closing brace (}) are missing their trailing semicolon (;).
  3. Empty CSS values now throw an error: previously, empty string values were rendered without issue. For example, when trying to configure a new schedule in the Notifications Web module, the following error is thrown:
Screenshot 2026-04-14 at 16 08 38

Here the getColor() returns empty string in this case.

  1. LESS division not evaluated: A LESS expression that previously compiled correctly to max-height: calc(100vh - 4.16666667em); now outputs invalid CSS: max-height: calc(100vh - 50/12em);. According to the LESS docs, to evaluate the division, a LESS variable must be used.

@lippserd
Copy link
Copy Markdown
Member Author

  1. Decimal leading zero: The change is applied in the wrong direction: 0.5em is being converted to .5em, but it should be the other way around (.5em → 0.5em) as you mentioned above.

Are you sure about that?

2. Missing semicolon: CSS properties before the closing brace (}) are missing their trailing semicolon (;).

Why do you think that's an issue?

3. Empty CSS values now throw an error: previously, empty string values were rendered without issue. For example, when trying to configure a new schedule in the Notifications Web module [...]

That's interesting (since this results in property: ; during rendering, which is obviously just invalid), and I wonder what happened before — were the rules simply ignored? Anyway, PHPDoc specifies that a string must be passed, and the notification module violates that. That needs to be fixed there. I'll consider adapting Style /LessRuleset accordingly so that its contract is actually enforced.

4. LESS division not evaluated: A LESS expression that previously compiled correctly to max-height: calc(100vh - 4.16666667em); now outputs invalid CSS: max-height: calc(100vh - 50/12em);. According to the LESS docs, to evaluate the division, a LESS variable must be used.

That's a good find, and it's been invalid CSS/Less since it was introduced. Now that you've brought it up, would you like to add a fix to this PR?

@sukhwinder33445
Copy link
Copy Markdown
Contributor

Are you sure about that?

Yes, looked again at the before and after CSS minified files and found that in most cases the leading zero has been removed, but in some places the change is applied as you mentioned above, and in others it remains unchanged. So we have three different behaviors, I think there should be consistency here.

Removed leading zero:

/*Before*/
.icinga-module.module-icingadb .item-layout.downtime .visual {
    ...
    padding: 0.5em 0.25em;
    /* The source file (`icingadb/downtime.less`) does not contain the leading zero, so I guess the LESS compiler was adding it before. */
}

/*After*/
.icinga-module.module-icingadb .item-layout.downtime .visual {
    ...
    padding: .5em .25em;
}

A zero is added:

 /*Before*/
.icinga-module.module-icingadb .row-item .performance-data {
    ...
    margin-left: -.25em;
}

 /*After*/
.icinga-module.module-icingadb .row-item .performance-data {
    ...
    margin-left: -0.25em
}

Remains the same in before and after cases:

.icinga-module.module-icingadb .row-item .performance-data .inline-pie {
   ...    
   margin-left: .25em
}

Why do you think that's an issue?

Yes, it is not an issue, but I thought it could be an unwanted change since it was not mentioned in the changes table above. Or did you mention it as normalization noise?

That's a good find, and it's been invalid CSS/Less since it was introduced. Now that you've brought it up, would you like to add a fix to this PR?

Okey, i will push a commit.

@lippserd
Copy link
Copy Markdown
Member Author

Are you sure about that?

Yes, looked again at the before and after CSS minified files [...]

We have no control over how the Wikimedia Less parser minifies the CSS. Therefore, it only makes sense to compare the unminified versions.

Why do you think that's an issue?

Yes, it is not an issue, but I thought it could be an unwanted change since it was not mentioned in the changes table above. Or did you mention it as normalization noise?

Same as above.

@sukhwinder33445 sukhwinder33445 force-pushed the less branch 2 times, most recently from 7c96160 to 0af9a40 Compare April 15, 2026 09:34
@sukhwinder33445
Copy link
Copy Markdown
Contributor

Yes, you are right. That's the minifier which removes the leading zero and the semicolon. The non-minified file contains only the changes mentioned above.

This is invalid since `wikimedia/less.php:v5.0.0` : https://gerrit.wikimedia.org/r/c/mediawiki/libs/less.php/+/1049149
Less only evaluates its own variables, escaping won't help here.
Use a Less variable to evaluate the divison correctly, and remove the
unnecessary escape characters.
Copy link
Copy Markdown
Member

@nilmerg nilmerg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category Example
Font shorthand explicit line-height 1em → 1em/1

That's not caused by normalization but by not evaluating it as division. But these variables don't seem to be used anyway, so that's why it wasn't an issue previously and the change won't be noticed now.

Comment on lines 99 to 100
if ($theme === null || (is_file($theme) && is_readable($theme))) {
$this->theme = $theme;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why we didn't use realpath here as we use it for other less files already. Now that you use @import, I think it's safer to use it for theme files as well.

public function setThemeMode(string $themeMode): static
{
if (is_file($themeMode) && is_readable($themeMode)) {
$this->themeMode = $themeMode;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, realpath won't hurt.

LESS;
$compiler = new WikimediaLessCompiler([
// Disable URL adjustment - Less.php tries to make URLs relative to the file path when using @import.
'relativeUrls' => false,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the exact reason for this? I enabled it again but didn't spot an issue. And looking at wikimedia's implementation, I think it's safer to enable since it escapes certain characters it seems.

Copy link
Copy Markdown
Member Author

@lippserd lippserd Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should see issues, e.g., fonts not loading, logo not loading.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. Then the comment explaining it is misleading as it doesn't affect @import in any way. Even tried to import a realative path with this enabled and it worked fine.

@lippserd
Copy link
Copy Markdown
Member Author

Font shorthand explicit line-height
1em → 1em/1

That's not caused by normalization but by not evaluating it as division. But these variables don't seem to be used anyway, so that's why it wasn't an issue previously and the change won't be noticed now.

The new version of the Wikimedia Less parser handles mathematical expressions differently, which is why we have to specify 'math' => 'always'. Nevertheless, this particular expression is no longer evaluated.

@nilmerg nilmerg added the affects-upgrades The change requires migration or user awareness label Apr 17, 2026
@nilmerg
Copy link
Copy Markdown
Member

nilmerg commented Apr 17, 2026

The upgrading docs need to mention the changes, especially those to mathematical expressions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

affects-upgrades The change requires migration or user awareness cla/signed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants