-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Local Variable Scoping in Import Files #2442
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
Comments
LESS variables behave like CSS properties: the latest definition in a scope "wins". You can address this in your example by surrounding imports in a mixin scope. .import-header() {
@import "header";
}
.import-button() {
@import "button";
}
.import-header();
.import-button(); |
Yes, that should be the case, but then why are two files imported separately into one "master" file in the same scope? How could one file possibly know of the other's existence? Shouldnt there be some way to specify in an @import statement to specify that the file should be treated as a separate scope? Consider that any third party code distributed in LESS has to work in a host environment without knowing what strange and unknown variables could be defined there. How could packages distributed in LESS ever work under a single global scope? |
Less is not unusual in this way. For example, an imported JavaScript file runs the same whether included as an external file or included inline.
Variables can be name-spaced, or the library itself can be wrapped in a mixin. So, there are ways to solve it, and it does behave as expected. However, it sounds like you're proposing a feature like:
... which would wrap the import in a local scope, sort of like Node modules. Something like that? |
Agreed that scoping is similar, but what is different is that all variable assignments in LESS, not just declarations are hoisted to the top of scope. This means that variables assigned in other files after importing a file adjust their values in previous files. If you reassign the value of a variable in javascript it is expected that change will only affect code included afterward. Removing this linearity makes it difficult to implement inheritance, since whatever a value is defined to last becomes what its defined as everywhere in the file. My proposal would be to add Since LESS does not separate |
Yes, JavaScript works that way, so you're talking about two different things.
If you're trying to make a case that Less should behave differently, that can't happen, as there are a lot of features that rely on the inheritance model. And the fact that it behaves differently than a scripting language is no accident. Like CSS, Less is not a scripting language. All declarations are final, you might say. They don't "run" in order and have different values at different points. Variables in each scope end up with a final value for that scope. So, they aren't "hoisted", because hoisting is a concept of imperative languages. So asking if Less can "hoist" some things and not others is illogical, because that's not what's happening. If you're trying to figure out how you can implement something that isolates scope, I've given some options. If you want to propose a feature, that's fine, but it sounds like you're talking mostly about how you expect Less to behave. I would recommend looking at the docs at http://lesscss.org/features/#variables-feature |
I do think scoping imports might be useful, but I'd want some other people to weigh in on it. Opening for any further discussion on: @import (scoped) "package"; |
Thanks. I hope you'll consider this. |
we already have that:
It's actually even better to move the P.S. Aside from above, the problem of |
Lazy-evaluation (and declarative nature of almost anything in general) is out-of-consideration since this is simply what (among a few other things of course) makes Less to be Less. I'm afraid this component loading scheme is designed solely with Sass in mind (or with just whatever imperative C-like variable evaluation in general) - basically it's the same pitfall as in #1706 (comment).
So while "scoped" import like above will probably do the trick for you in this particular "component" case you'll certainly face more troubles if you continue to ignore these fundamental Less differences. |
To illustrate how such "component loading mechanismus" might look like if it would take modern Less into consideration, here're few examples: [1]. This is how "Semantic-UI" component looks like by now (simplified code with all of its import trickery expanded): // some auxiliary stuff defined in button.less itself
@component: 'button';
// variables (and related stuff) that supposed to be customizable
// imported via something like "../@{theme}/@{component}.less"
@color: red;
// actual CSS styles:
.button {
color: @color;
} This approach have the advantage of using human-readable variable names (e.g. @import "button.less";
@color: blue; can't work for more than one component. [2] No, this is not the solution example yet. This is an example of how a more Less friendly library (e.g. "Bootstrap") handles this kind of stuff currently (to show the big picture before introducing the third example): // variables (and related stuff) usually defined in some shared "variables.less"
@button-color: red;
// actual CSS styles:
.button {
color: @button-color;
} this approach has exactly opposite pros and cons, you may override things whereever you want but those customizible variables have to have unique names (e.g. [3] The solution is obviously in namespaces... Actually while "namespaced variables" still have some room for improvement (#1848) this particular use-case does not require anything new, the following approach is available since Less 1.4.x: // variables (and related stuff) defined whereever suitable:
.button-stuff { // any appropriate name (also see in comments below)
@color: green;
}
// actual CSS styles:
& {
// using .button-stuff namespace here
.button-stuff();
.button {
color: @color;
}
} // end-of & and to be used like: @import "button.less";
.button-stuff {
@color: yellow;
} Exact code may vary as always. For instance since |
Also, yes this:
Closing again as having multiple methods to achieve the same effect, both in a library and by wrapping an import. Thanks, for weighing in, Max. |
Just wanted to say thanks @seven-phases-max for spending your time to thoroughly explain scoping and possible implementations which was above and beyond. I've added the mentioned scoping fix to each definition file and it works like a charm. The library will finally have a standard less import file in the It's worth noting that my original intent when adding precompiled css was to write code that could be maintained in LESS and ported by script to SCSS, which is something which bootstrap does to be platform neutral. I've however run into issues with SCSS not supporting some features that I took as the lowest common denominator for pre-processors, like permitting variables names inside So it looks like LESS comes out ahead for me in many regards (including support) 👍 Kudos! |
Any updates on this problem? |
Thanks for the project, and taking time to read this request. I enjoy LESS immensely.
I'm running into a critical issue with variable scoping that's preventing me from using
@import
to include multiple components in the same project.Test Case
The actual implementation is a bit different, but it can be boiled down to a simple test case.
Consider a master file for outputting a concatenated release of components that imports several different components.
And two components
The expected output is
But the actual output is
I've added a test case in zip format here
Rationale
I'm working on an open source component framework. Each component may include variable names that may be used in other components, but should be scoped to each component so that they do not conflict.
Variable overlap is inevitable with distributed component design since individual authors cannot be aware of the variables used in other components.
Currently the only way I can make my library work is to sandbox each component by compiling them separately, and informing developers that they cannot directly import components from my library in their less files.
For more details on the specific implementation that I'm running into trouble with you can see this overview, or peruse how a component loads a theme
The text was updated successfully, but these errors were encountered: